2016-12-09 6 views
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 
+0

Библиотека [ecto_enum] (https://github.com/gjaldon/ecto_enum) может быть вам полезна. –

+0

Удивительный! Но я хотел бы исправить этот проект. – Haito

ответ

0

Оба ваши dump и load функции должны возвращать {:ok, value} не только значение, как ты делаешь.

Вы можете ознакомиться с документацией here. Соответствующая часть:

dump(type, value, dumper \\ &dump/2) 
dump(t, term, (t, term -> {:ok, term} | :error)) :: {:ok, term} | :error 

 Смежные вопросы

  • Нет связанных вопросов^_^