lib/memorex/ecto/timex_duration.ex

defmodule Memorex.Ecto.TimexDuration do
  @moduledoc """
  An Ecto type which lets [Timex.Duration](https://hexdocs.pm/timex/Timex.Duration.html) be stored in Postgres as an
  integer (representing number of seconds). The `Timex.Duration` is converted to seconds when it is written to the
  database, and is converted back to a `Timex.Duration` when it is read from the database.

  To use, simply mark a field as type `TimexDuration` in the schema file.  For example, see field `:interval` on
  `Memorex.Domain.Card`, e.g., `field :interval, TimexDuration`

  See [here](https://hexdocs.pm/ecto/Ecto.Type.html) for more info on creating Ecto types.
  """

  use Ecto.Type

  alias Timex.Duration

  @impl Ecto.Type
  def type, do: :integer

  @impl Ecto.Type
  def cast(duration) when is_integer(duration) do
    {:ok, Duration.from_seconds(duration)}
  end

  def cast(%Duration{} = duration), do: {:ok, duration}
  def cast(_), do: :error

  @impl Ecto.Type
  def load(data) when is_integer(data) do
    {:ok, Duration.from_seconds(data)}
  end

  @impl Ecto.Type
  def equal?(nil, _duration2), do: false
  def equal?(_duration1, nil), do: false

  def equal?(duration1, duration2) do
    Duration.to_seconds(duration1) == Duration.to_seconds(duration2)
  end

  @impl Ecto.Type
  def dump(%Duration{} = duration), do: {:ok, Duration.to_seconds(duration, truncate: true)}
  def dump(_), do: :error
end