c4710n
November 24, 2021, 1:22am
1
When reading the doc of Ecto.Query.join
, I found a piece of code:
from p in Post,
left_join: c in assoc(p, :comments),
select: {p, c}
I am wondering which module define the assoc
above. I have checked:
Ecto.Query
- failed to find it.
Ecto.Query.API
- failed to find it.
Ecto.Query.Build
- failed to find it.
Ecto.assoc
- apparently, I think, Ecto.assoc
is not what I am finding.
Can anyone give some tip on this? Thanks in advanced.
1 Like
I guess assoc
should be in the Ecto.Query.API
module, but it’s not, so this should be a documentation issue.
Actually, there’s no such function in Ecto. So how can a non-existing function be called? If you noticed that Ecto.Query.join
is a macro, you will understand. You can fire up an iex
session without loading any deps, and try this:
iex> quote do: assoc(p, :comments)
{:assoc, [], [{:p, [], Elixir}, :comments]}
The expression assoc(p, :comments)
is halfway compiled to Elixir AST, then dissected and reassembled into something else, rather than executed at run-time.
This is where the magic happens (line 75):
def escape({string, schema} = join, _vars, env) when is_binary(string) do
case Macro.expand(schema, env) do
schema when is_atom(schema) ->
{:_, {string, schema}, nil, []}
_ ->
Builder.error! "malformed join `#{Macro.to_string(join)}` in query expression"
end
end
def escape({:assoc, _, [{var, _, context}, field]}, vars, _env)
when is_atom(var) and is_atom(context) do
ensure_field!(field)
var = Builder.find_var!(var, vars)
field = Builder.quoted_atom!(field, "field/2")
{:_, nil, {var, field}, []}
end
def escape({:^, _, [expr]}, _vars, _env) do
{:_, quote(do: Ecto.Query.Builder.Join.join!(unquote(expr))), nil, []}
end
5 Likes