From 4278f3173689db1b160129a15bc93a300e19b3e8 Mon Sep 17 00:00:00 2001 From: Daniel Newman Date: Mon, 20 Nov 2023 14:48:38 +1000 Subject: [PATCH] Implement test and resources to show reference bug --- test/complex_calculations_test.exs | 73 +++++++++++++++++++ test/support/complex_calculations/registry.ex | 1 + .../complex_calculations/resources/channel.ex | 14 ++++ .../resources/channel_member.ex | 5 +- .../resources/dm_channel.ex | 72 ++++++++++++++++++ 5 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 test/support/complex_calculations/resources/dm_channel.ex diff --git a/test/complex_calculations_test.exs b/test/complex_calculations_test.exs index 01f35e1..cb749d4 100644 --- a/test/complex_calculations_test.exs +++ b/test/complex_calculations_test.exs @@ -1,4 +1,5 @@ defmodule AshPostgres.Test.ComplexCalculationsTest do + alias AshPostgres.Test.ComplexCalculations.Channel use AshPostgres.RepoCase, async: false test "complex calculation" do @@ -112,4 +113,76 @@ defmodule AshPostgres.Test.ComplexCalculationsTest do assert channel.name == user_2.name end + + test "complex calculation while using actor on related resource passes reference" do + dm_channel = + AshPostgres.Test.ComplexCalculations.DMChannel + |> Ash.Changeset.new() + |> AshPostgres.Test.ComplexCalculations.Api.create!() + + user_1 = + AshPostgres.Test.User + |> Ash.Changeset.for_create(:create, %{name: "User 1"}) + |> AshPostgres.Test.Api.create!() + + user_2 = + AshPostgres.Test.User + |> Ash.Changeset.for_create(:create, %{name: "User 2"}) + |> AshPostgres.Test.Api.create!() + + channel_member_1 = + AshPostgres.Test.ComplexCalculations.ChannelMember + |> Ash.Changeset.for_create(:create, %{channel_id: dm_channel.id, user_id: user_1.id}) + |> AshPostgres.Test.ComplexCalculations.Api.create!() + + channel_member_2 = + AshPostgres.Test.ComplexCalculations.ChannelMember + |> Ash.Changeset.new() + |> Ash.Changeset.manage_relationship(:channel, dm_as_channel, type: :append) + |> Ash.Changeset.manage_relationship(:user, user_2, type: :append) + |> AshPostgres.Test.ComplexCalculations.Api.create!() + + dm_channel = + dm_channel + |> AshPostgres.Test.ComplexCalculations.Api.load!([ + :first_member, + :second_member + ]) + + assert dm_channel.first_member.id == channel_member_1.id + assert dm_channel.second_member.id == channel_member_2.id + + dm_channel = + dm_channel + |> AshPostgres.Test.ComplexCalculations.Api.load!(:name, actor: user_1) + + assert dm_channel.name == user_1.name + + dm_channel = + dm_channel + |> AshPostgres.Test.ComplexCalculations.Api.load!(:name, actor: user_2) + + assert dm_channel.name == user_2.name + + channels = + AshPostgres.Test.ComplexCalculations.Channel + |> Ash.Query.for_read(:read) + |> AshPostgres.Test.ComplexCalculations.Api.read!() + + channels = + channels + |> AshPostgres.Test.ComplexCalculations.Api.load!([dm_channel: :name], + actor: user_1 + ) + + [channel | _] = channels + + assert channel.dm_channel.name == user_1.name + + channel = + channel + |> AshPostgres.Test.ComplexCalculations.Api.load(:dm_name, actor: user_1) + + assert channel.dm_name == user_1.name + end end diff --git a/test/support/complex_calculations/registry.ex b/test/support/complex_calculations/registry.ex index 1323267..29f3afc 100644 --- a/test/support/complex_calculations/registry.ex +++ b/test/support/complex_calculations/registry.ex @@ -7,6 +7,7 @@ defmodule AshPostgres.Test.ComplexCalculations.Registry do entry(AshPostgres.Test.ComplexCalculations.Skill) entry(AshPostgres.Test.ComplexCalculations.Documentation) entry(AshPostgres.Test.ComplexCalculations.Channel) + entry(AshPostgres.Test.ComplexCalculations.DMChannel) entry(AshPostgres.Test.ComplexCalculations.ChannelMember) end end diff --git a/test/support/complex_calculations/resources/channel.ex b/test/support/complex_calculations/resources/channel.ex index b357983..188898e 100644 --- a/test/support/complex_calculations/resources/channel.ex +++ b/test/support/complex_calculations/resources/channel.ex @@ -36,11 +36,17 @@ defmodule AshPostgres.Test.ComplexCalculations.Channel do from_many?(true) sort(created_at: :desc) end + + has_one :dm_channel, AshPostgres.Test.ComplexCalculations.DMChannel do + api(AshPostgres.Test.ComplexCalculations.Api) + destination_attribute(:id) + end end aggregates do first(:first_member_name, [:first_member, :user], :name) first(:second_member_name, [:second_member, :user], :name) + first(:dm_channel_name, [:dm_channel], :name) end calculations do @@ -60,5 +66,13 @@ defmodule AshPostgres.Test.ComplexCalculations.Channel do ) ) end + + calculate(:dm_name, :string, expr(dm_channel_name)) + end + + policies do + policy always() do + authorize_if(always()) + end end end diff --git a/test/support/complex_calculations/resources/channel_member.ex b/test/support/complex_calculations/resources/channel_member.ex index dd5a8a8..0d78a29 100644 --- a/test/support/complex_calculations/resources/channel_member.ex +++ b/test/support/complex_calculations/resources/channel_member.ex @@ -21,7 +21,8 @@ defmodule AshPostgres.Test.ComplexCalculations.ChannelMember do end relationships do - belongs_to(:user, AshPostgres.Test.User, api: AshPostgres.Test.Api) - belongs_to(:channel, AshPostgres.Test.ComplexCalculations.Channel) + belongs_to(:user, AshPostgres.Test.User, api: AshPostgres.Test.Api, attribute_writable?: true) + + belongs_to(:channel, AshPostgres.Test.ComplexCalculations.Channel, attribute_writable?: true) end end diff --git a/test/support/complex_calculations/resources/dm_channel.ex b/test/support/complex_calculations/resources/dm_channel.ex new file mode 100644 index 0000000..a5d7100 --- /dev/null +++ b/test/support/complex_calculations/resources/dm_channel.ex @@ -0,0 +1,72 @@ +defmodule AshPostgres.Test.ComplexCalculations.DMChannel do + @moduledoc false + use Ash.Resource, + data_layer: AshPostgres.DataLayer, + authorizers: [Ash.Policy.Authorizer] + + require Ash.Expr + + actions do + defaults([:create, :read, :update, :destroy]) + end + + attributes do + uuid_primary_key(:id) + + create_timestamp(:created_at, private?: false) + update_timestamp(:updated_at, private?: false) + end + + postgres do + table "complex_calculations_channels" + repo(AshPostgres.TestRepo) + end + + relationships do + has_many :channel_members, AshPostgres.Test.ComplexCalculations.ChannelMember do + destination_attribute(:channel_id) + end + + has_one :first_member, AshPostgres.Test.ComplexCalculations.ChannelMember do + destination_attribute(:channel_id) + from_many?(true) + sort(created_at: :asc) + end + + has_one :second_member, AshPostgres.Test.ComplexCalculations.ChannelMember do + destination_attribute(:channel_id) + from_many?(true) + sort(created_at: :desc) + end + end + + aggregates do + first(:first_member_name, [:first_member, :user], :name) + first(:second_member_name, [:second_member, :user], :name) + end + + calculations do + calculate :name, :string do + calculation( + expr( + cond do + first_member.user_id == ^actor(:id) -> + first_member_name + + second_member.user_id == ^actor(:id) -> + second_member_name + + true -> + first_member_name <> ", " <> second_member_name + end + ) + ) + end + end + + policies do + policy always() do + authorize_if(always()) + end + end +end