2017-08-12 5 views
1

J'ai une table Postgres avec un tsrange column, et j'aimerais l'inclure dans le schema de mon module Ecto. Je vois cela Postgrex.Range exists. Je l'ai essayé ceci:Schéma Ecto avec un champ tsrange

schema "clients" do 
    field :valid_at, Postgrex.Range 
    ... 
end 

Mais cela me donne cette erreur:

** (ArgumentError) invalid or unknown type Postgrex.Range for field :valid_at 
    lib/ecto/schema.ex:1785: Ecto.Schema.check_type!/3 
    lib/ecto/schema.ex:1473: Ecto.Schema.__field__/4 

Toutes les suggestions? J'utilise Phoenix 1.3 et la branche maître Ecto.

Répondre

0

On dirait que @TheAnh a la bonne approche, mais voici ce qui en fait travailler pour liquidée moi:

defmodule Myapp.TsRange do 
    @behaviour Ecto.Type 

    def type, do: :tsrange 

    def cast(nil),   do: {:ok, nil} 
    def cast([lower, upper]), do: {:ok, [lower, upper]} 
    def cast(_),    do: :error 

    def load(%Postgrex.Range{lower: lower, upper: upper}) do 
    lower = lower |> to_datetime 
    upper = upper |> to_datetime 
    case [lower, upper] do 
     [nil, nil]     -> {:ok, [nil, nil]} 
     [{:ok, lower}, {:ok, upper}] -> {:ok, [lower, upper]} 
     _ -> :error 
    end 
    end 
    def load(_), do: :error 

    def dump([lower, upper]) do 
    {:ok, %Postgrex.Range{lower: lower |> from_datetime, 
          upper: upper |> from_datetime, 
          upper_inclusive: false}} 
    end 
    def dump(_), do: :error 

    defp to_datetime(nil), do: nil 
    defp to_datetime({{y, m, d}, {h, min, s, ms}}) do 
    NaiveDateTime.new(y, m, d, h, min, s, ms) 
    end 

    defp from_datetime(nil), do: nil 
    defp from_datetime(dt) do 
    {{dt.year, dt.month, dt.day}, {dt.hour, dt.minute, dt.second, elem(dt.microsecond, 0)}} 
    end 

end 
3

Je pense que vous devriez créer un type personnalisé pour tsrange pour travailler avec Ecto.

defmodule YourApp.TimestampRange do 
@behaviour Ecto.Type 

    def type, do: :tsrange 

    def cast([lower, upper]) do 
    {:ok, [lower, upper]} 
    end 

    def cast(_), do: :error 

    def load(%Postgrex.Range{lower: lower, upper: upper}) do 
    {:ok, [lower, upper]} 
    end 

    def dump([lower, upper]) do 
    {:ok, %Postgrex.Range{lower: lower, upper: upper, upper_inclusive: false}} 
    end 

    def dump(_), do: :error 
end 

À propos des limites inclusives checkout PostgreSQL documentation

puis dans votre application, vous pouvez utiliser:

schema "clients" do 
    field :valid_at, YourApp.TimestampRange 
    ... 
end 
+1

Vous n'avez pas vraiment besoin de la première clause 'load' ici. La deuxième clause traitera le cas 'nil' exactement de la même manière. – Dogbert

+0

Ahh merci beaucoup! – TheAnh