Current section

Files

Jump to
query_builder lib assoc_list preload_spec.ex
Raw

lib/assoc_list/preload_spec.ex

defmodule QueryBuilder.AssocList.PreloadSpec do
@moduledoc false
@type strategy :: :separate | :through_join
@type t :: %__MODULE__{strategy: strategy(), query_opts: keyword() | nil}
@enforce_keys [:strategy]
defstruct strategy: :separate,
query_opts: nil
@spec new(strategy(), keyword() | nil) :: t()
def new(strategy \\ :separate, query_opts \\ nil)
def new(strategy, query_opts) when strategy in [:separate, :through_join] do
if query_opts != nil and not Keyword.keyword?(query_opts) do
raise ArgumentError,
"invalid preload query opts; expected a keyword list or nil, got: #{inspect(query_opts)}"
end
if query_opts != nil and strategy != :separate do
raise ArgumentError,
"invalid preload spec: scoped preload queries require separate preload; " <>
"got strategy #{inspect(strategy)} with query opts #{inspect(query_opts)}"
end
%__MODULE__{strategy: strategy, query_opts: query_opts}
end
def new(strategy, query_opts) do
raise ArgumentError,
"invalid preload spec; expected strategy to be :separate or :through_join, " <>
"got: #{inspect(strategy)} with query opts #{inspect(query_opts)}"
end
@spec merge!(t() | nil, t() | nil, module(), atom()) :: t() | nil
def merge!(nil, nil, _source_schema, _assoc_field), do: nil
def merge!(%__MODULE__{} = spec, nil, _source_schema, _assoc_field), do: spec
def merge!(nil, %__MODULE__{} = spec, _source_schema, _assoc_field), do: spec
def merge!(%__MODULE__{} = a, %__MODULE__{} = b, source_schema, assoc_field) do
strategy = merge_strategy!(a.strategy, b.strategy)
query_opts = merge_query_opts!(a.query_opts, b.query_opts, source_schema, assoc_field)
if query_opts != nil and strategy == :through_join do
raise ArgumentError,
"conflicting preload requirements for #{inspect(source_schema)}.#{inspect(assoc_field)}: " <>
"cannot combine a scoped separate preload with `preload_through_join`"
end
%__MODULE__{strategy: strategy, query_opts: query_opts}
end
defp merge_strategy!(:through_join, _other), do: :through_join
defp merge_strategy!(_other, :through_join), do: :through_join
defp merge_strategy!(:separate, _other), do: :separate
defp merge_strategy!(_other, :separate), do: :separate
defp merge_query_opts!(a, b, source_schema, assoc_field) do
case {a, b} do
{nil, nil} ->
nil
{opts, nil} ->
opts
{nil, opts} ->
opts
{opts, opts} ->
opts
{a, b} ->
raise ArgumentError,
"conflicting scoped preload queries for #{inspect(source_schema)}.#{inspect(assoc_field)}: " <>
"cannot combine #{inspect(a)} and #{inspect(b)}"
end
end
end