Packages
ecto
2.0.4
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/distinct.ex
defmodule Ecto.Query.Builder.Distinct do
@moduledoc false
alias Ecto.Query.Builder
@doc """
Escapes a list of quoted expressions.
iex> escape(quote do true end, [], __ENV__)
{true, %{}}
iex> escape(quote do [x.x, 13] end, [x: 0], __ENV__)
{[{:{}, [], [{:{}, [], [:., [], [{:{}, [], [:&, [], [0]]}, :x]]}, [], []]},
13],
%{}}
"""
@spec escape(Macro.t, Keyword.t, Macro.Env.t) :: {Macro.t, %{}}
def escape(expr, _vars, _env) when is_boolean(expr) do
{expr, %{}}
end
def escape({:^, _, [expr]}, _vars, _env) do
{quote(do: Ecto.Query.Builder.Distinct.distinct!(unquote(expr))), %{}}
end
def escape(expr, vars, env) do
expr
|> List.wrap
|> Enum.map_reduce(%{}, &do_escape(&1, &2, vars, env))
end
defp do_escape({:^, _, [expr]}, params, _vars, _env) do
{quote(do: Ecto.Query.Builder.Distinct.field!(unquote(expr))), params}
end
defp do_escape(field, params, _vars, _env) when is_atom(field) do
{Macro.escape(to_field(field)), params}
end
defp do_escape(expr, params, vars, env) do
Builder.escape(expr, :any, params, vars, env)
end
@doc """
Called at runtime to verify a field.
"""
def field!(field) when is_atom(field),
do: to_field(field)
def field!(other) do
raise ArgumentError,
"expected a field as an atom in `distinct`, got: `#{inspect other}`"
end
@doc """
Called at runtime to verify distinct.
"""
def distinct!(distinct) when is_boolean(distinct) do
distinct
end
def distinct!(distinct) do
Enum.map List.wrap(distinct), fn
field when is_atom(field) ->
to_field(field)
_ ->
raise ArgumentError,
"expected a boolean or a list of fields in `distinct`, got: `#{inspect distinct}`"
end
end
defp to_field(field), do: {{:., [], [{:&, [], [0]}, field]}, [], []}
@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, expr, env) do
binding = Builder.escape_binding(binding)
{expr, params} = escape(expr, binding, env)
params = Builder.escape_params(params)
distinct = quote do: %Ecto.Query.QueryExpr{
expr: unquote(expr),
params: unquote(params),
file: unquote(env.file),
line: unquote(env.line)}
Builder.apply_query(query, __MODULE__, [distinct], env)
end
@doc """
The callback applied by `build/4` to build the query.
"""
@spec apply(Ecto.Queryable.t, term) :: Ecto.Query.t
def apply(query, distinct) do
query = Ecto.Queryable.to_query(query)
if query.distinct do
Builder.error! "only one distinct expression is allowed in query"
else
%{query | distinct: distinct}
end
end
end