mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 13:33:20 +12:00
a43624c9f3
--------- Co-authored-by: Alykhan Jetha <aj@marketcircle.com>
292 lines
6.9 KiB
Elixir
292 lines
6.9 KiB
Elixir
defmodule Ash.Test.Resource.Change.CascadeUpdate do
|
|
@moduledoc false
|
|
use ExUnit.Case, async: true
|
|
|
|
alias Ash.Test.Domain
|
|
alias Ash.Test.Resource.Change.CascadeUpdate, as: Test
|
|
|
|
defmodule Notifier do
|
|
@moduledoc false
|
|
use Ash.Notifier
|
|
|
|
def notify(notification) do
|
|
if notification.action.name == :update 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
|
|
attribute :name, :string, public?: true
|
|
end
|
|
|
|
actions do
|
|
default_accept :*
|
|
defaults [:read, create: :*]
|
|
|
|
update :update do
|
|
primary? true
|
|
require_atomic? false
|
|
skip_unknown_inputs [:content]
|
|
|
|
change cascade_update(:posts,
|
|
copy_inputs: [:name, :content],
|
|
return_notifications?: true
|
|
)
|
|
end
|
|
|
|
update :update_atomic do
|
|
change cascade_update(:posts,
|
|
copy_inputs: [:name]
|
|
)
|
|
end
|
|
|
|
update :wrong_relationship_cascade do
|
|
change cascade_update(:postssss,
|
|
copy_inputs: [:name]
|
|
)
|
|
end
|
|
|
|
update :no_notification_update do
|
|
change cascade_update(:posts,
|
|
return_notifications?: true,
|
|
action: :no_notification_update
|
|
)
|
|
end
|
|
end
|
|
|
|
relationships do
|
|
has_many :posts, Test.Post, public?: true
|
|
end
|
|
|
|
code_interface do
|
|
define :create
|
|
define :update
|
|
define :no_notification_update
|
|
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
|
|
attribute :name, :string, public?: true
|
|
end
|
|
|
|
actions do
|
|
default_accept :*
|
|
defaults [:read, create: :*]
|
|
|
|
update :update do
|
|
primary? true
|
|
require_atomic? false
|
|
skip_unknown_inputs [:content]
|
|
|
|
change cascade_update(:comments,
|
|
copy_inputs: [:name]
|
|
)
|
|
|
|
change cascade_update(:summary,
|
|
copy_inputs: [:name, :content]
|
|
)
|
|
|
|
change before_action(fn changeset, _ ->
|
|
Agent.update(
|
|
Test.Agent,
|
|
&%{&1 | updates: MapSet.put(&1.updates, changeset.data.id)}
|
|
)
|
|
|
|
changeset
|
|
end)
|
|
end
|
|
|
|
update :no_notification_update do
|
|
end
|
|
end
|
|
|
|
relationships do
|
|
has_many :comments, Test.Comment, public?: true
|
|
has_one :summary, Test.Summary, public?: true
|
|
belongs_to :author, Test.Author, public?: true, attribute_writable?: true
|
|
end
|
|
|
|
code_interface do
|
|
define :create
|
|
define :update
|
|
define :read
|
|
end
|
|
end
|
|
|
|
defmodule Comment do
|
|
@moduledoc false
|
|
use Ash.Resource, domain: Domain, data_layer: Ash.DataLayer.Ets
|
|
|
|
actions do
|
|
default_accept :*
|
|
defaults [:read, create: :*]
|
|
|
|
update :update do
|
|
primary? true
|
|
end
|
|
end
|
|
|
|
attributes do
|
|
uuid_primary_key :id
|
|
attribute :name, :string, public?: true
|
|
end
|
|
|
|
relationships do
|
|
belongs_to :post, Test.Post, public?: true, attribute_writable?: true
|
|
end
|
|
|
|
code_interface do
|
|
define :create
|
|
define :update
|
|
define :read
|
|
end
|
|
end
|
|
|
|
defmodule Summary do
|
|
@moduledoc false
|
|
use Ash.Resource, domain: Domain, data_layer: Ash.DataLayer.Ets
|
|
|
|
actions do
|
|
default_accept :*
|
|
defaults [:read, create: :*]
|
|
|
|
update :update do
|
|
primary? true
|
|
end
|
|
end
|
|
|
|
attributes do
|
|
uuid_primary_key :id
|
|
attribute :name, :string, public?: true
|
|
attribute :content, :string, public?: true
|
|
end
|
|
|
|
relationships do
|
|
belongs_to :post, Test.Post, public?: true, attribute_writable?: true
|
|
end
|
|
|
|
code_interface do
|
|
define :create
|
|
define :update
|
|
define :read
|
|
end
|
|
end
|
|
|
|
setup do
|
|
{:ok, pid} =
|
|
start_supervised({Agent, fn -> %{updates: MapSet.new(), notifications: MapSet.new()} end})
|
|
|
|
Process.register(pid, Test.Agent)
|
|
|
|
:ok
|
|
end
|
|
|
|
test "when updating an author with name & content, all downstream relationships are also updated" do
|
|
author = Author.create!(%{})
|
|
post1 = Post.create!(%{author_id: author.id})
|
|
post2 = Post.create!(%{author_id: author.id})
|
|
|
|
comment1 = Comment.create!(%{post_id: post1.id})
|
|
comment2 = Comment.create!(%{post_id: post1.id})
|
|
|
|
summary = Summary.create!(%{post_id: post1.id})
|
|
|
|
name = "Ash Framework"
|
|
content = "Is great!"
|
|
|
|
# Cascade the values down the chain...
|
|
author |> Ash.update!(%{name: name, content: content})
|
|
|
|
a = Ash.get!(Author, author.id)
|
|
p = Ash.get!(Post, post1.id)
|
|
p2 = Ash.get!(Post, post2.id)
|
|
c1 = Ash.get!(Comment, comment1.id)
|
|
c2 = Ash.get!(Comment, comment2.id)
|
|
s1 = Ash.get!(Summary, summary.id)
|
|
|
|
assert ^name = a.name
|
|
assert ^name = p.name
|
|
assert ^name = p2.name
|
|
assert ^name = c1.name
|
|
assert ^name = c2.name
|
|
assert ^name = s1.name
|
|
assert ^content = s1.content
|
|
end
|
|
|
|
test "wrong relationship in cascade should error" do
|
|
author = Author.create!(%{})
|
|
Post.create!(%{author_id: author.id})
|
|
|
|
catch_error(
|
|
author
|
|
|> Ash.Changeset.for_update(:wrong_relationship_cascade, %{name: "Ash"})
|
|
|> Ash.update!()
|
|
)
|
|
end
|
|
|
|
test "updated 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)
|
|
|
|
name = "Ash Framework"
|
|
author |> Ash.update!(%{name: name})
|
|
|
|
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_update!([author], :no_notification_update, %{name: "Ash Framework"})
|
|
|
|
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_update!(author, %{name: "Ash Framework"})
|
|
|
|
assert [_ | _] = Post.read!()
|
|
assert [_ | _] = Author.read!()
|
|
end
|
|
|
|
test "does not error when there is nothing to cascade update" do
|
|
author = Author.create!(%{})
|
|
name = "Ash Framework"
|
|
Author.update!(author, %{name: name})
|
|
|
|
a2 = Ash.get!(Author, author.id)
|
|
assert ^name = a2.name
|
|
end
|
|
end
|