2016-09-10 3 views
1

У меня есть схема, где я хочу, чтобы одно из полей представлялось в виде %Cm{value: 1.0} (для сантиметров).Ecto custom types: как я могу представить поле в модели как конкретный тип?

я определил этот тип логотипо:

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 

Следуя этим указаниям из документации (https://hexdocs.pm/ecto/Ecto.Type.html):

  • type должна вывести название типа DB
  • cast должен получать любой тип и выводить свой собственный тип Ecto
  • load должен получить тип DB и выходного пользовательского экто типа
  • 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 

Теперь я попытайтесь сохранить блоки в db:

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)}) 

Однако я продолжаю получать ошибки:

** (CaseClauseError) no case clause matching: %Units.Cm{value: 2.0} 

Я пробовал различные комбинации подходов, но не могу показаться, чтобы получить это право. Поэтому я не уверен на 100%, что понимаю документацию.

В конце дня, я хочу, чтобы иметь возможность пройти вокруг структурной структуры формы %Block{max_depth: %Units.Cm{value: 1.0}}, где значение cm хранится как плавающая точка в базе данных (postgres).

+1

Попробуйте вернуть '{: ok, cm}' (где 'cm' является'% Cm {...} 'или' Cm.new (...) ') из всех случаев успеха в' Db.Types .Cm.cast/1'. – Dogbert

ответ

0

Правильный ответ, предложенный Dogbert: возвращался value в отличие от {:ok, value}.