Skip to content

Commit b5e9e7d

Browse files
committed
Parse ISO 8601 date strings back to DateTime in GraphQL responses
1 parent 94d4b00 commit b5e9e7d

1 file changed

Lines changed: 30 additions & 2 deletions

File tree

lib/beacon/graphql/query_executor.ex

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,36 @@ defmodule Beacon.GraphQL.QueryExecutor do
128128
# top-level key, unwrap to just the value so templates get the data directly
129129
# (e.g., @featured_links = [...] instead of %{"featuredLinks" => [...]}).
130130
defp unwrap_response(%{} = data) when map_size(data) == 1 do
131-
data |> Map.values() |> hd()
131+
data |> Map.values() |> hd() |> parse_dates()
132132
end
133133

134-
defp unwrap_response(data), do: data
134+
defp unwrap_response(data), do: parse_dates(data)
135+
136+
# JSON has no date type. GraphQL responses serialize DateTime/NaiveDateTime
137+
# to ISO 8601 strings. Parse them back so template code that expects
138+
# DateTime structs (e.g., Date.to_iso8601, Calendar functions) works.
139+
@iso_datetime ~r/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/
140+
141+
defp parse_dates(%{} = map) do
142+
Map.new(map, fn {k, v} -> {k, parse_dates(v)} end)
143+
end
144+
145+
defp parse_dates(list) when is_list(list), do: Enum.map(list, &parse_dates/1)
146+
147+
defp parse_dates(value) when is_binary(value) do
148+
if Regex.match?(@iso_datetime, value) do
149+
case DateTime.from_iso8601(value) do
150+
{:ok, dt, _offset} -> dt
151+
_ ->
152+
case NaiveDateTime.from_iso8601(value) do
153+
{:ok, ndt} -> ndt
154+
_ -> value
155+
end
156+
end
157+
else
158+
value
159+
end
160+
end
161+
162+
defp parse_dates(value), do: value
135163
end

0 commit comments

Comments
 (0)