ash/test/resource/changes/cascade_destroy_test.exs
Zach Daniel 23d7479417 fix: handle nil notification results better
fix: don't emit after batch notifications if `notify?: false`
2024-05-16 11:19:24 -05:00

176 lines
4.1 KiB
Elixir

defmodule Ash.Test.Resource.Change.CascadeDestroy do
@moduledoc false
use ExUnit.Case, async: true
alias Ash.Test.Domain
alias Ash.Test.Resource.Change.CascadeDestroy, as: Test
defmodule Notifier do
@moduledoc false
use Ash.Notifier
def notify(notification) do
if notification.action.name == :destroy do
Agent.update(
Test.Agent,
&%{&1 | notifications: MapSet.put(&1.notifications, notification.data.id)}
)
end
:ok
end
end
defmodule Author do
@moduledoc false
use Ash.Resource, domain: Domain, data_layer: Ash.DataLayer.Ets
attributes do
uuid_primary_key :id
end
actions do
defaults [:read, create: :*]
destroy :destroy do
primary? true
change cascade_destroy(:posts, return_notifications?: true)
end
destroy :no_notification_destroy do
change cascade_destroy(:posts,
return_notifications?: true,
action: :no_notification_destroy
)
end
end
relationships do
has_many :posts, Test.Post, public?: true
end
code_interface do
define :create
define :destroy
define :no_notification_destroy
define :read
end
end
defmodule Post do
@moduledoc false
use Ash.Resource, domain: Domain, data_layer: Ash.DataLayer.Ets, notifiers: [Test.Notifier]
attributes do
uuid_primary_key :id
end
actions do
defaults [:read, create: :*]
destroy :destroy do
primary? true
require_atomic? false
change before_action(fn changeset, _ ->
Agent.update(
Test.Agent,
&%{&1 | destroys: MapSet.put(&1.destroys, changeset.data.id)}
)
changeset
end)
end
destroy :no_notification_destroy do
end
end
relationships do
belongs_to :author, Test.Author, public?: true, attribute_writable?: true
end
code_interface do
define :create
define :read
end
end
setup do
{:ok, pid} =
start_supervised({Agent, fn -> %{destroys: MapSet.new(), notifications: MapSet.new()} end})
Process.register(pid, Test.Agent)
:ok
end
test "when destroying an author, all their posts area also destroyed" do
author = Author.create!(%{})
post_ids =
1..Enum.random(3..25)
|> Enum.map(fn _ -> Post.create!(%{author_id: author.id}) end)
|> MapSet.new(& &1.id)
Author.destroy!(author)
deleted_ids = Agent.get(Test.Agent, & &1.destroys)
assert MapSet.equal?(post_ids, deleted_ids)
assert [] = Post.read!()
assert [] = Author.read!()
end
test "destroyed records are notified" do
author = Author.create!(%{})
post_ids =
1..Enum.random(3..25)
|> Enum.map(fn _ -> Post.create!(%{author_id: author.id}) end)
|> MapSet.new(& &1.id)
Author.destroy!(author)
notified_ids = Agent.get(Test.Agent, & &1.notifications)
assert MapSet.equal?(post_ids, notified_ids)
end
test "does not error when notifications are requested but none are returned - bulk" do
author = Author.create!(%{})
1..Enum.random(3..5)
|> Enum.map(fn _ -> Post.create!(%{author_id: author.id}) end)
Ash.bulk_destroy!([author], :no_notification_destroy, %{})
assert [] = Post.read!()
assert [] = Author.read!()
end
test "does not error when notifications are requested but none are returned - single" do
author = Author.create!(%{})
1..Enum.random(3..5)
|> Enum.map(fn _ -> Post.create!(%{author_id: author.id}) end)
Author.no_notification_destroy!(author)
assert [] = Post.read!()
assert [] = Author.read!()
end
test "does not error when there is nothing to cascade destroy - resource provided" do
author = Author.create!(%{})
Author.destroy!(author)
assert [] = Author.read!()
end
test "does not error when there is nothing to cascade destroy - ID provided" do
author = Author.create!(%{})
Author.destroy!(author.id)
assert [] = Author.read!()
end
end