Current section
Files
Jump to
Current section
Files
lib/query/distinct.ex
defmodule QueryBuilder.Query.Distinct do
@moduledoc false
require Ecto.Query
import QueryBuilder.Utils
def distinct(ecto_query, assoc_list, value) do
distinct_expr = build_distinct_expr!(assoc_list, value)
Ecto.Query.distinct(ecto_query, ^distinct_expr)
end
defp build_distinct_expr!(_assoc_list, value) when is_boolean(value), do: value
defp build_distinct_expr!(_assoc_list, %Ecto.Query.DynamicExpr{} = dynamic),
do: dynamic
defp build_distinct_expr!(assoc_list, value) when is_atom(value) or is_binary(value) do
token_to_dynamic(assoc_list, value)
end
defp build_distinct_expr!(assoc_list, {direction, expr})
when is_atom(direction) do
build_distinct_expr!(assoc_list, [{direction, expr}])
end
defp build_distinct_expr!(assoc_list, values) when is_list(values) do
Enum.map(values, &build_distinct_order_expr!(assoc_list, &1))
end
defp build_distinct_expr!(_assoc_list, value) do
raise ArgumentError,
"distinct expects a boolean or order_by-like expressions (tokens, dynamics, lists/keyword lists); got: #{inspect(value)}"
end
defp build_distinct_order_expr!(assoc_list, {direction, expr}) when is_atom(direction) do
resolved_expr =
case expr do
%Ecto.Query.DynamicExpr{} = dynamic ->
dynamic
fun when is_function(fun, 1) ->
fun.(&find_field_and_binding_from_token(assoc_list, &1))
token when is_atom(token) or is_binary(token) ->
token_to_dynamic(assoc_list, token)
other ->
raise ArgumentError,
"distinct expression #{inspect({direction, other})} is invalid; expected a token, dynamic, or 1-arity function"
end
{direction, resolved_expr}
end
defp build_distinct_order_expr!(assoc_list, expr) do
resolved_expr =
case expr do
%Ecto.Query.DynamicExpr{} = dynamic ->
dynamic
fun when is_function(fun, 1) ->
fun.(&find_field_and_binding_from_token(assoc_list, &1))
token when is_atom(token) or is_binary(token) ->
token_to_dynamic(assoc_list, token)
other ->
raise ArgumentError,
"distinct expression #{inspect(other)} is invalid; expected a token, dynamic, or 1-arity function"
end
resolved_expr
end
defp token_to_dynamic(assoc_list, token) do
{field, binding} = find_field_and_binding_from_token(assoc_list, token)
Ecto.Query.dynamic([{^binding, x}], field(x, ^field))
end
end