diff --git a/lib/ash/actions/read/calculations.ex b/lib/ash/actions/read/calculations.ex index eb2630a8f..e59d011fb 100644 --- a/lib/ash/actions/read/calculations.ex +++ b/lib/ash/actions/read/calculations.ex @@ -1386,7 +1386,7 @@ defmodule Ash.Actions.Read.Calculations do nil -> related_query = relationship.destination - |> Ash.Query.set_context(%{private: %{lazy?: true}}) + |> Ash.Query.set_context(%{private: %{lazy?: true, reuse_values?: reuse_values?}}) |> Ash.Query.select([]) |> merge_query_load( further, @@ -1814,7 +1814,9 @@ defmodule Ash.Actions.Read.Calculations do Ash.Resource.loaded?(initial_data, relationship_path ++ [calculation], type: :request) end - defp loaded_and_reusable?(_initial_data, _relationship_path, _calculation, _false), do: false + defp loaded_and_reusable?(_initial_data, _relationship_path, _calculation, false) do + false + end defp add_calculation_dependency(query, source, dest) do %{ diff --git a/lib/ash/actions/read/read.ex b/lib/ash/actions/read/read.ex index 9e0679b00..8aa1cf12e 100644 --- a/lib/ash/actions/read/read.ex +++ b/lib/ash/actions/read/read.ex @@ -364,6 +364,7 @@ defmodule Ash.Actions.Read do defp load_relationships(data, query, opts) do lazy? = !!opts[:lazy?] + reuse_values? = !!opts[:reuse_values?] context = %{ @@ -384,7 +385,8 @@ defmodule Ash.Actions.Read do Ash.Actions.Read.Relationships.load( data, query, - lazy? + lazy?, + reuse_values? ) end @@ -392,7 +394,8 @@ defmodule Ash.Actions.Read do Ash.Actions.Read.Relationships.load( data, query, - lazy? + lazy?, + reuse_values? ) end end diff --git a/lib/ash/actions/read/relationships.ex b/lib/ash/actions/read/relationships.ex index d13b25383..bd33d5b69 100644 --- a/lib/ash/actions/read/relationships.ex +++ b/lib/ash/actions/read/relationships.ex @@ -18,10 +18,10 @@ defmodule Ash.Actions.Read.Relationships do {:ok, records} end - def load(records, query, lazy?) do + def load(records, query, lazy?, reuse_values?) do query.load |> with_related_queries(query, records, lazy?) - |> fetch_related_records(records) + |> fetch_related_records(records, reuse_values?) |> attach_related_records(records) end @@ -39,9 +39,9 @@ defmodule Ash.Actions.Read.Relationships do end) end - defp fetch_related_records(batch, records, acc \\ []) + defp fetch_related_records(batch, records, reuse_values?, acc \\ []) - defp fetch_related_records([], _records, acc) do + defp fetch_related_records([], _records, _reuse_values?, acc) do Enum.map(acc, fn {a, b, %Task{} = task} -> {a, b, Task.await(task, :infinity)} @@ -54,12 +54,12 @@ defmodule Ash.Actions.Read.Relationships do end) end - defp fetch_related_records([first | rest], records, acc) do + defp fetch_related_records([first | rest], records, reuse_values?, acc) do result = case first do {relationship, {:lazy, query}} -> {relationship, {:lazy, query}, - lazy_related_records(records, relationship, query, Enum.empty?(rest))} + lazy_related_records(records, relationship, query, Enum.empty?(rest), reuse_values?)} {relationship, %{valid?: true} = related_query} -> do_fetch_related_records(records, relationship, related_query, Enum.empty?(rest)) @@ -68,10 +68,10 @@ defmodule Ash.Actions.Read.Relationships do {relationship, related_query, {:error, errors}} end - fetch_related_records(rest, records, [result | acc]) + fetch_related_records(rest, records, reuse_values?, [result | acc]) end - defp lazy_related_records(records, relationship, related_query, last?) do + defp lazy_related_records(records, relationship, related_query, last?, reuse_values?) do primary_key = Ash.Resource.Info.primary_key(relationship.source) related_records_with_lazy_join_source = @@ -101,6 +101,8 @@ defmodule Ash.Actions.Read.Relationships do fn -> Ash.load(related_records_with_lazy_join_source, related_query, lazy?: true, + reuse_values?: + reuse_values? || related_query.context[:private][:reuse_values?] || false, domain: related_query.domain, actor: related_query.context.private[:actor], tenant: related_query.tenant, diff --git a/lib/ash/changeset/changeset.ex b/lib/ash/changeset/changeset.ex index 265db22d9..d51ce8f10 100644 --- a/lib/ash/changeset/changeset.ex +++ b/lib/ash/changeset/changeset.ex @@ -4280,8 +4280,11 @@ defmodule Ash.Changeset do ], meta: [ type: :any, - doc: - "Freeform data that will be retained along with the options, which can be used to track/manage the changes that are added to the `relationships` key." + doc: """ + Freeform data that will be retained along with the options, which can be used to track/manage the changes + that are added to the `relationships` key. Use the `meta[:order]` option to specify the order in which multiple + calls to `manage_relationship` should be executed. + """ ], ignore?: [ type: :any, diff --git a/test/support/policy_complex/resources/post.ex b/test/support/policy_complex/resources/post.ex index 1b62fb8db..302353b20 100644 --- a/test/support/policy_complex/resources/post.ex +++ b/test/support/policy_complex/resources/post.ex @@ -1,5 +1,6 @@ defmodule Ash.Test.Support.PolicyComplex.Post do @moduledoc false + use Ash.Resource, domain: Ash.Test.Support.PolicyComplex.Domain, data_layer: Ash.DataLayer.Ets, @@ -44,6 +45,7 @@ defmodule Ash.Test.Support.PolicyComplex.Post do end create :create do + primary? true accept [:text] change relate_actor(:author) end