[extra-01] add custom date range graphql type

This type allow graphql to work natively with postgres date range and
reduce the amount of work to convert between representations.
This commit is contained in:
Joao P Dubas 2021-06-28 00:27:38 +00:00
parent 1597d34a2d
commit 24a2c516c5
2 changed files with 94 additions and 0 deletions

View File

@ -0,0 +1,46 @@
defmodule WabanexWeb.Schema.Types.Custom.DateRange do
use Absinthe.Schema.Notation
alias Absinthe.Blueprint.Input
scalar :date_range, name: "DateRange" do
description("""
The `DateRange` scalar represents a range/period of date. The `DateRange`
appears as a string of two ISO8601 formatted dates separated by comma.
""")
serialize &serialize_range/1
parse &parse_range/1
end
@spec serialize_range(PgRanges.DateRange.t()) :: String.t()
@spec serialize_range(list(String.t())) :: String.t()
defp serialize_range(%PgRanges.DateRange{lower: start_range, upper: end_range}),
do: serialize_range([start_range, end_range])
defp serialize_range([start_range, nil]), do: "#{Date.to_iso8601(start_range)},"
defp serialize_range([start_range, end_range]),
do: "#{Date.to_iso8601(start_range)},#{Date.to_iso8601(end_range)}"
@spec parse_range(Input.String.t()) :: {:ok, PgRanges.DateRange.t()} | :error
@spec parse_range(Input.Null.t()) :: {:ok, nil}
defp parse_range(%Input.String{value: value}) do
value
|> String.split(",")
|> Enum.map(&Date.from_iso8601/1)
|> case do
[{:error, _}] -> :error
[{:error, _}, _] -> :error
[_, {:error, _}] -> :error
result -> {:ok, result |> Enum.map(fn {:ok, value} -> value end) |> new()}
end
end
defp parse_range(%Input.Null{}), do: {:ok, nil}
defp parse_range(_), do: :error
defp new([start_date]), do: new([start_date, nil])
defp new([start_date, end_date]), do: PgRanges.DateRange.new(start_date, end_date)
defp new([]), do: new([nil, nil])
end

View File

@ -0,0 +1,48 @@
defmodule WabanexWeb.Schema.Types.Custom.DateRangeTest do
use ExUnit.Case, async: true
alias Absinthe.{Blueprint.Input, Type}
alias PgRanges.DateRange
alias WabanexWeb.Schema.Types
defmodule TestSchema do
use Absinthe.Schema
import_types Types.Custom.DateRange
query do
end
end
defp serialize(type, value) do
TestSchema.__absinthe_type__(type)
|> Type.Scalar.serialize(value)
end
defp parse(type, value) do
TestSchema.__absinthe_type__(type)
|> Type.Scalar.parse(value)
end
describe ":date_range" do
test "serialize a list of dates as a list of ISO8601 date strings" do
assert "1978-12-15,1980-02-13" == serialize(:date_range, [~D[1978-12-15], ~D[1980-02-13]])
assert "1978-12-15," == serialize(:date_range, [~D[1978-12-15], nil])
end
test "serialize a postgres range as a list of ISO8601 date strings" do
assert "1978-12-15,1980-02-13" ==
serialize(:date_range, DateRange.new(~D[1978-12-15], ~D[1980-02-13]))
assert "1978-12-15," == serialize(:date_range, DateRange.new(~D[1978-12-15], nil))
end
test "can be parsed from a string of ISO8601" do
assert {:ok, DateRange.new(~D[1978-12-15], ~D[1980-02-13])} ==
parse(:date_range, %Input.String{value: "1978-12-15,1980-02-13"})
assert {:ok, DateRange.new(~D[1978-12-15], nil)} ==
parse(:date_range, %Input.String{value: "1978-12-15"})
end
end
end