fix: when hydrating nested aggregates, use correct related resource/path pair

closes #1213
This commit is contained in:
Zach Daniel 2024-05-30 00:12:12 -05:00
parent 4910bf9d6d
commit fbcafa1bfa
2 changed files with 140 additions and 14 deletions

View file

@ -2789,16 +2789,17 @@ defmodule Ash.Actions.Read do
field = add_calc_context(field, actor, authorize?, tenant, tracer, domain) field = add_calc_context(field, actor, authorize?, tenant, tracer, domain)
if authorize? && field.authorize? do if authorize? && field.authorize? do
authorize_aggregate( {:ok,
field, authorize_aggregate(
path_filters, field,
actor, path_filters,
authorize?, actor,
tenant, authorize?,
tracer, tenant,
domain, tracer,
ref_path domain,
) ref_path
)}
else else
{:ok, agg} {:ok, agg}
end end
@ -2849,15 +2850,15 @@ defmodule Ash.Actions.Read do
end end
%Ash.Resource.Aggregate{} = resource_aggregate -> %Ash.Resource.Aggregate{} = resource_aggregate ->
related_resource = agg_related_resource =
Ash.Resource.Info.related(related_resource, ref_path ++ aggregate.relationship_path) Ash.Resource.Info.related(related_resource, resource_aggregate.relationship_path)
read_action = read_action =
resource_aggregate.read_action || resource_aggregate.read_action ||
Ash.Resource.Info.primary_action!(related_resource, :read).name Ash.Resource.Info.primary_action!(agg_related_resource, :read).name
with %{valid?: true} = aggregate_query <- with %{valid?: true} = aggregate_query <-
Ash.Query.for_read(related_resource, read_action), Ash.Query.for_read(agg_related_resource, read_action),
%{valid?: true} = aggregate_query <- %{valid?: true} = aggregate_query <-
Ash.Query.Aggregate.build_query(aggregate_query, Ash.Query.Aggregate.build_query(aggregate_query,
filter: resource_aggregate.filter, filter: resource_aggregate.filter,

View file

@ -0,0 +1,125 @@
defmodule Ash.Test.Actions.CalculationsReferenceAggregatesTest do
@moduledoc false
use ExUnit.Case, async: true
defmodule One do
use Ash.Resource,
data_layer: Ash.DataLayer.Ets,
domain: Ash.Test.Actions.CalculationsReferenceAggregatesTest.Domain
ets do
private? true
end
actions do
defaults [:read]
end
relationships do
belongs_to :two, Ash.Test.Actions.CalculationsReferenceAggregatesTest.Two
end
attributes do
uuid_primary_key :id
attribute :quantity, :integer, allow_nil?: false, public?: true, constraints: [min: 0]
end
end
defmodule Two do
use Ash.Resource,
data_layer: Ash.DataLayer.Ets,
domain: Ash.Test.Actions.CalculationsReferenceAggregatesTest.Domain
ets do
private? true
end
attributes do
uuid_primary_key :id
end
actions do
defaults [:read]
end
relationships do
has_many :one, One
end
aggregates do
sum :total_quantity, :one, :quantity, default: 0
end
end
defmodule Three do
use Ash.Resource,
data_layer: Ash.DataLayer.Ets,
domain: Ash.Test.Actions.CalculationsReferenceAggregatesTest.Domain
ets do
private? true
end
actions do
defaults [:read]
end
attributes do
uuid_primary_key :id
end
relationships do
belongs_to :two, Two
belongs_to :four, Ash.Test.Actions.CalculationsReferenceAggregatesTest.Four
end
end
defmodule Four do
use Ash.Resource,
data_layer: Ash.DataLayer.Ets,
domain: Ash.Test.Actions.CalculationsReferenceAggregatesTest.Domain
ets do
private? true
end
actions do
defaults [:read, :create]
end
attributes do
uuid_primary_key :id
end
relationships do
has_many :three, Three
end
calculations do
# This throws
calculate :total_quantity,
:integer,
expr(sum(three.two, field: :total_quantity) || 0)
end
end
defmodule Domain do
use Ash.Domain
resources do
resource One
resource Two
resource Three
resource Four
end
end
test "loading calculations that reference aggregates" do
Four
|> Ash.create!(%{})
|> Ash.load!(:total_quantity)
|> Map.get(:total_quantity)
|> Kernel.==(0)
|> assert()
end
end