【发布时间】:2016-09-12 03:31:05
【问题描述】:
我有一个架构,我希望其中一个字段以 %Cm{value: 1.0} 的形式表示(对于厘米单位)。
我已经定义了这个客户类型:
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
遵循文档 (https://hexdocs.pm/ecto/Ecto.Type.html) 中的这些指南:
type应该输出数据库类型的名称cast应该接收任何类型并输出您的自定义 Ecto 类型load应该接收 DB 类型并输出您的自定义 Ecto 类型dump应该会收到您的自定义 Ecto 类型并输出 DB 类型
还有以下架构:
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
现在我尝试将块保存到数据库:
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)})
但是我不断收到错误:
** (CaseClauseError) no case clause matching: %Units.Cm{value: 2.0}
我尝试了各种方法组合,但似乎无法正确使用。所以我不能 100% 确定我理解文档。
归根结底,我希望能够传递 %Block{max_depth: %Units.Cm{value: 1.0}} 形式的模型结构,其中 cm 值作为浮点存储在数据库 (postgres) 中。
【问题讨论】:
-
尝试从
Db.Types.Cm.cast/1中的所有成功案例中返回{:ok, cm}(其中cm是%Cm{...}或Cm.new(...))。