Ecto自定义类型:如何将模型中的字段表示为特定类型?

时间:2016-09-10 21:27:21

标签: elixir ecto

我有一个架构,我希望其中一个字段以datetime(厘米单位)的形式表示。

我定义了这种客户类型:

%Cm{value: 1.0}

遵循文档(https://hexdocs.pm/ecto/Ecto.Type.html)中的这些指南:

  
      
  • 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 应输出数据库类型的名称
  •   
  • type应该接收任何类型并输出您的自定义Ecto类型
  •   
  • cast应该收到数据库类型并输出您的自定义Ecto类型
  •   
  • load应该会收到您的自定义Ecto类型并输出数据库类型
  •   

以下架构:

dump

现在我尝试将块保存到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)})

我尝试了各种方法组合,但似乎无法做到正确。因此,我并非100%确定我理解文档。

在一天结束时,我希望能够传递 ** (CaseClauseError) no case clause matching: %Units.Cm{value: 2.0} 形式的模型结构,其中cm值存储为数据库中的浮点(postgres)。

1 个答案:

答案 0 :(得分:0)

Dogbert提供的正确答案:正在返回value而不是{:ok, value}