From ab14f5fb86e97e42e558183e5f6b961f01aecd80 Mon Sep 17 00:00:00 2001 From: Rebecca Le Date: Mon, 26 Jan 2026 01:55:57 +0800 Subject: [PATCH] fix: flatten nested calculation/aggregate maps before wrapping in subquery for aggregates When keyset pagination is combined with a relationship sort and loaded aggregates, the query's select contains nested maps like `%{calculations: %{__calc__0: expr}}`. Ecto doesn't allow nested maps in subquery selects, causing an error. This fix reuses `AshSql.Query.rewrite_nested_selects/1` (already used in `distinct.ex` and `query.ex` for the same purpose) to flatten these nested maps before creating the subquery in `wrap_in_subquery_for_aggregates`. Fixes the failing test in https://github.com/ash-project/ash_postgres/pull/677 --- lib/aggregate.ex | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/lib/aggregate.ex b/lib/aggregate.ex index f213e4f..972ebad 100644 --- a/lib/aggregate.ex +++ b/lib/aggregate.ex @@ -2548,6 +2548,24 @@ defmodule AshSql.Aggregate do ) end + # Flatten nested calculations/aggregates maps before creating subquery + # Ecto doesn't allow nested maps in subquery select expressions + {calculations_require_rewrite, aggregates_require_rewrite, query_with_all_attrs} = + AshSql.Query.rewrite_nested_selects(query_with_all_attrs) + + # After flattening, we need to: + # 1. Use the updated select_calculations from the rewritten query (which excludes :calculations) + # 2. Add the flattened calculation/aggregate field names to the select + flattened_calc_fields = Map.keys(calculations_require_rewrite) + flattened_agg_fields = Map.keys(aggregates_require_rewrite) + + # Get select_calculations from the rewritten query (it has :calculations removed) + select_calculations = + (query_with_all_attrs.__ash_bindings__[:select_calculations] || []) -- [:calculations] + + select_aggregates = + (query_with_all_attrs.__ash_bindings__[:select_aggregates] || []) -- [:aggregates] + subquery_query = from(row in subquery(query_with_all_attrs), as: ^query.__ash_bindings__.root_binding, @@ -2556,8 +2574,10 @@ defmodule AshSql.Aggregate do row, ^Enum.concat([ selected_fields, - query.__ash_bindings__[:select_calculations] || [], - query.__ash_bindings__[:select_aggregates] || [] + select_calculations, + select_aggregates, + flattened_calc_fields, + flattened_agg_fields ]) ) ) @@ -2572,6 +2592,16 @@ defmodule AshSql.Aggregate do query.__ash_bindings__ |> Map.put(:bindings, only_root_binding) |> Map.delete(:__order__?) + |> Map.update( + :calculations_require_rewrite, + calculations_require_rewrite, + &Map.merge(&1, calculations_require_rewrite) + ) + |> Map.update( + :aggregates_require_rewrite, + aggregates_require_rewrite, + &Map.merge(&1, aggregates_require_rewrite) + ) Map.put(subquery_query, :__ash_bindings__, new_bindings) end