Skip to content

Commit 1be980f

Browse files
Fix macros inside of order_by (#4578)
1 parent 67afe55 commit 1be980f

File tree

2 files changed

+42
-15
lines changed

2 files changed

+42
-15
lines changed

lib/ecto/query/builder/order_by.ex

+39-15
Original file line numberDiff line numberDiff line change
@@ -51,41 +51,57 @@ defmodule Ecto.Query.Builder.OrderBy do
5151
{Macro.t(), {list, term}}
5252
def escape(kind, expr, params_acc, vars, env) do
5353
expr
54-
|> Macro.expand_once(get_env(env))
5554
|> List.wrap()
56-
|> Enum.map_reduce(params_acc, &do_escape(&1, &2, kind, vars, env))
55+
|> Enum.flat_map_reduce(params_acc, &do_escape(&1, &2, kind, vars, env))
5756
end
5857

5958
defp do_escape({dir, {:^, _, [expr]}}, params_acc, kind, _vars, _env) do
60-
{{quoted_dir!(kind, dir),
61-
quote(do: Ecto.Query.Builder.OrderBy.field!(unquote(kind), unquote(expr)))}, params_acc}
59+
{[{quoted_dir!(kind, dir),
60+
quote(do: Ecto.Query.Builder.OrderBy.field!(unquote(kind), unquote(expr)))}], params_acc}
6261
end
6362

6463
defp do_escape({:^, _, [expr]}, params_acc, kind, _vars, _env) do
65-
{{:asc, quote(do: Ecto.Query.Builder.OrderBy.field!(unquote(kind), unquote(expr)))},
64+
{[{:asc, quote(do: Ecto.Query.Builder.OrderBy.field!(unquote(kind), unquote(expr)))}],
6665
params_acc}
6766
end
6867

6968
defp do_escape({dir, field}, params_acc, kind, _vars, _env) when is_atom(field) do
70-
{{quoted_dir!(kind, dir), Macro.escape(to_field(field))}, params_acc}
69+
{[{quoted_dir!(kind, dir), Macro.escape(to_field(field))}], params_acc}
7170
end
7271

7372
defp do_escape(field, params_acc, _kind, _vars, _env) when is_atom(field) do
74-
{{:asc, Macro.escape(to_field(field))}, params_acc}
73+
{[{:asc, Macro.escape(to_field(field))}], params_acc}
7574
end
7675

7776
defp do_escape({dir, expr}, params_acc, kind, vars, env) do
78-
{ast, params_acc} = Builder.escape(expr, :any, params_acc, vars, env)
79-
{{quoted_dir!(kind, dir), ast}, params_acc}
77+
fun = &escape_expansion(kind, &1, &2, &3, &4, &5)
78+
{ast, params_acc} = Builder.escape(expr, :any, params_acc, vars, {env, fun})
79+
{[{quoted_dir!(kind, dir), ast}], params_acc}
8080
end
8181

82-
defp do_escape(expr, params_acc, _kind, vars, env) do
83-
{ast, params_acc} = Builder.escape(expr, :any, params_acc, vars, env)
84-
{{:asc, ast}, params_acc}
82+
defp do_escape(expr, params_acc, kind, vars, env) do
83+
fun = &escape_expansion(kind, &1, &2, &3, &4, &5)
84+
{ast, params_acc} = Builder.escape(expr, :any, params_acc, vars, {env, fun})
85+
86+
if is_list(ast) do
87+
{ast, params_acc}
88+
else
89+
{[{:asc, ast}], params_acc}
90+
end
8591
end
8692

87-
defp get_env({env, _}), do: env
88-
defp get_env(env), do: env
93+
defp escape_expansion(kind, expr, _type, params_acc, vars, env) when is_list(expr) do
94+
escape(kind, expr, params_acc, vars, env)
95+
end
96+
97+
defp escape_expansion(_kind, field, _type, params_acc, _vars, _env) when is_atom(field) do
98+
{Macro.escape(to_field(field)), params_acc}
99+
end
100+
101+
defp escape_expansion(kind, expr, type, params_acc, vars, env) do
102+
fun = &escape_expansion(kind, &1, &2, &3, &4, &5)
103+
Builder.escape(expr, type, params_acc, vars, {env, fun})
104+
end
89105

90106
@doc """
91107
Checks the variable is a quoted direction at compilation time or
@@ -159,7 +175,15 @@ defmodule Ecto.Query.Builder.OrderBy do
159175
"""
160176
def order_by!(query, exprs, op, file, line) do
161177
{expr, params, subqueries} = order_by_or_distinct!(:order_by, query, exprs, [])
162-
expr = %Ecto.Query.ByExpr{expr: expr, params: Enum.reverse(params), line: line, file: file, subqueries: subqueries}
178+
179+
expr = %Ecto.Query.ByExpr{
180+
expr: expr,
181+
params: Enum.reverse(params),
182+
line: line,
183+
file: file,
184+
subqueries: subqueries
185+
}
186+
163187
apply(query, expr, op)
164188
end
165189

test/ecto/query/builder/order_by_test.exs

+3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ defmodule Ecto.Query.Builder.OrderByTest do
5555

5656
assert {Macro.escape(quote do [asc: &0.id(), asc: fragment({:raw, "lower("}, {:expr, &0.title()}, {:raw, ")"}), asc: nth_value(&0.links(), 1)] end), {[], %{}}} ==
5757
escape(:order_by, quote do my_custom_order(x) end, {[], %{}}, [x: 0], __ENV__)
58+
59+
assert assert {[asc: {:{}, [], [:is_nil, [], [{:{}, [], [:&, [], [0]]}]]}], {[], %{}}} ==
60+
escape(:order_by, quote do is_nil(x) end, {[], %{}}, [x: 0], __ENV__)
5861
end
5962

6063
test "raises on unbound variables" do

0 commit comments

Comments
 (0)