Packages
ecto
2.2.0-rc.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/from.ex
defmodule Ecto.Query.Builder.From do
@moduledoc false
alias Ecto.Query.Builder
@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: MySchema)
{quote(do: MySchema), []}
iex> escape(quote do: p in posts)
{quote(do: posts), [p: 0]}
iex> escape(quote do: p in {"posts", MySchema})
{quote(do: {"posts", MySchema}), [p: 0]}
iex> escape(quote do: [p, q] in posts)
{quote(do: posts), [p: 0, q: 1]}
iex> escape(quote do: [_, _] in abc)
{quote(do: abc), [_: 0, _: 1]}
iex> escape(quote do: other)
{quote(do: other), []}
iex> escape(quote do: x() in other)
** (Ecto.Query.CompileError) binding list should contain only variables, got: x()
"""
@spec escape(Macro.t) :: {Macro.t, Keyword.t}
def escape({:in, _, [var, query]}) do
Builder.escape_binding(query, List.wrap(var))
end
def escape(query) do
{query, []}
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.Env.t) :: {Macro.t, Keyword.t, non_neg_integer | nil}
def build(query, env) do
{query, binds} = escape(query)
{count_bind, quoted} =
case expand_from(query, env) do
schema when is_atom(schema) ->
# Get the source at runtime so no unnecessary compile time
# dependencies between modules are added
source = quote do: unquote(schema).__schema__(:source)
prefix = quote do: unquote(schema).__schema__(:prefix)
{1, query(prefix, source, schema)}
source when is_binary(source) ->
# When a binary is used, there is no schema
{1, query(nil, source, nil)}
{source, schema} when is_binary(source) and is_atom(schema) ->
prefix = quote do: unquote(schema).__schema__(:prefix)
{1, query(prefix, source, schema)}
other ->
{nil, other}
end
quoted = Builder.apply_query(quoted, __MODULE__, [length(binds)], env)
{quoted, binds, count_bind}
end
defp query(prefix, source, schema) do
{:%, [], [Ecto.Query, {:%{}, [], [from: {source, schema}, prefix: prefix]}]}
end
defp expand_from({left, right}, env) do
{left, Macro.expand(right, env)}
end
defp expand_from(other, env) do
Macro.expand(other, env)
end
@doc """
The callback applied by `build/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 > Builder.count_binds(query) do
Builder.error! "`from` in query expression specified #{count} " <>
"binds but query contains #{Builder.count_binds(query)} binds"
end
end
end