From 8b624232282df62a4356cbc1ccc314fa149f7710 Mon Sep 17 00:00:00 2001 From: Junil Chon Date: Tue, 5 Nov 2024 13:19:46 -0600 Subject: [PATCH] chore: provide a test for relationship filter by actor --- test/custom_paginate_test.exs | 85 +++++++++++++++++++ test/support/domain.ex | 1 + .../filter_by_actor_messages_calculation.ex | 36 ++++++++ .../calculations/messages_calculation.ex | 8 +- .../channel/changes/create_message_user.ex | 24 ++++++ test/support/resources/channel/channel.ex | 21 +++++ test/support/resources/channel/message.ex | 10 +-- .../channel/message_viewable_user.ex | 36 ++++++++ .../types/page_of_filter_by_actor_messages.ex | 30 +++++++ 9 files changed, 241 insertions(+), 10 deletions(-) create mode 100644 test/support/resources/channel/calculations/filter_by_actor_messages_calculation.ex create mode 100644 test/support/resources/channel/changes/create_message_user.ex create mode 100644 test/support/resources/channel/message_viewable_user.ex create mode 100644 test/support/resources/channel/types/page_of_filter_by_actor_messages.ex diff --git a/test/custom_paginate_test.exs b/test/custom_paginate_test.exs index feb54f1b..9529102a 100644 --- a/test/custom_paginate_test.exs +++ b/test/custom_paginate_test.exs @@ -164,4 +164,89 @@ defmodule AshGraphql.CustpmPaginateTest do } end end + + test "loading relationships with filter by actor works" do + user_1 = + AshGraphql.Test.User + |> Ash.Changeset.for_create(:create) + |> Ash.create!(authorize?: false) + + user_2 = + AshGraphql.Test.User + |> Ash.Changeset.for_create(:create) + |> Ash.create!(authorize?: false) + + channel = + AshGraphql.Test.Channel + |> Ash.Changeset.for_create(:create, name: "test channel") + |> Ash.create!() + + text_message = + AshGraphql.Test.TextMessage + |> Ash.Changeset.for_create(:create, text: "test text message") + |> Ash.Changeset.manage_relationship(:channel, channel, type: :append_and_remove) + |> Ash.create!() + + AshGraphql.Test.MessageViewableUser + |> Ash.Changeset.for_create(:create, %{user_id: user_1.id, message_id: text_message.id}) + |> Ash.create!() + + image_message = + AshGraphql.Test.ImageMessage + |> Ash.Changeset.for_create(:create, text: "test image message") + |> Ash.Changeset.manage_relationship(:channel, channel, type: :append_and_remove) + |> Ash.create!() + + AshGraphql.Test.MessageViewableUser + |> Ash.Changeset.for_create(:create, %{user_id: user_2.id, message_id: image_message.id}) + |> Ash.create!() + + resp = + """ + query ChannelWithUnionFilterByActorChannelMessages($id: ID!) { + channel(id: $id) { + id + filterByActorChannelMessages { + count + hasNextPage + results { + ...on TextMessage { + __typename + id + text + type + } + ...on ImageMessage { + __typename + id + text + type + } + } + } + } + } + """ + |> Absinthe.run(AshGraphql.Test.Schema, + variables: %{"id" => channel.id}, + context: %{actor: user_1} + ) + + assert {:ok, result} = resp + + refute Map.has_key?(result, :errors) + + %{ + "channel" => %{ + "id" => _, + "filterByActorChannelMessages" => %{ + "count" => count, + "hasNextPage" => _, + "results" => results + } + } + } = result.data + + refute count != Enum.count(results) + end end diff --git a/test/support/domain.ex b/test/support/domain.ex index 65cf0f8f..5f5933c9 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -49,6 +49,7 @@ defmodule AshGraphql.Test.Domain do resource(AshGraphql.Test.Channel) resource(AshGraphql.Test.ChannelSimple) resource(AshGraphql.Test.Message) + resource(AshGraphql.Test.MessageViewableUser) resource(AshGraphql.Test.TextMessage) resource(AshGraphql.Test.ImageMessage) resource(AshGraphql.Test.Subscribable) diff --git a/test/support/resources/channel/calculations/filter_by_actor_messages_calculation.ex b/test/support/resources/channel/calculations/filter_by_actor_messages_calculation.ex new file mode 100644 index 00000000..32a28833 --- /dev/null +++ b/test/support/resources/channel/calculations/filter_by_actor_messages_calculation.ex @@ -0,0 +1,36 @@ +defmodule AshGraphql.Test.PageOfFilterByActorChannelMessagesCalculation do + @moduledoc false + use Ash.Resource.Calculation + + def load(_, _, context) do + limit = context.arguments.limit || 10 + offset = context.arguments.offset || 0 + + [ + :filter_by_user_channel_message_count, + filter_by_actor_messages: + AshGraphql.Test.Message + |> Ash.Query.limit(limit) + |> Ash.Query.offset(offset) + |> Ash.Query.select([:type, :text]) + ] + end + + def calculate([channel], _, context) do + limit = context.arguments.limit || 10 + offset = context.arguments.offset || 0 + + {:ok, + [ + %{ + count: channel.filter_by_user_channel_message_count, + has_next_page: channel.filter_by_user_channel_message_count > offset + limit, + results: + channel.filter_by_actor_messages + |> Enum.map( + &%Ash.Union{type: AshGraphql.Test.MessageUnion.struct_to_name(&1), value: &1} + ) + } + ]} + end +end diff --git a/test/support/resources/channel/calculations/messages_calculation.ex b/test/support/resources/channel/calculations/messages_calculation.ex index 20666fe1..3b20c985 100644 --- a/test/support/resources/channel/calculations/messages_calculation.ex +++ b/test/support/resources/channel/calculations/messages_calculation.ex @@ -16,17 +16,17 @@ defmodule AshGraphql.Test.PageOfChannelMessagesCalculation do ] end - def calculate([post], _, context) do + def calculate([channel], _, context) do limit = context.arguments.limit || 100 offset = context.arguments.offset || 0 {:ok, [ %{ - count: post.channel_message_count, - has_next_page: post.channel_message_count > offset + limit, + count: channel.channel_message_count, + has_next_page: channel.channel_message_count > offset + limit, results: - post.messages + channel.messages |> Enum.map( &%Ash.Union{type: AshGraphql.Test.MessageUnion.struct_to_name(&1), value: &1} ) diff --git a/test/support/resources/channel/changes/create_message_user.ex b/test/support/resources/channel/changes/create_message_user.ex new file mode 100644 index 00000000..4e316939 --- /dev/null +++ b/test/support/resources/channel/changes/create_message_user.ex @@ -0,0 +1,24 @@ +defmodule AshGraphql.Test.Changes.CreateMessageUser do + @moduledoc false + use Ash.Resource.Change + + def change(changeset, _, context) do + IO.inspect(context: context) + + changeset + |> Ash.Changeset.after_action(fn _, result -> + case AshGraphql.Test.MessageUser + |> Ash.Changeset.for_create(:create, %{ + message_id: changeset.data.id, + user_id: context.actor.id + }) + |> Ash.create() do + {:ok, _} -> + {:ok, result} + + {:error, error} -> + {:error, error} + end + end) + end +end diff --git a/test/support/resources/channel/channel.ex b/test/support/resources/channel/channel.ex index 6114981a..de8b0bd2 100644 --- a/test/support/resources/channel/channel.ex +++ b/test/support/resources/channel/channel.ex @@ -69,13 +69,34 @@ defmodule AshGraphql.Test.Channel do default(10) end end + + calculate :filter_by_actor_channel_messages, + AshGraphql.Test.PageOfFilterByActorChannelMessages, + AshGraphql.Test.PageOfFilterByActorChannelMessagesCalculation do + public?(true) + + argument :offset, :integer do + default(0) + end + + argument :limit, :integer do + default(10) + end + end end aggregates do count(:channel_message_count, :messages, public?: true) + + count(:filter_by_user_channel_message_count, :filter_by_actor_messages, public?: true) end relationships do has_many(:messages, AshGraphql.Test.Message, public?: true) + + has_many(:filter_by_actor_messages, AshGraphql.Test.Message, + public?: true, + filter: expr(exists(message_users, user_id == ^actor(:id))) + ) end end diff --git a/test/support/resources/channel/message.ex b/test/support/resources/channel/message.ex index e8da7de2..a7c24027 100644 --- a/test/support/resources/channel/message.ex +++ b/test/support/resources/channel/message.ex @@ -5,8 +5,6 @@ defmodule AshGraphql.Test.Message do domain: AshGraphql.Test.Domain, data_layer: Ash.DataLayer.Ets - # extensions: [AshGraphql.Resource] - ets do table(:message) end @@ -30,9 +28,9 @@ defmodule AshGraphql.Test.Message do relationships do belongs_to(:channel, AshGraphql.Test.Channel, public?: true) - end - # graphql do - # type :message - # end + has_many(:message_users, AshGraphql.Test.MessageViewableUser, + destination_attribute: :message_id + ) + end end diff --git a/test/support/resources/channel/message_viewable_user.ex b/test/support/resources/channel/message_viewable_user.ex new file mode 100644 index 00000000..f12db872 --- /dev/null +++ b/test/support/resources/channel/message_viewable_user.ex @@ -0,0 +1,36 @@ +defmodule AshGraphql.Test.MessageViewableUser do + @moduledoc false + + use Ash.Resource, + domain: AshGraphql.Test.Domain, + data_layer: Ash.DataLayer.Ets + + ets do + table(:message_user) + end + + actions do + default_accept(:*) + defaults([:read, :update, :destroy]) + + create :create do + primary?(true) + end + end + + relationships do + belongs_to(:message, AshGraphql.Test.Message, + primary_key?: true, + allow_nil?: false, + attribute_writable?: true, + public?: true + ) + + belongs_to(:user, AshGraphql.Test.User, + primary_key?: true, + allow_nil?: false, + attribute_writable?: true, + public?: true + ) + end +end diff --git a/test/support/resources/channel/types/page_of_filter_by_actor_messages.ex b/test/support/resources/channel/types/page_of_filter_by_actor_messages.ex new file mode 100644 index 00000000..5c9d65d1 --- /dev/null +++ b/test/support/resources/channel/types/page_of_filter_by_actor_messages.ex @@ -0,0 +1,30 @@ +defmodule AshGraphql.Test.PageOfFilterByActorChannelMessages do + @moduledoc false + + use AshGraphql.Type + + use Ash.Type.NewType, + subtype_of: :map, + constraints: [ + fields: [ + count: [ + type: :integer, + allow_nil?: false + ], + has_next_page: [ + type: :boolean, + allow_nil?: false + ], + results: [ + type: {:array, AshGraphql.Test.MessageUnion}, + allow_nil?: false + ] + ] + ] + + @impl true + def graphql_type(_), do: :filter_by_actor_channel_messages + + @impl true + def graphql_input_type(_), do: :filter_by_actor_channel_messages +end