fix: pull aggregate values properly

This commit is contained in:
Zach Daniel 2022-03-15 19:55:23 -04:00
parent 81dcbf1bdf
commit 920dff7f00
2 changed files with 64 additions and 45 deletions

View file

@ -249,40 +249,46 @@ defmodule Ash.Actions.Read do
data = fetched_data[:results] data = fetched_data[:results]
load_paths = query.context.load_paths load_paths = query.context.load_paths
initial_query = query.context.initial_query initial_query = query.context.initial_query
aggregate_value_request_paths = fetched_data[:aggregate_value_request_paths] || []
case Enum.filter(load_paths, fn path -> if !Enum.empty?(aggregate_value_request_paths) &&
!get_in(context, path ++ [:data]) !get_in(context, path ++ [:aggregate_values]) do
end) do {:new_deps, aggregate_value_request_paths}
[] -> else
data case Enum.filter(load_paths, fn path ->
|> Load.attach_loads(get_in(context, [:data, :fetch, :load]) || %{}) !get_in(context, path ++ [:data])
|> add_aggregate_values( end) do
query.aggregates, [] ->
query.resource, data
Map.get(fetched_data, :aggregate_values) || %{}, |> Load.attach_loads(get_in(context, [:data, :fetch, :load]) || %{})
Map.get(fetched_data, :aggregates_in_query) || [] |> add_aggregate_values(
) query.aggregates,
|> add_calculation_values( query.resource,
Map.get(fetched_data, :ultimate_query) || query, get_in(context, path ++ [:aggregate_values]) || %{},
Map.get(fetched_data, :calculations_at_runtime) || [] Map.get(fetched_data, :aggregates_in_query) || []
) )
|> case do |> add_calculation_values(
{:ok, values} -> Map.get(fetched_data, :ultimate_query) || query,
values Map.get(fetched_data, :calculations_at_runtime) || []
|> add_tenant(query) )
|> add_page( |> case do
action, {:ok, values} ->
Map.get(fetched_data, :count), values
query.sort, |> add_tenant(query)
initial_query, |> add_page(
Keyword.put(query_opts, :page, query.context[:page_opts]) action,
) Map.get(fetched_data, :count),
|> add_query(Map.get(fetched_data, :ultimate_query), request_opts) query.sort,
|> unwrap_for_get(get?) initial_query,
end Keyword.put(query_opts, :page, query.context[:page_opts])
)
|> add_query(Map.get(fetched_data, :ultimate_query), request_opts)
|> unwrap_for_get(get?)
end
deps -> deps ->
{:new_deps, Enum.map(deps, &(&1 ++ [:data]))} {:new_deps, Enum.map(deps, &(&1 ++ [:data]))}
end
end end
end) end)
) )
@ -568,7 +574,9 @@ defmodule Ash.Actions.Read do
%{ %{
results: request_opts[:initial_data], results: request_opts[:initial_data],
aggregates_in_query: aggregates_in_query, aggregates_in_query: aggregates_in_query,
calculations_at_runtime: calculations_at_runtime calculations_at_runtime: calculations_at_runtime,
aggregate_value_request_paths:
Enum.map(aggregate_value_requests, &(&1.path ++ [:data]))
}, },
%{ %{
requests: aggregate_value_requests requests: aggregate_value_requests
@ -606,7 +614,7 @@ defmodule Ash.Actions.Read do
{:ok, query} <- query, {:ok, query} <- query,
{:ok, filter} <- {:ok, filter} <-
filter_with_related(Enum.map(filter_requests, & &1.path), ash_query, data), filter_with_related(Enum.map(filter_requests, & &1.path), ash_query, data),
filter <- update_aggregate_filters(filter, data), filter <- update_aggregate_filters(filter, data, path),
{:ok, query} <- {:ok, query} <-
Ash.DataLayer.set_context( Ash.DataLayer.set_context(
ash_query.resource, ash_query.resource,
@ -674,7 +682,9 @@ defmodule Ash.Actions.Read do
ultimate_query: ultimate_query, ultimate_query: ultimate_query,
count: count, count: count,
calculations_at_runtime: calculations_at_runtime, calculations_at_runtime: calculations_at_runtime,
aggregates_in_query: aggregates_in_query aggregates_in_query: aggregates_in_query,
aggregate_value_request_paths:
Enum.map(aggregate_value_requests, &(&1.path ++ [:data]))
}, },
%{ %{
notifications: after_notifications, notifications: after_notifications,
@ -686,7 +696,9 @@ defmodule Ash.Actions.Read do
results: results, results: results,
count: count, count: count,
calculations_at_runtime: calculations_at_runtime, calculations_at_runtime: calculations_at_runtime,
aggregates_in_query: aggregates_in_query aggregates_in_query: aggregates_in_query,
aggregate_value_request_paths:
Enum.map(aggregate_value_requests, &(&1.path ++ [:data]))
}, },
%{ %{
notifications: after_notifications, notifications: after_notifications,
@ -717,11 +729,14 @@ defmodule Ash.Actions.Read do
defp validate_get(_, _, _), do: :ok defp validate_get(_, _, _), do: :ok
defp update_aggregate_filters(filter, data) do defp update_aggregate_filters(filter, data, path) do
Filter.update_aggregates(filter, fn aggregate, ref -> Filter.update_aggregates(filter, fn aggregate, ref ->
case data[:aggregate][ref.relationship_path ++ aggregate.relationship_path][ case get_in(
:authorization_filter data,
] do path ++
[:aggregate, ref.relationship_path] ++
aggregate.relationship_path ++ [:authorization_filter]
) do
nil -> nil ->
aggregate aggregate
@ -1111,10 +1126,14 @@ defmodule Ash.Actions.Read do
defp add_aggregate_values(results, aggregates, resource, aggregate_values, aggregates_in_query) do defp add_aggregate_values(results, aggregates, resource, aggregate_values, aggregates_in_query) do
keys_to_aggregates = keys_to_aggregates =
Enum.reduce(aggregate_values, %{}, fn {_name, keys_to_values}, acc -> Enum.reduce(aggregate_values, %{}, fn
Enum.reduce(keys_to_values, acc, fn {pkey, values}, acc -> {_name, %{data: keys_to_values}}, acc ->
Map.update(acc, pkey, values, &Map.merge(&1, values)) Enum.reduce(keys_to_values, acc, fn {pkey, values}, acc ->
end) Map.update(acc, pkey, values, &Map.merge(&1, values))
end)
_, acc ->
acc
end) end)
pkey = Ash.Resource.Info.primary_key(resource) pkey = Ash.Resource.Info.primary_key(resource)

View file

@ -281,7 +281,7 @@ defmodule Ash.Query.Aggregate do
resource: aggregate_resource, resource: aggregate_resource,
api: initial_query.api, api: initial_query.api,
query: aggregate_query(related, reverse_relationship, request_path), query: aggregate_query(related, reverse_relationship, request_path),
path: [:aggregate_values, relationship_path], path: request_path ++ [:aggregate_values, relationship_path],
action: Ash.Resource.Info.primary_action(aggregate_resource, :read), action: Ash.Resource.Info.primary_action(aggregate_resource, :read),
name: "fetch aggregate: #{Enum.join(relationship_path, ".")}", name: "fetch aggregate: #{Enum.join(relationship_path, ".")}",
data: data: