Help needed with the creation of a custom DateRange Ecto type

Hi! I am trying to write a custom Ecto type called DateRange. It would be backed by Postgrex’s %Postgrex.Range{} and the Date type.
Its implementation is located here and I believe it to be correct:

defmodule NewApp.Ecto.DateRange do

  @behaviour Ecto.Type

  def type, do: :daterange

  def cast(%{"lower" => lower, "upper" => upper}) do
    new_lower = Date.from_iso8601! lower
    new_upper = Date.from_iso8601! upper
    {:ok, Date.range(new_lower, new_upper)}
  end

  def cast(%Date.Range{}=range) do
    {:ok, range}
  end

  def cast(_), do: :error

  def load(%Postgrex.Range{lower: lower, upper: upper}) do
    {:ok, Date.range(lower, upper)}
  end

  def load(_), do: :error

  def dump(%Date.Range{}=range) do
    {:ok, %Postgrex.Range{lower: range.first, upper: range.last}}
  end

  def dump(_), do: :error
end

However, there’s an error during insertion that I fail to understand:

** (CaseClauseError) no case clause matching: {~D[2017-11-04]}
(ecto) lib/ecto/adapters/postgres/datetime.ex:40: 
    Ecto.Adapters.Postgres.TypeModule.encode_value/2

The full log is located here.

I do not understand why at some point there’s this tuple that contains only one date. That’s not something I explicitly do, and I fail to understand its origin.

Thanks in advance. :slight_smile:

1 Like

I came across this today. I hope this still helps:

def dump(%Date.Range{} = range) do
  {:ok, %Postgrex.Range{lower: Date.to_erl(range.first), upper: Date.to_erl(range.last)}}
end
3 Likes