From 7042a4691d8711e95623a42cd9597e6cc2e6544a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Mon, 20 May 2024 09:06:38 -0400 Subject: [PATCH 01/12] support subqueries in order_by, group_by, distinct, windows --- lib/ecto/query.ex | 7 ++- lib/ecto/query/builder/distinct.ex | 22 ++++++-- lib/ecto/query/builder/group_by.ex | 22 ++++---- lib/ecto/query/builder/order_by.ex | 44 ++++++++++----- lib/ecto/query/builder/windows.ex | 38 +++++++------ lib/ecto/query/planner.ex | 66 ++++++++++++++++++++++- lib/ecto/repo/preloader.ex | 2 +- test/ecto/query/builder/distinct_test.exs | 15 ++++++ test/ecto/query/builder/group_by_test.exs | 13 +++++ test/ecto/query/builder/order_by_test.exs | 14 +++++ test/ecto/query/builder/windows_test.exs | 14 +++++ 11 files changed, 210 insertions(+), 47 deletions(-) diff --git a/lib/ecto/query.ex b/lib/ecto/query.ex index cc3a691f1d..262031be40 100644 --- a/lib/ecto/query.ex +++ b/lib/ecto/query.ex @@ -431,6 +431,11 @@ defmodule Ecto.Query do defstruct [:expr, :file, :line, params: []] end + defmodule ByExpr do + @moduledoc false + defstruct [:expr, :file, :line, params: [], subqueries: [], aliases: %{}] + end + defmodule BooleanExpr do @moduledoc false defstruct [:op, :expr, :file, :line, params: [], subqueries: []] @@ -2866,7 +2871,7 @@ defmodule Ecto.Query do schema = assert_schema!(query) pks = schema.__schema__(:primary_key) expr = for pk <- pks, do: {dir, field(0, pk)} - %QueryExpr{expr: expr, file: __ENV__.file, line: __ENV__.line} + %ByExpr{expr: expr, file: __ENV__.file, line: __ENV__.line} end defp assert_schema!(%{from: %Ecto.Query.FromExpr{source: {_source, schema}}}) diff --git a/lib/ecto/query/builder/distinct.ex b/lib/ecto/query/builder/distinct.ex index 087205e357..02139014de 100644 --- a/lib/ecto/query/builder/distinct.ex +++ b/lib/ecto/query/builder/distinct.ex @@ -30,11 +30,21 @@ defmodule Ecto.Query.Builder.Distinct do Called at runtime to verify distinct. """ def distinct!(query, distinct, file, line) when is_boolean(distinct) do - apply(query, %Ecto.Query.QueryExpr{expr: distinct, params: [], line: line, file: file}) + apply(query, %Ecto.Query.ByExpr{expr: distinct, params: [], line: line, file: file}) end def distinct!(query, distinct, file, line) do - {expr, params} = Builder.OrderBy.order_by_or_distinct!(:distinct, query, distinct, []) - expr = %Ecto.Query.QueryExpr{expr: expr, params: Enum.reverse(params), line: line, file: file} + {expr, params, subqueries, aliases} = + Builder.OrderBy.order_by_or_distinct!(:distinct, query, distinct, []) + + expr = %Ecto.Query.ByExpr{ + expr: expr, + params: Enum.reverse(params), + line: line, + file: file, + subqueries: subqueries, + aliases: aliases + } + apply(query, expr) end @@ -54,12 +64,14 @@ defmodule Ecto.Query.Builder.Distinct do def build(query, binding, expr, env) do {query, binding} = Builder.escape_binding(query, binding, env) - {expr, {params, _acc}} = escape(expr, {[], %{}}, binding, env) + {expr, {params, acc}} = escape(expr, {[], %{subqueries: [], aliases: {:%{}, [], []}}}, binding, env) params = Builder.escape_params(params) - distinct = quote do: %Ecto.Query.QueryExpr{ + distinct = quote do: %Ecto.Query.ByExpr{ expr: unquote(expr), params: unquote(params), + subqueries: unquote(acc[:subqueries]), + aliases: unquote(acc[:aliases]), file: unquote(env.file), line: unquote(env.line)} Builder.apply_query(query, __MODULE__, [distinct], env) diff --git a/lib/ecto/query/builder/group_by.ex b/lib/ecto/query/builder/group_by.ex index b0f46b7d26..4d6057fd9c 100644 --- a/lib/ecto/query/builder/group_by.ex +++ b/lib/ecto/query/builder/group_by.ex @@ -49,21 +49,21 @@ defmodule Ecto.Query.Builder.GroupBy do Shared between group_by and partition_by. """ def group_or_partition_by!(kind, query, exprs, params) do - {expr, {params, _}} = - Enum.map_reduce(List.wrap(exprs), {params, length(params)}, fn + {expr, {params, _, subqueries, aliases}} = + Enum.map_reduce(List.wrap(exprs), {params, length(params), [], %{}}, fn field, params_count when is_atom(field) -> {to_field(field), params_count} - %Ecto.Query.DynamicExpr{} = dynamic, {params, count} -> - {expr, params, count} = Builder.Dynamic.partially_expand(kind, query, dynamic, params, count) - {expr, {params, count}} + %Ecto.Query.DynamicExpr{} = dynamic, {params, count, subqueries, aliases} -> + {expr, params, subqueries, aliases, count} = Builder.Dynamic.partially_expand(query, dynamic, params, subqueries, aliases, count) + {expr, {params, count, subqueries, aliases}} other, _params_count -> raise ArgumentError, "expected a list of fields and dynamics in `#{kind}`, got: `#{inspect other}`" end) - {expr, params} + {expr, params, subqueries, aliases} end defp to_field(field), do: {{:., [], [{:&, [], [0]}, field]}, [], []} @@ -72,8 +72,8 @@ defmodule Ecto.Query.Builder.GroupBy do Called at runtime to assemble group_by. """ def group_by!(query, group_by, file, line) do - {expr, params} = group_or_partition_by!(:group_by, query, group_by, []) - expr = %Ecto.Query.QueryExpr{expr: expr, params: Enum.reverse(params), line: line, file: file} + {expr, params, subqueries, aliases} = group_or_partition_by!(:group_by, query, group_by, []) + expr = %Ecto.Query.ByExpr{expr: expr, params: Enum.reverse(params), line: line, file: file, subqueries: subqueries, aliases: aliases} apply(query, expr) end @@ -93,12 +93,14 @@ defmodule Ecto.Query.Builder.GroupBy do def build(query, binding, expr, env) do {query, binding} = Builder.escape_binding(query, binding, env) - {expr, {params, _acc}} = escape(:group_by, expr, {[], %{}}, binding, env) + {expr, {params, acc}} = escape(:group_by, expr, {[], %{subqueries: [], aliases: {:%{}, [], []}}}, binding, env) params = Builder.escape_params(params) - group_by = quote do: %Ecto.Query.QueryExpr{ + group_by = quote do: %Ecto.Query.ByExpr{ expr: unquote(expr), params: unquote(params), + subqueries: unquote(acc[:subqueries]), + aliases: unquote(acc[:aliases]), file: unquote(env.file), line: unquote(env.line)} Builder.apply_query(query, __MODULE__, [group_by], env) diff --git a/lib/ecto/query/builder/order_by.ex b/lib/ecto/query/builder/order_by.ex index 9b7a94cdef..4467d85a3d 100644 --- a/lib/ecto/query/builder/order_by.ex +++ b/lib/ecto/query/builder/order_by.ex @@ -136,32 +136,50 @@ defmodule Ecto.Query.Builder.OrderBy do Shared between order_by and distinct. """ def order_by_or_distinct!(kind, query, exprs, params) do - {expr, {params, _}} = - Enum.map_reduce(List.wrap(exprs), {params, length(params)}, fn + {expr, {params, _, subqueries, aliases}} = + Enum.map_reduce(List.wrap(exprs), {params, length(params), [], %{}}, fn {dir, expr}, params_count when dir in @directions -> - {expr, params} = dynamic_or_field!(kind, expr, query, params_count) + {expr, params} = + dynamic_or_field!(kind, expr, query, params_count) + {{dir, expr}, params} expr, params_count -> - {expr, params} = dynamic_or_field!(kind, expr, query, params_count) + {expr, params} = + dynamic_or_field!(kind, expr, query, params_count) + {{:asc, expr}, params} end) - {expr, params} + {expr, params, subqueries, aliases} end @doc """ Called at runtime to assemble order_by. """ def order_by!(query, exprs, op, file, line) do - {expr, params} = order_by_or_distinct!(:order_by, query, exprs, []) - expr = %Ecto.Query.QueryExpr{expr: expr, params: Enum.reverse(params), line: line, file: file} + {expr, params, subqueries, aliases} = order_by_or_distinct!(:order_by, query, exprs, []) + expr = %Ecto.Query.ByExpr{expr: expr, params: Enum.reverse(params), line: line, file: file, subqueries: subqueries, aliases: aliases} apply(query, expr, op) end - defp dynamic_or_field!(kind, %Ecto.Query.DynamicExpr{} = dynamic, query, {params, count}) do - {expr, params, count} = Builder.Dynamic.partially_expand(kind, query, dynamic, params, count) - {expr, {params, count}} + defp dynamic_or_field!( + _kind, + %Ecto.Query.DynamicExpr{} = dynamic, + query, + {params, count, subqueries, aliases} + ) do + {expr, params, subqueries, aliases, count} = + Ecto.Query.Builder.Dynamic.partially_expand( + query, + dynamic, + params, + subqueries, + aliases, + count + ) + + {expr, {params, count, subqueries, aliases}} end defp dynamic_or_field!(_kind, field, _query, params_count) when is_atom(field) do @@ -196,13 +214,15 @@ defmodule Ecto.Query.Builder.OrderBy do def build(query, binding, expr, op, env) do {query, binding} = Builder.escape_binding(query, binding, env) - {expr, {params, _acc}} = escape(:order_by, expr, {[], %{}}, binding, env) + {expr, {params, acc}} = escape(:order_by, expr, {[], %{subqueries: [], aliases: {:%{}, [], []}}}, binding, env) params = Builder.escape_params(params) order_by = - quote do: %Ecto.Query.QueryExpr{ + quote do: %Ecto.Query.ByExpr{ expr: unquote(expr), params: unquote(params), + subqueries: unquote(acc[:subqueries]), + aliases: unquote(acc[:aliases]), file: unquote(env.file), line: unquote(env.line) } diff --git a/lib/ecto/query/builder/windows.ex b/lib/ecto/query/builder/windows.ex index 65e56b02c6..902db05f34 100644 --- a/lib/ecto/query/builder/windows.ex +++ b/lib/ecto/query/builder/windows.ex @@ -125,24 +125,26 @@ defmodule Ecto.Query.Builder.Windows do end defp escape_window(vars, {name, expr}, env) do - {compile_acc, runtime_acc, {params, _acc}} = escape(expr, {[], %{}}, vars, env) - {name, compile_acc, runtime_acc, Builder.escape_params(params)} + {compile_acc, runtime_acc, {params, acc}} = escape(expr, {[], %{subqueries: [], aliases: {:%{}, [], []}}}, vars, env) + {name, compile_acc, runtime_acc, Builder.escape_params(params), acc} end - defp build_compile_window({name, compile_acc, _, params}, env) do + defp build_compile_window({name, compile_acc, _, params, acc}, env) do {name, quote do - %Ecto.Query.QueryExpr{ + %Ecto.Query.ByExpr{ expr: unquote(compile_acc), params: unquote(params), + subqueries: unquote(acc[:subqueries]), + aliases: unquote(acc[:aliases]), file: unquote(env.file), line: unquote(env.line) } end} end - defp build_runtime_window({name, compile_acc, runtime_acc, params}, _env) do - {:{}, [], [name, Enum.reverse(compile_acc), runtime_acc, Enum.reverse(params)]} + defp build_runtime_window({name, compile_acc, runtime_acc, params, acc}, _env) do + {:{}, [], [name, Enum.reverse(compile_acc), runtime_acc, Enum.reverse(params), {:%{}, [], [subqueries: acc[:subqueries], aliases: acc[:aliases]]}]} end @doc """ @@ -150,30 +152,32 @@ defmodule Ecto.Query.Builder.Windows do """ def runtime!(query, runtime, file, line) do windows = - Enum.map(runtime, fn {name, compile_acc, runtime_acc, params} -> - {acc, params} = do_runtime_window!(runtime_acc, query, compile_acc, params) - expr = %Ecto.Query.QueryExpr{expr: Enum.reverse(acc), params: Enum.reverse(params), file: file, line: line} + Enum.map(runtime, fn {name, compile_acc, runtime_acc, params, escape_acc} -> + {{acc, subqueries, aliases}, params} = do_runtime_window!(runtime_acc, query, {compile_acc, escape_acc[:subqueries], escape_acc[:aliases]}, params) + expr = %Ecto.Query.ByExpr{expr: Enum.reverse(acc), params: Enum.reverse(params), file: file, line: line, subqueries: subqueries, aliases: aliases} {name, expr} end) apply(query, windows) end - defp do_runtime_window!([{:order_by, order_by} | kw], query, acc, params) do - {order_by, params} = OrderBy.order_by_or_distinct!(:order_by, query, order_by, params) - do_runtime_window!(kw, query, [{:order_by, order_by} | acc], params) + defp do_runtime_window!([{:order_by, order_by} | kw], query, {acc, subqueries_acc, aliases_acc}, params) do + {order_by, params, subqueries, aliases} = OrderBy.order_by_or_distinct!(:order_by, query, order_by, params) + + do_runtime_window!(kw, query, {[{:order_by, order_by} | acc], subqueries_acc ++ subqueries, Map.merge(aliases_acc, aliases)}, params) end - defp do_runtime_window!([{:partition_by, partition_by} | kw], query, acc, params) do - {partition_by, params} = GroupBy.group_or_partition_by!(:partition_by, query, partition_by, params) - do_runtime_window!(kw, query, [{:partition_by, partition_by} | acc], params) + defp do_runtime_window!([{:partition_by, partition_by} | kw], query, {acc, subqueries_acc, aliases_acc}, params) do + {partition_by, params, subqueries, aliases} = GroupBy.group_or_partition_by!(:partition_by, query, partition_by, params) + + do_runtime_window!(kw, query, {[{:partition_by, partition_by} | acc], subqueries_acc ++ subqueries, Map.merge(aliases_acc, aliases)}, params) end - defp do_runtime_window!([{:frame, frame} | kw], query, acc, params) do + defp do_runtime_window!([{:frame, frame} | kw], query, {acc, subqueries_acc, aliases_acc}, params) do case frame do %Ecto.Query.DynamicExpr{} -> {frame, params, _count} = Builder.Dynamic.partially_expand(:windows, query, frame, params, length(params)) - do_runtime_window!(kw, query, [{:frame, frame} | acc], params) + do_runtime_window!(kw, query, {[{:frame, frame} | acc], subqueries_acc, aliases_acc}, params) _ -> raise ArgumentError, diff --git a/lib/ecto/query/planner.ex b/lib/ecto/query/planner.ex index 051d5d2aa6..1f71f0415c 100644 --- a/lib/ecto/query/planner.ex +++ b/lib/ecto/query/planner.ex @@ -2,7 +2,7 @@ defmodule Ecto.Query.Planner do # Normalizes a query and its parameters. @moduledoc false - alias Ecto.Query.{BooleanExpr, DynamicExpr, FromExpr, JoinExpr, QueryExpr, SelectExpr, LimitExpr} + alias Ecto.Query.{BooleanExpr, ByExpr, DynamicExpr, FromExpr, JoinExpr, QueryExpr, SelectExpr, LimitExpr} if map_size(%Ecto.Query{}) != 21 do raise "Ecto.Query match out of date in builder" @@ -206,6 +206,10 @@ defmodule Ecto.Query.Planner do |> plan_assocs() |> plan_combinations(adapter, cte_names) |> plan_wheres(adapter, cte_names) + |> plan_order_bys(adapter, cte_names) + |> plan_group_bys(adapter, cte_names) + |> plan_distinct(adapter, cte_names) + |> plan_windows(adapter, cte_names) |> plan_select(adapter, cte_names) |> plan_cache(operation, adapter) rescue @@ -676,6 +680,62 @@ defmodule Ecto.Query.Planner do %{query | wheres: wheres, havings: havings} end + @spec plan_order_bys(Ecto.Query.t(), module, map()) :: Ecto.Query.t + defp plan_order_bys(query, adapter, cte_names) do + order_bys = + Enum.map(query.order_bys, fn + %{subqueries: []} = order_by -> + order_by + + %{subqueries: subqueries} = order_by -> + %{order_by | subqueries: Enum.map(subqueries, &plan_subquery(&1, query, nil, adapter, false, cte_names))} + end) + + %{query | order_bys: order_bys} + end + + @spec plan_windows(Ecto.Query.t(), module, map()) :: Ecto.Query.t + defp plan_windows(query, adapter, cte_names) do + windows = + Enum.map(query.windows, fn + {key, %{subqueries: []} = window} -> + {key, window} + + {key, %{subqueries: subqueries} = window} -> + {key, %{window | subqueries: Enum.map(subqueries, &plan_subquery(&1, query, nil, adapter, false, cte_names))}} + end) + + %{query | windows: windows} + end + + @spec plan_distinct(Ecto.Query.t(), module, map()) :: Ecto.Query.t + defp plan_distinct(query, adapter, cte_names) do + case query.distinct do + %Ecto.Query.ByExpr{subqueries: []} -> + query + + %Ecto.Query.ByExpr{subqueries: subqueries} = by_expr -> + %{query | distinct: %{by_expr | subqueries: Enum.map(subqueries, &plan_subquery(&1, query, nil, adapter, false, cte_names))}} + + _ -> + query + end + end + + @spec plan_group_bys(Ecto.Query.t(), module, map()) :: Ecto.Query.t + defp plan_group_bys(query, adapter, cte_names) do + group_bys = + Enum.map(query.group_bys, fn + %{subqueries: []} = group_by -> + group_by + + %{subqueries: subqueries} = group_by -> + %{group_by | subqueries: Enum.map(subqueries, &plan_subquery(&1, query, nil, adapter, false, cte_names))} + end) + + %{query | group_bys: group_bys} + end + @spec plan_select(Ecto.Query.t(), module, map()) :: Ecto.Query.t defp plan_select(query, adapter, cte_names) do case query do @@ -796,6 +856,10 @@ defmodule Ecto.Query.Planner do defp expr_to_cache(%SelectExpr{expr: expr, subqueries: subqueries}) do {expr, Enum.map(subqueries, fn %{cache: cache} -> {:subquery, cache} end)} end + defp expr_to_cache(%ByExpr{expr: expr, subqueries: []}), do: expr + defp expr_to_cache(%ByExpr{expr: expr, subqueries: subqueries}) do + {expr, Enum.map(subqueries, fn %{cache: cache} -> {:subquery, cache} end)} + end defp expr_to_cache(%BooleanExpr{op: op, expr: expr, subqueries: []}), do: {op, expr} defp expr_to_cache(%BooleanExpr{op: op, expr: expr, subqueries: subqueries}) do # Alternate implementation could be replace {:subquery, i} expression in expr. diff --git a/lib/ecto/repo/preloader.ex b/lib/ecto/repo/preloader.ex index 23d3902966..987e62149c 100644 --- a/lib/ecto/repo/preloader.ex +++ b/lib/ecto/repo/preloader.ex @@ -312,7 +312,7 @@ defmodule Ecto.Repo.Preloader do query = add_preload_order(assoc.preload_order, query) update_in query.order_bys, fn order_bys -> - [%Ecto.Query.QueryExpr{expr: [asc: related_field_ast], params: [], + [%Ecto.Query.ByExpr{expr: [asc: related_field_ast], params: [], file: __ENV__.file, line: __ENV__.line}|order_bys] end diff --git a/test/ecto/query/builder/distinct_test.exs b/test/ecto/query/builder/distinct_test.exs index 0a8ace7c72..546dc45126 100644 --- a/test/ecto/query/builder/distinct_test.exs +++ b/test/ecto/query/builder/distinct_test.exs @@ -63,6 +63,21 @@ defmodule Ecto.Query.Builder.DistinctTest do [{1, {0, :foo}}, {"bar", {0, :bar}}, {2, {0, :baz}}, {"bat", {0, :bat}}] end + test "supports subqueries" do + distinct = [ + asc: dynamic([p], exists(from other_post in "posts", where: other_post.id == parent_as(:p).id)) + ] + + %{distinct: distinct} = from p in "posts", as: :p, distinct: ^distinct + assert distinct.expr == [asc: {:exists, [], [subquery: 0]}] + assert [_] = distinct.subqueries + + %{distinct: distinct} = from p in "posts", as: :p, distinct: [asc: exists(from other_post in "posts", where: other_post.id == parent_as(:p).id)] + assert distinct.expr == [asc: {:exists, [], [subquery: 0]}] + assert [_] = distinct.subqueries + end + + test "raises on non-atoms" do message = "expected a field as an atom in `distinct`, got: `\"temp\"`" assert_raise ArgumentError, message, fn -> diff --git a/test/ecto/query/builder/group_by_test.exs b/test/ecto/query/builder/group_by_test.exs index 21cb768183..7fbc6d98dc 100644 --- a/test/ecto/query/builder/group_by_test.exs +++ b/test/ecto/query/builder/group_by_test.exs @@ -53,6 +53,19 @@ defmodule Ecto.Query.Builder.GroupByTest do assert group_by("q", [q], ^[key]).group_bys == group_by("q", [q], [q.title]).group_bys end + test "accepts subqueries" do + key = dynamic([p], exists(from other_q in "q", where: other_q.title == parent_as(:q).title)) + assert [group_by] = group_by("q", [q], ^key).group_bys + + assert group_by.expr == [{:exists, [], [{:subquery, 0}]}] + assert [_] = group_by.subqueries + + assert [group_by] = group_by("q", [q], exists(from other_q in "q", where: other_q.title == parent_as(:q).title)).group_bys + + assert group_by.expr == [{:exists, [], [{:subquery, 0}]}] + assert [_] = group_by.subqueries + end + test "raises when no a field or a list of fields" do message = "expected a field as an atom in `group_by`, got: `\"temp\"`" assert_raise ArgumentError, message, fn -> diff --git a/test/ecto/query/builder/order_by_test.exs b/test/ecto/query/builder/order_by_test.exs index 8165699497..f173b37f78 100644 --- a/test/ecto/query/builder/order_by_test.exs +++ b/test/ecto/query/builder/order_by_test.exs @@ -124,6 +124,20 @@ defmodule Ecto.Query.Builder.OrderByTest do [{1, {0, :foo}}, {"bar", {0, :bar}}, {2, {0, :baz}}, {"bat", {0, :bat}}] end + test "supports subqueries" do + order_by = [ + asc: dynamic([p], exists(from other_post in "posts", where: other_post.id == parent_as(:p).id)) + ] + + %{order_bys: [order_by]} = from p in "posts", as: :p, order_by: ^order_by + assert order_by.expr == [asc: {:exists, [], [subquery: 0]}] + assert [_] = order_by.subqueries + + %{order_bys: [order_by]} = from p in "posts", as: :p, order_by: [asc: exists(from other_post in "posts", where: other_post.id == parent_as(:p).id)] + assert order_by.expr == [asc: {:exists, [], [subquery: 0]}] + assert [_] = order_by.subqueries + end + test "supports interpolated atomnames in selected_as/1" do query = from p in "posts", select: selected_as(p.id, :ident), order_by: selected_as(^:ident) assert [asc: {:selected_as, [], [:ident]}] = hd(query.order_bys).expr diff --git a/test/ecto/query/builder/windows_test.exs b/test/ecto/query/builder/windows_test.exs index cc218ed72b..c47bf13c4e 100644 --- a/test/ecto/query/builder/windows_test.exs +++ b/test/ecto/query/builder/windows_test.exs @@ -77,6 +77,20 @@ defmodule Ecto.Query.Builder.WindowsTest do assert query.windows[:w].params == [{"foo", {0, :foo}}] end + test "supports subqueries" do + partition_by = [dynamic([p], exists(from other_q in "q", where: other_q.title == parent_as(:q).title))] + + query = "q" |> windows([p], w: [partition_by: ^partition_by]) + + assert query.windows[:w].expr[:partition_by] == [{:exists, [], [subquery: 0]}] + assert [_] = query.windows[:w].subqueries + + query = "q" |> windows([p], w: [partition_by: exists(from other_q in "q", where: other_q.title == parent_as(:q).title)]) + + assert query.windows[:w].expr[:partition_by] == [{:exists, [], [subquery: 0]}] + assert [_] = query.windows[:w].subqueries + end + test "raises on invalid partition by" do assert_raise ArgumentError, ~r"expected a list of fields and dynamics in `partition_by`", fn -> windows("q", w: [partition_by: ^[1]]) From 62d0bf969c2817314f92b5461b6f9c05428bb6c7 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 25 May 2024 07:53:44 -0400 Subject: [PATCH 02/12] remove alias tracking from `ByExpr` --- lib/ecto/query.ex | 2 +- lib/ecto/query/builder/distinct.ex | 8 +++----- lib/ecto/query/builder/group_by.ex | 19 +++++++++---------- lib/ecto/query/builder/order_by.ex | 21 ++++++++++----------- lib/ecto/query/builder/windows.ex | 25 ++++++++++++------------- 5 files changed, 35 insertions(+), 40 deletions(-) diff --git a/lib/ecto/query.ex b/lib/ecto/query.ex index 262031be40..4614df8416 100644 --- a/lib/ecto/query.ex +++ b/lib/ecto/query.ex @@ -433,7 +433,7 @@ defmodule Ecto.Query do defmodule ByExpr do @moduledoc false - defstruct [:expr, :file, :line, params: [], subqueries: [], aliases: %{}] + defstruct [:expr, :file, :line, params: [], subqueries: []] end defmodule BooleanExpr do diff --git a/lib/ecto/query/builder/distinct.ex b/lib/ecto/query/builder/distinct.ex index 02139014de..60db471ae2 100644 --- a/lib/ecto/query/builder/distinct.ex +++ b/lib/ecto/query/builder/distinct.ex @@ -33,7 +33,7 @@ defmodule Ecto.Query.Builder.Distinct do apply(query, %Ecto.Query.ByExpr{expr: distinct, params: [], line: line, file: file}) end def distinct!(query, distinct, file, line) do - {expr, params, subqueries, aliases} = + {expr, params, subqueries} = Builder.OrderBy.order_by_or_distinct!(:distinct, query, distinct, []) expr = %Ecto.Query.ByExpr{ @@ -41,8 +41,7 @@ defmodule Ecto.Query.Builder.Distinct do params: Enum.reverse(params), line: line, file: file, - subqueries: subqueries, - aliases: aliases + subqueries: subqueries } apply(query, expr) @@ -64,14 +63,13 @@ defmodule Ecto.Query.Builder.Distinct do def build(query, binding, expr, env) do {query, binding} = Builder.escape_binding(query, binding, env) - {expr, {params, acc}} = escape(expr, {[], %{subqueries: [], aliases: {:%{}, [], []}}}, binding, env) + {expr, {params, acc}} = escape(expr, {[], %{subqueries: []}}, binding, env) params = Builder.escape_params(params) distinct = quote do: %Ecto.Query.ByExpr{ expr: unquote(expr), params: unquote(params), subqueries: unquote(acc[:subqueries]), - aliases: unquote(acc[:aliases]), file: unquote(env.file), line: unquote(env.line)} Builder.apply_query(query, __MODULE__, [distinct], env) diff --git a/lib/ecto/query/builder/group_by.ex b/lib/ecto/query/builder/group_by.ex index 4d6057fd9c..b5fa56519a 100644 --- a/lib/ecto/query/builder/group_by.ex +++ b/lib/ecto/query/builder/group_by.ex @@ -49,21 +49,21 @@ defmodule Ecto.Query.Builder.GroupBy do Shared between group_by and partition_by. """ def group_or_partition_by!(kind, query, exprs, params) do - {expr, {params, _, subqueries, aliases}} = - Enum.map_reduce(List.wrap(exprs), {params, length(params), [], %{}}, fn + {expr, {params, _, subqueries}} = + Enum.map_reduce(List.wrap(exprs), {params, length(params), []}, fn field, params_count when is_atom(field) -> {to_field(field), params_count} - %Ecto.Query.DynamicExpr{} = dynamic, {params, count, subqueries, aliases} -> - {expr, params, subqueries, aliases, count} = Builder.Dynamic.partially_expand(query, dynamic, params, subqueries, aliases, count) - {expr, {params, count, subqueries, aliases}} + %Ecto.Query.DynamicExpr{} = dynamic, {params, count, subqueries} -> + {expr, params, subqueries, _aliases, count} = Builder.Dynamic.partially_expand(query, dynamic, params, subqueries, %{}, count) + {expr, {params, count, subqueries}} other, _params_count -> raise ArgumentError, "expected a list of fields and dynamics in `#{kind}`, got: `#{inspect other}`" end) - {expr, params, subqueries, aliases} + {expr, params, subqueries} end defp to_field(field), do: {{:., [], [{:&, [], [0]}, field]}, [], []} @@ -72,8 +72,8 @@ defmodule Ecto.Query.Builder.GroupBy do Called at runtime to assemble group_by. """ def group_by!(query, group_by, file, line) do - {expr, params, subqueries, aliases} = group_or_partition_by!(:group_by, query, group_by, []) - expr = %Ecto.Query.ByExpr{expr: expr, params: Enum.reverse(params), line: line, file: file, subqueries: subqueries, aliases: aliases} + {expr, params, subqueries} = group_or_partition_by!(:group_by, query, group_by, []) + expr = %Ecto.Query.ByExpr{expr: expr, params: Enum.reverse(params), line: line, file: file, subqueries: subqueries} apply(query, expr) end @@ -93,14 +93,13 @@ defmodule Ecto.Query.Builder.GroupBy do def build(query, binding, expr, env) do {query, binding} = Builder.escape_binding(query, binding, env) - {expr, {params, acc}} = escape(:group_by, expr, {[], %{subqueries: [], aliases: {:%{}, [], []}}}, binding, env) + {expr, {params, acc}} = escape(:group_by, expr, {[], %{subqueries: []}}, binding, env) params = Builder.escape_params(params) group_by = quote do: %Ecto.Query.ByExpr{ expr: unquote(expr), params: unquote(params), subqueries: unquote(acc[:subqueries]), - aliases: unquote(acc[:aliases]), file: unquote(env.file), line: unquote(env.line)} Builder.apply_query(query, __MODULE__, [group_by], env) diff --git a/lib/ecto/query/builder/order_by.ex b/lib/ecto/query/builder/order_by.ex index 4467d85a3d..07aa3db02e 100644 --- a/lib/ecto/query/builder/order_by.ex +++ b/lib/ecto/query/builder/order_by.ex @@ -136,8 +136,8 @@ defmodule Ecto.Query.Builder.OrderBy do Shared between order_by and distinct. """ def order_by_or_distinct!(kind, query, exprs, params) do - {expr, {params, _, subqueries, aliases}} = - Enum.map_reduce(List.wrap(exprs), {params, length(params), [], %{}}, fn + {expr, {params, _, subqueries}} = + Enum.map_reduce(List.wrap(exprs), {params, length(params), []}, fn {dir, expr}, params_count when dir in @directions -> {expr, params} = dynamic_or_field!(kind, expr, query, params_count) @@ -151,15 +151,15 @@ defmodule Ecto.Query.Builder.OrderBy do {{:asc, expr}, params} end) - {expr, params, subqueries, aliases} + {expr, params, subqueries} end @doc """ Called at runtime to assemble order_by. """ def order_by!(query, exprs, op, file, line) do - {expr, params, subqueries, aliases} = order_by_or_distinct!(:order_by, query, exprs, []) - expr = %Ecto.Query.ByExpr{expr: expr, params: Enum.reverse(params), line: line, file: file, subqueries: subqueries, aliases: aliases} + {expr, params, subqueries} = order_by_or_distinct!(:order_by, query, exprs, []) + expr = %Ecto.Query.ByExpr{expr: expr, params: Enum.reverse(params), line: line, file: file, subqueries: subqueries} apply(query, expr, op) end @@ -167,19 +167,19 @@ defmodule Ecto.Query.Builder.OrderBy do _kind, %Ecto.Query.DynamicExpr{} = dynamic, query, - {params, count, subqueries, aliases} + {params, count, subqueries} ) do - {expr, params, subqueries, aliases, count} = + {expr, params, subqueries, _aliases, count} = Ecto.Query.Builder.Dynamic.partially_expand( query, dynamic, params, subqueries, - aliases, + %{}, count ) - {expr, {params, count, subqueries, aliases}} + {expr, {params, count, subqueries}} end defp dynamic_or_field!(_kind, field, _query, params_count) when is_atom(field) do @@ -214,7 +214,7 @@ defmodule Ecto.Query.Builder.OrderBy do def build(query, binding, expr, op, env) do {query, binding} = Builder.escape_binding(query, binding, env) - {expr, {params, acc}} = escape(:order_by, expr, {[], %{subqueries: [], aliases: {:%{}, [], []}}}, binding, env) + {expr, {params, acc}} = escape(:order_by, expr, {[], %{subqueries: []}}, binding, env) params = Builder.escape_params(params) order_by = @@ -222,7 +222,6 @@ defmodule Ecto.Query.Builder.OrderBy do expr: unquote(expr), params: unquote(params), subqueries: unquote(acc[:subqueries]), - aliases: unquote(acc[:aliases]), file: unquote(env.file), line: unquote(env.line) } diff --git a/lib/ecto/query/builder/windows.ex b/lib/ecto/query/builder/windows.ex index 902db05f34..8b0d6cf8f3 100644 --- a/lib/ecto/query/builder/windows.ex +++ b/lib/ecto/query/builder/windows.ex @@ -125,7 +125,7 @@ defmodule Ecto.Query.Builder.Windows do end defp escape_window(vars, {name, expr}, env) do - {compile_acc, runtime_acc, {params, acc}} = escape(expr, {[], %{subqueries: [], aliases: {:%{}, [], []}}}, vars, env) + {compile_acc, runtime_acc, {params, acc}} = escape(expr, {[], %{subqueries: []}}, vars, env) {name, compile_acc, runtime_acc, Builder.escape_params(params), acc} end @@ -136,7 +136,6 @@ defmodule Ecto.Query.Builder.Windows do expr: unquote(compile_acc), params: unquote(params), subqueries: unquote(acc[:subqueries]), - aliases: unquote(acc[:aliases]), file: unquote(env.file), line: unquote(env.line) } @@ -144,7 +143,7 @@ defmodule Ecto.Query.Builder.Windows do end defp build_runtime_window({name, compile_acc, runtime_acc, params, acc}, _env) do - {:{}, [], [name, Enum.reverse(compile_acc), runtime_acc, Enum.reverse(params), {:%{}, [], [subqueries: acc[:subqueries], aliases: acc[:aliases]]}]} + {:{}, [], [name, Enum.reverse(compile_acc), runtime_acc, Enum.reverse(params), {:%{}, [], [subqueries: acc[:subqueries]]}]} end @doc """ @@ -153,31 +152,31 @@ defmodule Ecto.Query.Builder.Windows do def runtime!(query, runtime, file, line) do windows = Enum.map(runtime, fn {name, compile_acc, runtime_acc, params, escape_acc} -> - {{acc, subqueries, aliases}, params} = do_runtime_window!(runtime_acc, query, {compile_acc, escape_acc[:subqueries], escape_acc[:aliases]}, params) - expr = %Ecto.Query.ByExpr{expr: Enum.reverse(acc), params: Enum.reverse(params), file: file, line: line, subqueries: subqueries, aliases: aliases} + {{acc, subqueries}, params} = do_runtime_window!(runtime_acc, query, {compile_acc, escape_acc[:subqueries]}, params) + expr = %Ecto.Query.ByExpr{expr: Enum.reverse(acc), params: Enum.reverse(params), file: file, line: line, subqueries: subqueries} {name, expr} end) apply(query, windows) end - defp do_runtime_window!([{:order_by, order_by} | kw], query, {acc, subqueries_acc, aliases_acc}, params) do - {order_by, params, subqueries, aliases} = OrderBy.order_by_or_distinct!(:order_by, query, order_by, params) + defp do_runtime_window!([{:order_by, order_by} | kw], query, {acc, subqueries_acc}, params) do + {order_by, params, subqueries} = OrderBy.order_by_or_distinct!(:order_by, query, order_by, params) - do_runtime_window!(kw, query, {[{:order_by, order_by} | acc], subqueries_acc ++ subqueries, Map.merge(aliases_acc, aliases)}, params) + do_runtime_window!(kw, query, {[{:order_by, order_by} | acc], subqueries_acc ++ subqueries}, params) end - defp do_runtime_window!([{:partition_by, partition_by} | kw], query, {acc, subqueries_acc, aliases_acc}, params) do - {partition_by, params, subqueries, aliases} = GroupBy.group_or_partition_by!(:partition_by, query, partition_by, params) + defp do_runtime_window!([{:partition_by, partition_by} | kw], query, {acc, subqueries_acc}, params) do + {partition_by, params, subqueries} = GroupBy.group_or_partition_by!(:partition_by, query, partition_by, params) - do_runtime_window!(kw, query, {[{:partition_by, partition_by} | acc], subqueries_acc ++ subqueries, Map.merge(aliases_acc, aliases)}, params) + do_runtime_window!(kw, query, {[{:partition_by, partition_by} | acc], subqueries_acc ++ subqueries}, params) end - defp do_runtime_window!([{:frame, frame} | kw], query, {acc, subqueries_acc, aliases_acc}, params) do + defp do_runtime_window!([{:frame, frame} | kw], query, {acc, subqueries_acc}, params) do case frame do %Ecto.Query.DynamicExpr{} -> {frame, params, _count} = Builder.Dynamic.partially_expand(:windows, query, frame, params, length(params)) - do_runtime_window!(kw, query, {[{:frame, frame} | acc], subqueries_acc, aliases_acc}, params) + do_runtime_window!(kw, query, {[{:frame, frame} | acc], subqueries_acc}, params) _ -> raise ArgumentError, From 57fdecbf000720061be15c2ce24e2c6fc3ef0c3a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 25 May 2024 08:00:38 -0400 Subject: [PATCH 03/12] combine group/order subquery planning into single helper --- lib/ecto/query/planner.ex | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/lib/ecto/query/planner.ex b/lib/ecto/query/planner.ex index 1f71f0415c..c85436bd38 100644 --- a/lib/ecto/query/planner.ex +++ b/lib/ecto/query/planner.ex @@ -206,8 +206,8 @@ defmodule Ecto.Query.Planner do |> plan_assocs() |> plan_combinations(adapter, cte_names) |> plan_wheres(adapter, cte_names) - |> plan_order_bys(adapter, cte_names) - |> plan_group_bys(adapter, cte_names) + |> plan_bys(:order_bys, adapter, cte_names) + |> plan_bys(:group_bys, adapter, cte_names) |> plan_distinct(adapter, cte_names) |> plan_windows(adapter, cte_names) |> plan_select(adapter, cte_names) @@ -680,18 +680,18 @@ defmodule Ecto.Query.Planner do %{query | wheres: wheres, havings: havings} end - @spec plan_order_bys(Ecto.Query.t(), module, map()) :: Ecto.Query.t - defp plan_order_bys(query, adapter, cte_names) do + @spec plan_bys(Ecto.Query.t(), key :: :group_bys | :order_bys, module, map()) :: Ecto.Query.t + defp plan_bys(query, key, adapter, cte_names) do order_bys = - Enum.map(query.order_bys, fn + Enum.map(Map.get(query, key), fn %{subqueries: []} = order_by -> order_by - %{subqueries: subqueries} = order_by -> + %{subqueries: subqueries} = order_by -> %{order_by | subqueries: Enum.map(subqueries, &plan_subquery(&1, query, nil, adapter, false, cte_names))} end) - %{query | order_bys: order_bys} + Map.put(query, key, order_bys) end @spec plan_windows(Ecto.Query.t(), module, map()) :: Ecto.Query.t @@ -722,20 +722,6 @@ defmodule Ecto.Query.Planner do end end - @spec plan_group_bys(Ecto.Query.t(), module, map()) :: Ecto.Query.t - defp plan_group_bys(query, adapter, cte_names) do - group_bys = - Enum.map(query.group_bys, fn - %{subqueries: []} = group_by -> - group_by - - %{subqueries: subqueries} = group_by -> - %{group_by | subqueries: Enum.map(subqueries, &plan_subquery(&1, query, nil, adapter, false, cte_names))} - end) - - %{query | group_bys: group_bys} - end - @spec plan_select(Ecto.Query.t(), module, map()) :: Ecto.Query.t defp plan_select(query, adapter, cte_names) do case query do From 851ddb023e96c58cb587facb071293f3b227a034 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 25 May 2024 16:31:49 -0400 Subject: [PATCH 04/12] Update lib/ecto/query/builder/distinct.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/ecto/query/builder/distinct.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/query/builder/distinct.ex b/lib/ecto/query/builder/distinct.ex index 60db471ae2..a919428190 100644 --- a/lib/ecto/query/builder/distinct.ex +++ b/lib/ecto/query/builder/distinct.ex @@ -69,7 +69,7 @@ defmodule Ecto.Query.Builder.Distinct do distinct = quote do: %Ecto.Query.ByExpr{ expr: unquote(expr), params: unquote(params), - subqueries: unquote(acc[:subqueries]), + subqueries: unquote(acc.subqueries), file: unquote(env.file), line: unquote(env.line)} Builder.apply_query(query, __MODULE__, [distinct], env) From 5dfb31047c2b9a88134c72c7e2a9e0a5009f8e2b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 25 May 2024 16:31:59 -0400 Subject: [PATCH 05/12] Update lib/ecto/query/builder/group_by.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/ecto/query/builder/group_by.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/query/builder/group_by.ex b/lib/ecto/query/builder/group_by.ex index b5fa56519a..0965d111c6 100644 --- a/lib/ecto/query/builder/group_by.ex +++ b/lib/ecto/query/builder/group_by.ex @@ -99,7 +99,7 @@ defmodule Ecto.Query.Builder.GroupBy do group_by = quote do: %Ecto.Query.ByExpr{ expr: unquote(expr), params: unquote(params), - subqueries: unquote(acc[:subqueries]), + subqueries: unquote(acc.subqueries), file: unquote(env.file), line: unquote(env.line)} Builder.apply_query(query, __MODULE__, [group_by], env) From ef3a80af76af57b187b016b8e31efa6a1a5a0aa1 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 25 May 2024 16:32:07 -0400 Subject: [PATCH 06/12] Update lib/ecto/query/builder/order_by.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/ecto/query/builder/order_by.ex | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/ecto/query/builder/order_by.ex b/lib/ecto/query/builder/order_by.ex index 07aa3db02e..771a2d9d1f 100644 --- a/lib/ecto/query/builder/order_by.ex +++ b/lib/ecto/query/builder/order_by.ex @@ -139,9 +139,7 @@ defmodule Ecto.Query.Builder.OrderBy do {expr, {params, _, subqueries}} = Enum.map_reduce(List.wrap(exprs), {params, length(params), []}, fn {dir, expr}, params_count when dir in @directions -> - {expr, params} = - dynamic_or_field!(kind, expr, query, params_count) - + {expr, params} = dynamic_or_field!(kind, expr, query, params_count) {{dir, expr}, params} expr, params_count -> From 19a9ef1e7fe75b693c0195d9c5620104b3f72b2a Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 25 May 2024 16:32:14 -0400 Subject: [PATCH 07/12] Update lib/ecto/query/builder/order_by.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/ecto/query/builder/order_by.ex | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/ecto/query/builder/order_by.ex b/lib/ecto/query/builder/order_by.ex index 771a2d9d1f..d81440ad4a 100644 --- a/lib/ecto/query/builder/order_by.ex +++ b/lib/ecto/query/builder/order_by.ex @@ -143,9 +143,7 @@ defmodule Ecto.Query.Builder.OrderBy do {{dir, expr}, params} expr, params_count -> - {expr, params} = - dynamic_or_field!(kind, expr, query, params_count) - + {expr, params} = dynamic_or_field!(kind, expr, query, params_count) {{:asc, expr}, params} end) From 3c5cabecda0a7b7aad2f5a1ccaea4fd7a7a50d16 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 25 May 2024 16:32:25 -0400 Subject: [PATCH 08/12] Update lib/ecto/query/builder/order_by.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/ecto/query/builder/order_by.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/query/builder/order_by.ex b/lib/ecto/query/builder/order_by.ex index d81440ad4a..a529c59852 100644 --- a/lib/ecto/query/builder/order_by.ex +++ b/lib/ecto/query/builder/order_by.ex @@ -217,7 +217,7 @@ defmodule Ecto.Query.Builder.OrderBy do quote do: %Ecto.Query.ByExpr{ expr: unquote(expr), params: unquote(params), - subqueries: unquote(acc[:subqueries]), + subqueries: unquote(acc.subqueries), file: unquote(env.file), line: unquote(env.line) } From 98f2d5bbdec2fd65ea02ed08d32f82655d35cd14 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 25 May 2024 16:32:32 -0400 Subject: [PATCH 09/12] Update lib/ecto/query/builder/windows.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/ecto/query/builder/windows.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/query/builder/windows.ex b/lib/ecto/query/builder/windows.ex index 8b0d6cf8f3..b3f5b70908 100644 --- a/lib/ecto/query/builder/windows.ex +++ b/lib/ecto/query/builder/windows.ex @@ -135,7 +135,7 @@ defmodule Ecto.Query.Builder.Windows do %Ecto.Query.ByExpr{ expr: unquote(compile_acc), params: unquote(params), - subqueries: unquote(acc[:subqueries]), + subqueries: unquote(acc.subqueries), file: unquote(env.file), line: unquote(env.line) } From 56f3089a5c96225ea97e2d1ccbb713d9a5586a8e Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 25 May 2024 16:33:05 -0400 Subject: [PATCH 10/12] Update lib/ecto/query/builder/windows.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/ecto/query/builder/windows.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/query/builder/windows.ex b/lib/ecto/query/builder/windows.ex index b3f5b70908..2cf9a6c94c 100644 --- a/lib/ecto/query/builder/windows.ex +++ b/lib/ecto/query/builder/windows.ex @@ -143,7 +143,7 @@ defmodule Ecto.Query.Builder.Windows do end defp build_runtime_window({name, compile_acc, runtime_acc, params, acc}, _env) do - {:{}, [], [name, Enum.reverse(compile_acc), runtime_acc, Enum.reverse(params), {:%{}, [], [subqueries: acc[:subqueries]]}]} + {:{}, [], [name, Enum.reverse(compile_acc), runtime_acc, Enum.reverse(params), {:%{}, [], Map.to_list(acc)}]} end @doc """ From 76c432a3c5a8b9390895a0a19fea3e3a9666409f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 25 May 2024 16:33:13 -0400 Subject: [PATCH 11/12] Update lib/ecto/query/builder/windows.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/ecto/query/builder/windows.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ecto/query/builder/windows.ex b/lib/ecto/query/builder/windows.ex index 2cf9a6c94c..c5bfb930b6 100644 --- a/lib/ecto/query/builder/windows.ex +++ b/lib/ecto/query/builder/windows.ex @@ -152,7 +152,7 @@ defmodule Ecto.Query.Builder.Windows do def runtime!(query, runtime, file, line) do windows = Enum.map(runtime, fn {name, compile_acc, runtime_acc, params, escape_acc} -> - {{acc, subqueries}, params} = do_runtime_window!(runtime_acc, query, {compile_acc, escape_acc[:subqueries]}, params) + {{acc, subqueries}, params} = do_runtime_window!(runtime_acc, query, {compile_acc, escape_acc.subqueries}, params) expr = %Ecto.Query.ByExpr{expr: Enum.reverse(acc), params: Enum.reverse(params), file: file, line: line, subqueries: subqueries} {name, expr} end) From 61692ce16d132a4beeea513599c3c5d0567cbf5b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 25 May 2024 16:33:20 -0400 Subject: [PATCH 12/12] Update test/ecto/query/builder/distinct_test.exs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- test/ecto/query/builder/distinct_test.exs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/ecto/query/builder/distinct_test.exs b/test/ecto/query/builder/distinct_test.exs index 546dc45126..d5d99700ae 100644 --- a/test/ecto/query/builder/distinct_test.exs +++ b/test/ecto/query/builder/distinct_test.exs @@ -77,7 +77,6 @@ defmodule Ecto.Query.Builder.DistinctTest do assert [_] = distinct.subqueries end - test "raises on non-atoms" do message = "expected a field as an atom in `distinct`, got: `\"temp\"`" assert_raise ArgumentError, message, fn ->