From d013818c0aeb2fee11e1164a2d3955c74ddf6139 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sun, 21 Jan 2024 00:45:23 -0500 Subject: [PATCH] improvement: handle pkey-less resources when attaching fields improvement: set lazy defaults when applying changeset attributes --- .credo.exs | 2 +- lib/ash/actions/read/read.ex | 47 +++++++++++++++++++++++++++------- lib/ash/changeset/changeset.ex | 2 ++ lib/ash/query/query.ex | 6 +++-- mix.lock | 4 +-- 5 files changed, 47 insertions(+), 14 deletions(-) diff --git a/.credo.exs b/.credo.exs index 5d93b7c7..9215ef22 100644 --- a/.credo.exs +++ b/.credo.exs @@ -103,7 +103,7 @@ {Credo.Check.Readability.ModuleNames, []}, {Credo.Check.Readability.ParenthesesInCondition, false}, {Credo.Check.Readability.ParenthesesOnZeroArityDefs, []}, - {Credo.Check.Readability.PredicateFunctionNames, []}, + {Credo.Check.Readability.PredicateFunctionNames, false}, {Credo.Check.Readability.PreferImplicitTry, []}, {Credo.Check.Readability.RedundantBlankLines, []}, {Credo.Check.Readability.Semicolons, []}, diff --git a/lib/ash/actions/read/read.ex b/lib/ash/actions/read/read.ex index 18e4797a..70aaea52 100644 --- a/lib/ash/actions/read/read.ex +++ b/lib/ash/actions/read/read.ex @@ -634,6 +634,7 @@ defmodule Ash.Actions.Read do result |> Enum.concat(rest) |> Enum.sort_by(& &1.__metadata__[:private][:result_index])} + {:error, error} -> {:error, error} end @@ -1127,14 +1128,14 @@ defmodule Ash.Actions.Read do fields_from_calculations = Enum.map(calculations_in_calculations, & &1.name) - Enum.map(data, fn record -> - case Enum.find(data_with_selected, fn selected_record -> - record.__struct__.primary_key_matches?(record, selected_record) - end) do - nil -> - Ash.Resource.put_metadata(record, :private, %{missing_from_data_layer: true}) - - match -> + if Enum.empty?(fields_from_calculations) and Enum.empty?(fields_from_aggregates) and + Enum.empty?(fields_from_data) do + data + else + # we have to assume they are all there and in the same order. Not my + # favorite thing, but no way around it in the short term. + if Enum.empty?(Ash.Resource.Info.primary_key(original_query.resource)) do + Enum.zip_with([data, data_with_selected], fn [record, match] -> record |> Map.merge(Map.take(match, fields_from_data)) |> Map.update!( @@ -1151,8 +1152,36 @@ defmodule Ash.Actions.Read do Map.take(match.calculations, fields_from_calculations) ) ) + end) + else + Enum.map(data, fn record -> + case Enum.find(data_with_selected, fn selected_record -> + record.__struct__.primary_key_matches?(record, selected_record) + end) do + nil -> + Ash.Resource.put_metadata(record, :private, %{missing_from_data_layer: true}) + + match -> + record + |> Map.merge(Map.take(match, fields_from_data)) + |> Map.update!( + :aggregates, + &Map.merge( + &1, + Map.take(match.aggregates, fields_from_aggregates) + ) + ) + |> Map.update!( + :calculations, + &Map.merge( + &1, + Map.take(match.calculations, fields_from_calculations) + ) + ) + end + end) end - end) + end end defp validate_get([_, _ | _] = results, %{get?: true}, query) do diff --git a/lib/ash/changeset/changeset.ex b/lib/ash/changeset/changeset.ex index cd460975..fbdf0e8c 100644 --- a/lib/ash/changeset/changeset.ex +++ b/lib/ash/changeset/changeset.ex @@ -4307,6 +4307,8 @@ defmodule Ash.Changeset do def apply_attributes(changeset, opts \\ []) def apply_attributes(%{valid?: true} = changeset, _opts) do + changeset = set_defaults(changeset, changeset.action_type, true) + {:ok, Enum.reduce(changeset.attributes, changeset.data, fn {attribute, value}, data -> Map.put(data, attribute, value) diff --git a/lib/ash/query/query.ex b/lib/ash/query/query.ex index 0acd81e1..015615e2 100644 --- a/lib/ash/query/query.ex +++ b/lib/ash/query/query.ex @@ -1296,8 +1296,10 @@ defmodule Ash.Query do add_error(query, :load, error) end else - add_error(query, - Ash.Error.Query.InvalidLoad.exception(load: {resource_calculation.name, args})) + add_error( + query, + Ash.Error.Query.InvalidLoad.exception(load: {resource_calculation.name, args}) + ) end end diff --git a/mix.lock b/mix.lock index 053040ed..e11ad4c4 100644 --- a/mix.lock +++ b/mix.lock @@ -1,8 +1,8 @@ %{ "benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"}, - "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, + "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, - "credo": {:hex, :credo, "1.7.0", "6119bee47272e85995598ee04f2ebbed3e947678dee048d10b5feca139435f75", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6839fcf63d1f0d1c0f450abc8564a57c43d644077ab96f2934563e68b8a769d7"}, + "credo": {:hex, :credo, "1.7.3", "05bb11eaf2f2b8db370ecaa6a6bda2ec49b2acd5e0418bc106b73b07128c0436", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "35ea675a094c934c22fb1dca3696f3c31f2728ae6ef5a53b5d648c11180a4535"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.4.1", "a22ed1e7bd3a3e3f197b68d806ef66acb61ee8f57b3ac85fc5d57354c5482a93", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "84b795d6d7796297cca5a3118444b80c7d94f7ce247d49886e7c291e1ae49801"},