我在编写自定义 Ecto 类型时遇到问题。它由%Postgrex.Range{}
类型支持。代码是
defmodule Foo.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
迁移是
def change do
create table(:users) do
add :email, :string, null: false
add :username, :string
add :name, :string, null: false
add :password_hash, :text, null: false
add :period, :daterange
timestamps()
end
用户架构是
schema "users" do
field :username, :string
field :name, :string
field :email, :string
field :password_hash, :string
field :password, :string, virtual: true
field :period, Foo.Ecto.DateRange
我的有问题的代码seeds.exs
是这个:
today = Date.utc_today()
{:ok, user2} = create_user %{name: "Gloubi Boulga",
email: "gloub@boul.ga", password: "xptdr32POD?é23PRK*efz",
period: Date.range(today, Timex.shift(today, months: 2))
}
最后,错误是这个:
* (CaseClauseError) no case clause matching: {~D[2017-11-04]}
(ecto) lib/ecto/adapters/postgres/datetime.ex:40: Ecto.Adapters.Postgres.TypeModule.encode_value/2
(ecto) /home/tchoutri/dev/Projects/Foo/deps/postgrex/lib/postgrex/type_module.ex:717: Ecto.Adapters.Postgres.TypeModule.encode_params/3
[…]
priv/repo/seeds.exs:33: anonymous fn/0 in :elixir_compiler_1.__FILE__/1
当然,我不明白为什么会发生这种转换,这非常令人沮丧,特别是考虑到创建支持的自定义 Ecto 类型%Postgrex.Range{}
应该有些微不足道。
编辑: 我Logger.debug
在 cast 函数中放了一些,我可以看到
[debug] Casting new_date #DateRange<~D[2017-11-11], ~D[2018-01-11]>
出现和
%Postgrex.Range{lower: ~D[2017-11-11], lower_inclusive: true, upper: ~D[2018-01-11], upper_inclusive: true}
在dump
函数中。