Current section
Files
Jump to
Current section
Files
lib/query_engine/query_associator.ex
defmodule OuterfacesEctoApi.QueryEngine.QueryAssociator do
@moduledoc """
Helper functions for API models.
"""
@spec preload_and_serialize(
repo :: Ecto.Repo.t(),
queryable :: Ecto.Queryable.t() | [Ecto.Queryable.t()],
preloads :: list(atom() | {atom(), list(atom())}),
opts :: Keyword.t()
) :: list(map())
def preload_and_serialize(repo, queryable, preloads, opts) when is_list(queryable) do
repo
|> preload_query(queryable, preloads)
|> Enum.map(&do_pre_serialize(&1, preloads, opts))
end
def preload_and_serialize(repo, queryable, preloads, opts) do
repo
|> preload_query(queryable, preloads)
|> do_pre_serialize(preloads, opts)
end
defp do_pre_serialize(record, preloads, opts) when is_struct(record) do
case record.__struct__ do
nil ->
record
struct ->
if function_exported?(struct, :pre_serialize, 3) do
struct.pre_serialize(record, preloads, opts)
else
raise """
The struct #{inspect(struct)} does not implement the `pre_serialize/3` function.
add `use OuterfacesEctoApi.QueryEngine.QuerySerializer` to the struct module
to use the default implementation.
"""
end
end
end
defp do_pre_serialize(field, _preloads, _opts) do
field
end
defp preload_query(repo, queryable, preloads) do
Enum.reduce(preloads, queryable, fn
{field, nested_fields}, acc ->
repo.preload(acc, [{field, nested_fields}])
field, acc when is_atom(field) ->
repo.preload(acc, field)
end)
end
@spec pre_serialize_fields(
result :: map(),
source_record :: map(),
fields :: list(atom() | {atom(), list(atom())}),
opts :: Keyword.t()
) :: map()
def pre_serialize_fields(result, source_record, fields, opts)
when is_map(result) and is_map(source_record) and is_list(fields) do
result = result |> Map.put(:schema, source_record.__struct__ |> Atom.to_string())
Enum.reduce(fields, result, fn
{key, nested_fields}, acc when is_atom(key) ->
case Map.get(source_record, key) do
nil ->
acc
|> Map.put(key, nil)
value when is_list(value) ->
Map.put(
acc,
key,
Enum.map(value, &do_pre_serialize(&1, nested_fields, opts))
)
value ->
Map.put(
acc,
key,
do_pre_serialize(value, nested_fields, opts)
)
end
key, acc when not is_nil(key) and is_atom(key) ->
case Map.get(source_record, key) do
nil ->
acc
|> Map.put(key, nil)
value when is_list(value) ->
Map.put(
acc,
key,
Enum.map(value, &do_pre_serialize(&1, [], opts))
)
value ->
Map.put(
acc,
key,
do_pre_serialize(value, [], opts)
)
end
_, acc ->
acc
end)
end
end