From bb2b80227daa6cb356e702e9f6d19eb467baaa56 Mon Sep 17 00:00:00 2001 From: Barnabas Jovanovics Date: Tue, 28 May 2024 11:47:07 +0200 Subject: [PATCH] update tests to show many_to_many filter problem --- .../post_followers/20240528090345.json | 95 ++++++++++++++ .../post_followers/20240528092603.json | 108 ++++++++++++++++ .../post_followers/20240528093505.json | 118 ++++++++++++++++++ .../20240528090345_migrate_resources27.exs | 29 +++++ .../20240528092603_migrate_resources28.exs | 25 ++++ .../20240528093505_migrate_resources29.exs | 21 ++++ test/load_test.exs | 33 ++++- test/support/resources/post.ex | 13 ++ test/support/resources/post_follower.ex | 13 +- 9 files changed, 452 insertions(+), 3 deletions(-) create mode 100644 priv/resource_snapshots/test_repo/post_followers/20240528090345.json create mode 100644 priv/resource_snapshots/test_repo/post_followers/20240528092603.json create mode 100644 priv/resource_snapshots/test_repo/post_followers/20240528093505.json create mode 100644 priv/test_repo/migrations/20240528090345_migrate_resources27.exs create mode 100644 priv/test_repo/migrations/20240528092603_migrate_resources28.exs create mode 100644 priv/test_repo/migrations/20240528093505_migrate_resources29.exs diff --git a/priv/resource_snapshots/test_repo/post_followers/20240528090345.json b/priv/resource_snapshots/test_repo/post_followers/20240528090345.json new file mode 100644 index 0000000..cd66137 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_followers/20240528090345.json @@ -0,0 +1,95 @@ +{ + "attributes": [ + { + "default": "fragment(\"gen_random_uuid()\")", + "size": null, + "type": "uuid", + "source": "id", + "references": null, + "allow_nil?": false, + "primary_key?": true, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "bigint", + "source": "order", + "references": null, + "allow_nil?": true, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "post_id", + "references": { + "name": "post_followers_post_id_fkey", + "table": "posts", + "primary_key?": true, + "schema": "public", + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "destination_attribute": "id", + "on_delete": null, + "on_update": null, + "deferrable": false, + "match_with": null, + "match_type": null, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "follower_id", + "references": { + "name": "post_followers_follower_id_fkey", + "table": "users", + "primary_key?": true, + "schema": "public", + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "destination_attribute": "id", + "on_delete": null, + "on_update": null, + "deferrable": false, + "match_with": null, + "match_type": null, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + } + ], + "table": "post_followers", + "hash": "A2DAE11511C56029F1F2AC8776796059F1AF680CD88DFBF91F7DBEA70302B6AF", + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "check_constraints": [], + "identities": [], + "custom_indexes": [], + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "base_filter": null, + "custom_statements": [], + "has_create_action": true +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/post_followers/20240528092603.json b/priv/resource_snapshots/test_repo/post_followers/20240528092603.json new file mode 100644 index 0000000..47bbd61 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_followers/20240528092603.json @@ -0,0 +1,108 @@ +{ + "attributes": [ + { + "default": "fragment(\"gen_random_uuid()\")", + "size": null, + "type": "uuid", + "source": "id", + "references": null, + "allow_nil?": false, + "generated?": false, + "primary_key?": true + }, + { + "default": "nil", + "size": null, + "type": "bigint", + "source": "order", + "references": null, + "allow_nil?": true, + "generated?": false, + "primary_key?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "post_id", + "references": { + "name": "post_followers_post_id_fkey", + "table": "posts", + "schema": "public", + "on_delete": null, + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "primary_key?": true, + "destination_attribute": "id", + "on_update": null, + "deferrable": false, + "match_type": null, + "match_with": null, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "generated?": false, + "primary_key?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "follower_id", + "references": { + "name": "post_followers_follower_id_fkey", + "table": "users", + "schema": "public", + "on_delete": null, + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "primary_key?": true, + "destination_attribute": "id", + "on_update": null, + "deferrable": false, + "match_type": null, + "match_with": null, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "generated?": false, + "primary_key?": false + } + ], + "table": "post_followers", + "hash": "9BAFF682E73CBFDA82F7AE21BEE571C7390BACAE3DDCD658232753A0424300A5", + "repo": "Elixir.AshPostgres.TestRepo", + "identities": [ + { + "name": "join_attributes", + "keys": [ + "follower_id", + "post_id" + ], + "where": null, + "base_filter": null, + "nils_distinct?": true, + "all_tenants?": false, + "index_name": "post_followers_join_attributes_index" + } + ], + "schema": null, + "check_constraints": [], + "custom_indexes": [], + "base_filter": null, + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "custom_statements": [], + "has_create_action": true +} \ No newline at end of file diff --git a/priv/resource_snapshots/test_repo/post_followers/20240528093505.json b/priv/resource_snapshots/test_repo/post_followers/20240528093505.json new file mode 100644 index 0000000..9d161b5 --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_followers/20240528093505.json @@ -0,0 +1,118 @@ +{ + "attributes": [ + { + "default": "fragment(\"gen_random_uuid()\")", + "size": null, + "type": "uuid", + "source": "id", + "references": null, + "allow_nil?": false, + "primary_key?": true, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "bigint", + "source": "order", + "references": null, + "allow_nil?": true, + "primary_key?": false, + "generated?": false + }, + { + "default": "\"active\"", + "size": null, + "type": "text", + "source": "state", + "references": null, + "allow_nil?": true, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "post_id", + "references": { + "name": "post_followers_post_id_fkey", + "table": "posts", + "primary_key?": true, + "destination_attribute": "id", + "schema": "public", + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "on_delete": null, + "on_update": null, + "deferrable": false, + "match_with": null, + "match_type": null, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "follower_id", + "references": { + "name": "post_followers_follower_id_fkey", + "table": "users", + "primary_key?": true, + "destination_attribute": "id", + "schema": "public", + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "on_delete": null, + "on_update": null, + "deferrable": false, + "match_with": null, + "match_type": null, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + } + ], + "table": "post_followers", + "hash": "D6DAC5347205272ED280B52E2A95167A56504474352E22F212BE07B99CE7D21B", + "repo": "Elixir.AshPostgres.TestRepo", + "identities": [ + { + "name": "join_attributes", + "keys": [ + "follower_id", + "post_id" + ], + "where": null, + "base_filter": null, + "all_tenants?": false, + "nils_distinct?": true, + "index_name": "post_followers_join_attributes_index" + } + ], + "check_constraints": [], + "custom_indexes": [], + "base_filter": null, + "schema": null, + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "custom_statements": [], + "has_create_action": true +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240528090345_migrate_resources27.exs b/priv/test_repo/migrations/20240528090345_migrate_resources27.exs new file mode 100644 index 0000000..8067387 --- /dev/null +++ b/priv/test_repo/migrations/20240528090345_migrate_resources27.exs @@ -0,0 +1,29 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources27 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + drop(constraint("post_followers", "post_followers_pkey")) + + alter table(:post_followers) do + modify(:follower_id, :uuid, primary_key: false) + modify(:post_id, :uuid, primary_key: false) + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + end + end + + def down do + drop(constraint("post_followers", "post_followers_pkey")) + + alter table(:post_followers) do + remove(:id) + modify(:post_id, :uuid, primary_key: true) + modify(:follower_id, :uuid, primary_key: true) + end + end +end diff --git a/priv/test_repo/migrations/20240528092603_migrate_resources28.exs b/priv/test_repo/migrations/20240528092603_migrate_resources28.exs new file mode 100644 index 0000000..36484e4 --- /dev/null +++ b/priv/test_repo/migrations/20240528092603_migrate_resources28.exs @@ -0,0 +1,25 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources28 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create( + unique_index(:post_followers, ["follower_id", "post_id"], + name: "post_followers_join_attributes_index" + ) + ) + end + + def down do + drop_if_exists( + unique_index(:post_followers, ["follower_id", "post_id"], + name: "post_followers_join_attributes_index" + ) + ) + end +end diff --git a/priv/test_repo/migrations/20240528093505_migrate_resources29.exs b/priv/test_repo/migrations/20240528093505_migrate_resources29.exs new file mode 100644 index 0000000..38f7201 --- /dev/null +++ b/priv/test_repo/migrations/20240528093505_migrate_resources29.exs @@ -0,0 +1,21 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources29 do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:post_followers) do + add(:state, :text, default: "active") + end + end + + def down do + alter table(:post_followers) do + remove(:state) + end + end +end diff --git a/test/load_test.exs b/test/load_test.exs index ffc7fc2..1602533 100644 --- a/test/load_test.exs +++ b/test/load_test.exs @@ -1,6 +1,6 @@ defmodule AshPostgres.Test.LoadTest do use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Author, Comment, Post, Record, TempEntity, User} + alias AshPostgres.Test.{Author, Comment, Post, Record, TempEntity, User, PostFollower} require Ash.Query @@ -74,6 +74,37 @@ defmodule AshPostgres.Test.LoadTest do assert %{linked_posts: [%{title: "destination"}, %{title: "destination"}]} = results end + test "many_to_many loads work with filter on join relationship" do + followers = + for i <- 0..2 do + User + |> Ash.Changeset.for_create(:create, %{name: "user#{i}", is_active: true}) + |> Ash.create!() + end + + Post + |> Ash.Changeset.for_create(:create, %{title: "a"}) + |> Ash.Changeset.manage_relationship(:followers, followers, type: :append_and_remove) + |> Ash.create!() + + PostFollower + |> Ash.Query.for_read(:read, %{}) + |> Ash.Query.limit(1) + |> Ash.read_one!() + |> Ash.Changeset.for_update(:update, %{state: :inactive}) + |> Ash.update!() + + # Logger.configure(level: :debug) + + [post] = + Post + |> Ash.Query.for_read(:read, %{}) + |> Ash.Query.load(:active_followers) + |> Ash.read!() + + assert length(post.active_followers) == 1 + end + test "many_to_many loads work when nested" do source_post = Post diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 7f8781e..52e9953 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -334,6 +334,19 @@ defmodule AshPostgres.Test.Post do read_action: :active ) + has_many :active_followers_assoc, AshPostgres.Test.PostFollower do + public?(true) + filter(expr(state == :active)) + end + + many_to_many(:active_followers, AshPostgres.Test.User, + public?: true, + through: AshPostgres.Test.PostFollower, + join_relationship: :first_follower_assoc, + source_attribute_on_join_resource: :post_id, + destination_attribute_on_join_resource: :follower_id + ) + has_many(:post_followers, AshPostgres.Test.PostFollower) many_to_many(:sorted_followers, AshPostgres.Test.User, diff --git a/test/support/resources/post_follower.ex b/test/support/resources/post_follower.ex index c00ef22..4afe251 100644 --- a/test/support/resources/post_follower.ex +++ b/test/support/resources/post_follower.ex @@ -9,6 +9,10 @@ defmodule AshPostgres.Test.PostFollower do repo AshPostgres.TestRepo end + identities do + identity(:join_attributes, [:post_id, :follower_id]) + end + actions do default_accept(:*) @@ -16,18 +20,23 @@ defmodule AshPostgres.Test.PostFollower do end attributes do + uuid_primary_key(:id) attribute(:order, :integer, public?: true) + + attribute :state, :atom do + public?(true) + constraints(one_of: [:active, :inactive]) + default(:active) + end end relationships do belongs_to :post, AshPostgres.Test.Post do - primary_key?(true) public?(true) allow_nil?(false) end belongs_to :follower, AshPostgres.Test.User do - primary_key?(true) public?(true) allow_nil?(false) end