Current section

Files

Jump to
query_builder lib query group_by.ex
Raw

lib/query/group_by.ex

defmodule QueryBuilder.Query.GroupBy do
@moduledoc false
require Ecto.Query
import QueryBuilder.Utils
def group_by(ecto_query, assoc_list, expr) do
group_by_exprs = build_group_by_exprs!(assoc_list, expr)
Ecto.Query.group_by(ecto_query, ^group_by_exprs)
end
defp build_group_by_exprs!(assoc_list, expr) when is_list(expr) do
if Keyword.keyword?(expr) do
raise ArgumentError,
"group_by does not accept a keyword list; " <>
"pass a token or a list of tokens/expressions, got: #{inspect(expr)}"
end
expr
|> Enum.flat_map(&build_group_by_exprs!(assoc_list, &1))
end
defp build_group_by_exprs!(assoc_list, expr) when is_function(expr, 1) do
expr
|> call_group_by_fun(assoc_list)
|> build_group_by_exprs!(assoc_list)
end
defp build_group_by_exprs!(_assoc_list, %Ecto.Query.DynamicExpr{} = dynamic),
do: [dynamic]
defp build_group_by_exprs!(assoc_list, token) when is_atom(token) or is_binary(token) do
[token_to_dynamic(assoc_list, token)]
end
defp build_group_by_exprs!(_assoc_list, expr) do
raise ArgumentError,
"group_by expects a token, a list of tokens/expressions, a dynamic, or a 1-arity function; got: #{inspect(expr)}"
end
defp call_group_by_fun(fun, assoc_list) do
fun.(&find_field_and_binding_from_token(assoc_list, &1))
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