fix: use values when already loading aggregates

This commit is contained in:
Zach Daniel 2023-03-29 08:00:42 -04:00
parent 9c5119d8c8
commit 24d802cd4b
4 changed files with 91 additions and 5 deletions

View file

@ -1662,10 +1662,10 @@ defmodule Ash.Actions.Load do
cond do
lateral_join?(query, relationship, source_data) ->
{:ok, Ash.Query.unset(query, :load)}
{:ok, %{query | load: []}}
Map.get(relationship, :no_attributes?) ->
{:ok, query}
{:ok, %{query | load: []}}
true ->
query =
@ -1714,7 +1714,7 @@ defmodule Ash.Actions.Load do
new_query =
query
|> Ash.Query.filter(^[{relationship.destination_attribute, filter_value}])
|> Ash.Query.unset(:load)
|> Map.put(:load, [])
{:ok, new_query}
end

View file

@ -812,6 +812,12 @@ defmodule Ash.Actions.Read do
data[:tracer]
)
ash_query =
add_aggregates_and_attributes_to_loaded_relationships(
ash_query,
calculation_dependencies
)
must_be_reselected =
if request_opts[:initial_data] do
# If there wasn't an explicit query select
@ -1249,6 +1255,43 @@ defmodule Ash.Actions.Read do
defp validate_get(_, _, _), do: :ok
defp add_aggregates_and_attributes_to_loaded_relationships(
query,
calculation_deps
) do
calculation_deps = Enum.uniq(calculation_deps)
calculation_deps
|> Enum.filter(&(&1.type == :relationship && loading?(query, &1)))
|> Enum.reduce(query, fn relationship_dep, query ->
to_load =
calculation_deps
|> Enum.filter(fn dep ->
dep.type in [:attribute, :aggregate] &&
dep.path ==
relationship_dep.path ++ [{relationship_dep.relationship, relationship_dep.query}]
end)
|> Enum.map(fn dep ->
if dep.type == :attribute do
dep.attribute
else
dep.aggregate
end
end)
load =
relationship_dep.path
|> Enum.map(&elem(&1, 0))
|> Enum.concat([relationship_dep.relationship])
|> to_load(to_load)
Ash.Query.load(query, load)
end)
end
defp to_load([], leaf), do: leaf
defp to_load([path | rest], leaf), do: [{path, to_load(rest, leaf)}]
defp calculation_dependency_requests(
query,
calculation_deps,
@ -1727,7 +1770,9 @@ defmodule Ash.Actions.Read do
# TODO: Make more generic?
defp query_unique_for_calc(query) do
Ash.Query.unset(query, [:load])
query
|> Ash.Query.unset([:load])
|> Map.put(:api, nil)
end
defp loading?(query, %{

View file

@ -393,7 +393,7 @@ defmodule Ash.Engine do
defp name_of({path, dep}, state) do
case Enum.find(state.requests, &(&1.path == path)) do
nil ->
"unknown dependency: #{inspect(path, structs: false)} -> #{inspect(dep)}"
"unknown dependency: #{inspect(path)} -> #{inspect(dep)}"
request ->
"#{request.name} -> #{inspect(dep)}"

View file

@ -148,6 +148,20 @@ defmodule Ash.Test.CalculationTest do
end
end
defmodule BestFriendsBestFriendsFirstName do
use Ash.Calculation
def load(_query, _opts, _) do
[best_friend: :best_friends_first_name]
end
def calculate(records, _opts, _) do
Enum.map(records, fn record ->
"bf: #{record.best_friend && record.best_friend.best_friends_first_name}"
end)
end
end
defmodule FriendsNames do
use Ash.Calculation
@ -211,6 +225,8 @@ defmodule Ash.Test.CalculationTest do
constraints: [allow_empty?: true, trim?: false]
end
calculate :best_friends_best_friends_first_name, :string, BestFriendsBestFriendsFirstName
calculate :best_friends_first_name_plus_stuff,
:string,
BestFriendsFirstNamePlusStuff
@ -656,4 +672,29 @@ defmodule Ash.Test.CalculationTest do
assert best_friends_names == [nil, "zach daniel"]
end
test "loading a nested aggregate works" do
best_friends_best_friends_first_names =
User
|> Ash.Query.load(:best_friends_best_friends_first_name)
|> Api.read!()
|> Enum.map(& &1.best_friends_best_friends_first_name)
|> Enum.sort()
assert best_friends_best_friends_first_names == ["bf: ", "bf: "]
end
test "loading a nested aggregate works even when its already being loaded" do
best_friends_best_friends_first_names =
User
|> Ash.Query.load([
:best_friends_best_friends_first_name,
best_friend: [best_friend: [:first_name]]
])
|> Api.read!()
|> Enum.map(& &1.best_friends_best_friends_first_name)
|> Enum.sort()
assert best_friends_best_friends_first_names == ["bf: ", "bf: "]
end
end