I have a schema, where I want one of the fields to be represented in the form of %Cm{value: 1.0}
(for centimetre units).
I have defined this custome type:
defmodule Db.Types.Cm do
alias Units.Cm
@behavior Ecto.Type
def type, do: :float
def cast(%Cm{value: integer}) when is_integer(integer) do
Cm.new(integer / 1.0)
end
def cast(val = %Cm{value: float}) when is_float(float) do
val
end
def cast(number) when is_float(number), do: Cm.new(number)
def cast(number) when is_integer(number), do: Cm.new(number / 1.0)
def cast(_), do: :error
def load(float) when is_float(float), do: Cm.new(float)
def dump(%Cm{value: float}) when is_float(float), do: float
def dump(%Cm{value: integer}) when is_integer(integer), do: (integer / 1.0)
def dump(_), do: :error
end
Following these guidelines from the docs (https://hexdocs.pm/ecto/Ecto.Type.html):
type
should output the name of the DB typecast
should receive any type and output your custom Ecto typeload
should receive the DB type and output your custom Ecto typedump
should receive your custom Ecto type and output the DB type
And the following schema:
defmodule Db.Block do
schema "blocks" do
field :max_depth, Types.Cm
timestamps()
end
@fields ~w(max_depth)a
def changeset(struct, params \\ %{}) do
struct
|> cast(params, @fields)
end
end
Now I try to save blocks to the db:
defmodule Db.BlockHelpers do
def new_block(attributes \\ %{}) do
block = Dict.merge(%{
max_depth: 2
}, attributes)
%Block{}
|> Block.changeset(block)
|> Repo.insert!
end
end
iex> new_block()
...> new_block(%{max_depth: Units.Cm.new(5.0)})
However I keep getting errors:
** (CaseClauseError) no case clause matching: %Units.Cm{value: 2.0}
I've tried various combinations of approaches, but can't seem to get it right. So I'm not 100% sure I understand the documentation.
At the end of the day, I want to be able to pass around a model struct of the form %Block{max_depth: %Units.Cm{value: 1.0}}
, where the cm value is stored as a floating point in the database (postgres).
{:ok, cm}
(wherecm
is%Cm{...}
orCm.new(...)
) from all the success cases inDb.Types.Cm.cast/1
. – Dogbert