0
Я хочу иметь собственный тип, который будет преобразовывать атомы взад и вперед по номерам (чтобы их можно было легко сохранить в БД).Реализация пользовательского типа обертки в ecto
Я попытался реализовать простой тип Ecto.
defmodule Kpsz.PressenceState do
@behaviour Ecto.Type
@moduledoc """
Representation of pressence state. It will store data as integers and convert them to atoms
"""
@bindings %{
1 => :unknown,
2 => :wanted,
3 => :confirmed
}
@reverse_bindings Enum.map(@bindings,fn {key, value} ->
{value, key}
end)
def reduce(index) when is_number(index), do: @bindings[index]
def reduce(atom) when is_atom(atom), do: @reverse_bindings[atom]
def type, do: :integer
def cast(arg) when is_number(arg), do: {:ok, arg}
def cast(arg) when is_atom(arg), do: {:ok, reduce(arg)}
def cast(_), do: :error
def load(integer) when is_number(integer), do: reduce(integer)
def load(_), do: :error
def dump(atom) when is_atom(atom), do: reduce(atom)
def dump(_), do: :error
end
Но он жалуется во время вставки:
Server: localhost:4000 (http)
Request: POST /pressence
** (exit) an exception was raised:
** (Ecto.ChangeError) value `2` for `Kpsz.Pressence.state` in `insert` does not match type Kpsz.PressenceState
(ecto) lib/ecto/repo/schema.ex:629: Ecto.Repo.Schema.dump_field!/6
(ecto) lib/ecto/repo/schema.ex:638: anonymous fn/6 in Ecto.Repo.Schema.dump_fields!/5
(stdlib) lists.erl:1263: :lists.foldl/3
(ecto) lib/ecto/repo/schema.ex:636: Ecto.Repo.Schema.dump_fields!/5
(ecto) lib/ecto/repo/schema.ex:585: Ecto.Repo.Schema.dump_changes!/6
(ecto) lib/ecto/repo/schema.ex:190: anonymous fn/11 in Ecto.Repo.Schema.do_insert/4
(ecto) lib/ecto/repo/schema.ex:614: anonymous fn/3 in Ecto.Repo.Schema.wrap_in_transaction/6
(ecto) lib/ecto/adapters/sql.ex:508: anonymous fn/3 in Ecto.Adapters.SQL.do_transaction/3
(db_connection) lib/db_connection.ex:1063: DBConnection.transaction_run/4
(db_connection) lib/db_connection.ex:987: DBConnection.run_begin/3
(db_connection) lib/db_connection.ex:667: DBConnection.transaction/3
(kpsz) web/controllers/pressence_controller.ex:7: Kpsz.PressenceController.assign/2
(kpsz) web/controllers/pressence_controller.ex:1: Kpsz.PressenceController.action/2
(kpsz) web/controllers/pressence_controller.ex:1: Kpsz.PressenceController.phoenix_controller_pipeline/2
(kpsz) lib/kpsz/endpoint.ex:1: Kpsz.Endpoint.instrument/4
(kpsz) lib/phoenix/router.ex:261: Kpsz.Router.dispatch/2
(kpsz) web/router.ex:1: Kpsz.Router.do_call/2
(kpsz) lib/kpsz/endpoint.ex:1: Kpsz.Endpoint.phoenix_pipeline/1
(kpsz) lib/plug/debugger.ex:123: Kpsz.Endpoint."call (overridable 3)"/2
(kpsz) lib/kpsz/endpoint.ex:1: Kpsz.Endpoint.call/2
Это, как я хочу, чтобы использовать его:
def create(user, event, repo \\ Repo) do
changeset = Pressence.changeset(%Pressence{}, %{event_id: event, user_id: user, state: :wanted})
repo.insert(changeset)
end
Библиотека [ecto_enum] (https://github.com/gjaldon/ecto_enum) может быть вам полезна. –
Удивительный! Но я хотел бы исправить этот проект. – Haito