2017-08-12 21 views
1

我有一個Postgres表,其中tsrange column,我想將其包含在我的Ecto模塊的schema中。我看到Postgrex.Range exists。我已經試過這樣:帶有一個tsrange字段的Ecto架構

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

但是,這給了我這個錯誤:

** (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 

有什麼建議?我使用Phoenix 1.3和Ecto主分支。

回答

0

看起來@TheAnh有正確的方法,但這裏是真正清盤的工作me:

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

我認爲你應該爲tsrange創建一個自定義類型來處理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 

關於包容性的邊界籤PostgreSQL documentation

,然後在你的應用程序,你可以使用:

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

您並不需要第一個'load'子句。第二個條款將以完全相同的方式處理'nil'情況。 – Dogbert

+0

啊,非常感謝! – TheAnh

相關問題