Packages
ecto
3.4.1
3.14.1
3.14.0
3.13.6
3.13.5
3.13.4
3.13.3
3.13.2
3.13.1
3.13.0
3.12.6
3.12.5
3.12.4
3.12.3
3.12.2
3.12.1
3.12.0
3.11.2
3.11.1
3.11.0
3.10.3
3.10.2
3.10.1
3.10.0
3.9.6
3.9.5
3.9.4
3.9.3
3.9.2
3.9.1
3.9.0
3.8.4
3.8.3
3.8.2
3.8.1
3.8.0
3.7.2
3.7.1
3.7.0
3.6.2
3.6.1
3.6.0
3.5.8
3.5.7
3.5.6
3.5.5
3.5.4
3.5.3
3.5.2
3.5.1
3.5.0
3.5.0-rc.1
3.5.0-rc.0
3.4.6
3.4.5
3.4.4
3.4.3
3.4.2
3.4.1
3.4.0
3.3.4
3.3.3
3.3.2
3.3.1
3.3.0
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.9
3.0.8
3.0.7
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
3.0.0-rc.1
3.0.0-rc.0
2.2.12
2.2.11
2.2.10
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.2.0-rc.1
2.2.0-rc.0
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.1.0-rc.5
2.1.0-rc.4
2.1.0-rc.3
2.1.0-rc.2
2.1.0-rc.1
2.1.0-rc.0
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-rc.6
2.0.0-rc.5
2.0.0-rc.4
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
2.0.0-beta.2
2.0.0-beta.1
2.0.0-beta.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.16.0
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
0.12.0-rc
0.11.3
0.11.2
0.11.1
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.1
0.5.0
0.4.0
0.3.0
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
A toolkit for data mapping and language integrated query for Elixir
Current section
Files
Jump to
Current section
Files
lib/ecto/query/builder/group_by.ex
import Kernel, except: [apply: 2]
defmodule Ecto.Query.Builder.GroupBy do
@moduledoc false
alias Ecto.Query.Builder
@doc """
Escapes a list of quoted expressions.
See `Ecto.Builder.escape/2`.
iex> escape(:group_by, quote do [x.x, 13] end, {[], :acc}, [x: 0], __ENV__)
{[{:{}, [], [{:{}, [], [:., [], [{:{}, [], [:&, [], [0]]}, :x]]}, [], []]},
13],
{[], :acc}}
"""
@spec escape(:group_by | :partition_by, Macro.t, {list, term}, Keyword.t, Macro.Env.t) ::
{Macro.t, {list, term}}
def escape(kind, expr, params_acc, vars, env) do
expr
|> List.wrap
|> Enum.map_reduce(params_acc, &do_escape(&1, &2, kind, vars, env))
end
defp do_escape({:^, _, [expr]}, params_acc, kind, _vars, _env) do
{quote(do: Ecto.Query.Builder.GroupBy.field!(unquote(kind), unquote(expr))), params_acc}
end
defp do_escape(field, params_acc, _kind, _vars, _env) when is_atom(field) do
{Macro.escape(to_field(field)), params_acc}
end
defp do_escape(expr, params_acc, _kind, vars, env) do
Builder.escape(expr, :any, params_acc, vars, env)
end
@doc """
Called at runtime to verify a field.
"""
def field!(_kind, field) when is_atom(field),
do: to_field(field)
def field!(kind, other) do
raise ArgumentError,
"expected a field as an atom in `#{kind}`, got: `#{inspect other}`"
end
@doc """
Shared between group_by and partition_by.
"""
def group_or_partition_by!(kind, query, exprs, params) do
{expr, {params, _}} =
Enum.map_reduce(List.wrap(exprs), {params, length(params)}, fn
field, params_count when is_atom(field) ->
{to_field(field), params_count}
%Ecto.Query.DynamicExpr{} = dynamic, {params, count} ->
{expr, params, count} = Builder.Dynamic.partially_expand(query, dynamic, params, count)
{expr, {params, count}}
other, _params_count ->
raise ArgumentError,
"expected a list of fields and dynamics in `#{kind}`, got: `#{inspect other}`"
end)
{expr, params}
end
defp to_field(field), do: {{:., [], [{:&, [], [0]}, field]}, [], []}
@doc """
Called at runtime to assemble group_by.
"""
def group_by!(query, group_by, file, line) do
{expr, params} = group_or_partition_by!(:group_by, query, group_by, [])
expr = %Ecto.Query.QueryExpr{expr: expr, params: Enum.reverse(params), line: line, file: file}
apply(query, expr)
end
@doc """
Builds a quoted expression.
The quoted expression should evaluate to a query at runtime.
If possible, it does all calculations at compile time to avoid
runtime work.
"""
@spec build(Macro.t, [Macro.t], Macro.t, Macro.Env.t) :: Macro.t
def build(query, _binding, {:^, _, [var]}, env) do
quote do
Ecto.Query.Builder.GroupBy.group_by!(unquote(query), unquote(var), unquote(env.file), unquote(env.line))
end
end
def build(query, binding, expr, env) do
{query, binding} = Builder.escape_binding(query, binding, env)
{expr, {params, _}} = escape(:group_by, expr, {[], :acc}, binding, env)
params = Builder.escape_params(params)
group_by = quote do: %Ecto.Query.QueryExpr{
expr: unquote(expr),
params: unquote(params),
file: unquote(env.file),
line: unquote(env.line)}
Builder.apply_query(query, __MODULE__, [group_by], env)
end
@doc """
The callback applied by `build/4` to build the query.
"""
@spec apply(Ecto.Queryable.t, term) :: Ecto.Query.t
def apply(%Ecto.Query{group_bys: group_bys} = query, expr) do
%{query | group_bys: group_bys ++ [expr]}
end
def apply(query, expr) do
apply(Ecto.Queryable.to_query(query), expr)
end
end