diff --git a/test/atomics_test.exs b/test/atomics_test.exs index 48d7751..4ad038d 100644 --- a/test/atomics_test.exs +++ b/test/atomics_test.exs @@ -294,26 +294,56 @@ defmodule AshPostgres.AtomicsTest do |> Map.get(:records) end - test "can use aggregates in validation" do - post = - Post - |> Ash.Changeset.for_create(:create, %{title: "foo", price: 1}) - |> Ash.create!() + Enum.each( + [ + :exists, + :list, + :count, + :combined + ], + fn aggregate -> + test "can use #{aggregate} in validation" do + post = + Post + |> Ash.Changeset.for_create(:create, %{title: "foo", price: 1}) + |> Ash.create!() - Comment - |> Ash.Changeset.for_create(:create, %{post_id: post.id, title: "foo"}) - |> Ash.create!() + Comment + |> Ash.Changeset.for_create(:create, %{post_id: post.id, title: "foo"}) + |> Ash.create!() - assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> - post - |> Ash.Changeset.for_update(:update_if_no_comments, %{title: "bar"}) - |> Ash.update!() + assert_raise Ash.Error.Invalid, ~r/Can only update if Post has no comments/, fn -> + post + |> Ash.Changeset.new() + |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + |> Ash.Changeset.for_update(:update_if_no_comments, %{title: "bar"}) + |> Ash.update!() + end + + assert_raise Ash.Error.Invalid, ~r/Can only update if Post has no comments/, fn -> + post + |> Ash.Changeset.new() + |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + |> Ash.Changeset.for_update(:update_if_no_comments_non_atomic, %{title: "bar"}) + |> Ash.update!() + end + + assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> + post + |> Ash.Changeset.new() + |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + |> Ash.Changeset.for_destroy(:destroy_if_no_comments_non_atomic, %{}) + |> Ash.destroy!() + end + + assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> + post + |> Ash.Changeset.new() + |> Ash.Changeset.put_context(:aggregate, unquote(aggregate)) + |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) + |> Ash.destroy!() + end + end end - - assert_raise Ash.Error.Invalid, ~r/Can only delete if Post has no comments/, fn -> - post - |> Ash.Changeset.for_destroy(:destroy_if_no_comments, %{}) - |> Ash.destroy!() - end - end + ) end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 3dbd324..473a010 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -17,18 +17,32 @@ defmodule HasNoComments do @moduledoc false use Ash.Resource.Validation - def atomic(_changeset, _opts, _context) do + def atomic(changeset, _opts, context) do # Test multiple types of aggregates in a single validation + condition = + case changeset.context.aggregate do + :exists -> + expr(exists(comments, true)) + + :list -> + expr(length(list(comments, field: :id)) > 0) + + :count -> + expr(count(comments) > 0) + + :combined -> + expr( + exists(comments, true) and + length(list(comments, field: :id)) > 0 and + count(comments) > 0 + ) + end + [ - {:atomic, [], - expr( - length(list(comments, field: :id)) > 0 or - count(comments) > 0 or - exists(comments, true) - ), + {:atomic, [], condition, expr( error(^Ash.Error.Changes.InvalidChanges, %{ - message: "Can only delete if Post has no comments" + message: ^context.message || "Post has comments" }) )} ] @@ -115,11 +129,31 @@ defmodule AshPostgres.Test.Post do end destroy :destroy_if_no_comments do - validate(HasNoComments) + validate HasNoComments do + message "Can only delete if Post has no comments" + end end update :update_if_no_comments do - validate(HasNoComments) + validate HasNoComments do + message "Can only update if Post has no comments" + end + end + + destroy :destroy_if_no_comments_non_atomic do + require_atomic?(false) + + validate HasNoComments do + message "Can only delete if Post has no comments" + end + end + + update :update_if_no_comments_non_atomic do + require_atomic?(false) + + validate HasNoComments do + message "Can only update if Post has no comments" + end end update :update_only_freds do