Packages
ecto
0.2.2
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/from_builder.ex
defmodule Ecto.Query.FromBuilder do
@moduledoc false
alias Ecto.Query.BuilderUtil
@doc """
Handles from expressions.
The expressions may either contain an `in` expression or not.
The right side is always expected to Queryable.
## Examples
iex> escape(quote do: MyModel)
{[], quote(do: MyModel)}
iex> escape(quote do: p in posts)
{[p: 0], quote(do: posts)}
iex> escape(quote do: [p, q] in posts)
{[p: 0, q: 1], quote(do: posts)}
iex> escape(quote do: [_, _] in abc)
{[], quote(do: abc)}
iex> escape(quote do: other)
{[], quote(do: other)}
iex> escape(quote do: x() in other)
** (Ecto.QueryError) invalid `from` query expression
"""
@spec escape(Macro.t) :: {Keyword.t, Macro.t}
def escape({:in, _, [list, expr]}) when is_list(list) do
binds =
Enum.flat_map(Stream.with_index(list), fn
{{:_, _, context}, _ix} when is_atom(context) ->
[]
{{var, _, context}, ix} when is_atom(var) and is_atom(context) ->
[{var, ix}]
{_, _count} ->
raise Ecto.QueryError, reason: "invalid `from` query expression"
end)
{binds, expr}
end
def escape({:in, meta, [var, expr]}) do
escape({:in, meta, [[var], expr]})
end
def escape(expr) do
{[], 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_with_binds(Macro.t, Macro.Env.t) :: {Macro.t, Keyword.t, non_neg_integer | nil}
def build_with_binds(expr, env) do
{binds, expr} = escape(expr)
case Macro.expand(expr, env) do
atom when is_atom(atom) ->
count_bind = 1
if Code.ensure_compiled?(atom) do
quoted = Ecto.Queryable.to_query(atom) |> Macro.escape
else
quoted = atom
end
other ->
count_bind = nil
quoted = other
end
quoted = BuilderUtil.apply_query(quoted, __MODULE__, [length(binds)], env)
{quoted, binds, count_bind}
end
@doc """
The callback applied by `build_with_binds/2` to build the query.
"""
@spec apply(Ecto.Queryable.t, non_neg_integer) :: Ecto.Query.t
def apply(query, binds) do
query = Ecto.Queryable.to_query(query)
check_binds(query, binds)
query
end
defp check_binds(query, count) do
if count > 1 and count > BuilderUtil.count_binds(query) do
raise Ecto.QueryError,
reason: "`from` in query expression specified #{count} " <>
"binds but query contains #{BuilderUtil.count_binds(query)} binds"
end
end
end