2016-12-09 2 views
0

Ich möchte einen benutzerdefinierten Typ, der Atome vor und zurück in Zahlen konvertieren (so dass sie leicht in DB gespeichert werden können).Implementierung benutzerdefinierten Wrapper-Typ in Ecto

Ich habe versucht, einfache Ecto Typ zu implementieren.

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 

Aber es beschwert sich beim Einfügen:

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 

Dies ist, wie ich will, es benutzen:

def create(user, event, repo \\ Repo) do 
    changeset = Pressence.changeset(%Pressence{}, %{event_id: event, user_id: user, state: :wanted}) 
    repo.insert(changeset) 
end 
+0

Die Bibliothek [ecto_enum] (https://github.com/gjaldon/ecto_enum) kann für Sie nützlich sein. –

+0

Super! Aber ich würde lieber das Projekt reparieren. – Haito

Antwort

0

Sowohl Ihre dump und load Funktionen sollten {:ok, value} nicht nur den Wert zurück, wie Sie gehen.

Sie können die Dokumentation here sehen. Der relevante Teil ist:

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