From 997be890b96cad7dfe031d7936c652d4e6d92723 Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Mon, 20 Nov 2023 23:37:46 +0100 Subject: [PATCH] Add minimal failing test for #182 --- .../test_repo/posts_tags/20231120222259.json | 95 +++++++++++++++++++ .../test_repo/tags/20231120222259.json | 48 ++++++++++ .../migrations/20231120222259_add_tags.exs | 62 ++++++++++++ test/sort_test.exs | 23 ++++- test/support/registry.ex | 2 + test/support/resources/post.ex | 10 ++ test/support/resources/post_tag.ex | 36 +++++++ test/support/resources/tag.ex | 29 ++++++ 8 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 priv/resource_snapshots/test_repo/posts_tags/20231120222259.json create mode 100644 priv/resource_snapshots/test_repo/tags/20231120222259.json create mode 100644 priv/test_repo/migrations/20231120222259_add_tags.exs create mode 100644 test/support/resources/post_tag.ex create mode 100644 test/support/resources/tag.ex diff --git a/priv/resource_snapshots/test_repo/posts_tags/20231120222259.json b/priv/resource_snapshots/test_repo/posts_tags/20231120222259.json new file mode 100644 index 00000000..3842ecc4 --- /dev/null +++ b/priv/resource_snapshots/test_repo/posts_tags/20231120222259.json @@ -0,0 +1,95 @@ +{ + "attributes": [ + { + "default": "nil", + "size": null, + "type": "bigint", + "source": "position", + "references": null, + "allow_nil?": false, + "generated?": false, + "primary_key?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "post_id", + "references": { + "name": "posts_tags_post_id_fkey", + "table": "posts", + "schema": "public", + "on_delete": null, + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "primary_key?": true, + "destination_attribute": "id", + "deferrable": false, + "match_type": null, + "match_with": null, + "on_update": null, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "generated?": false, + "primary_key?": true + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "tag_id", + "references": { + "name": "posts_tags_tag_id_fkey", + "table": "tags", + "schema": "public", + "on_delete": null, + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "primary_key?": true, + "destination_attribute": "id", + "deferrable": false, + "match_type": null, + "match_with": null, + "on_update": null, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "generated?": false, + "primary_key?": true + } + ], + "table": "posts_tags", + "hash": "7F58B3E1346CD5920C87C71859A63DF08743F3B4557A96E85BD08155613DF1D2", + "repo": "Elixir.AshPostgres.TestRepo", + "identities": [ + { + "name": "unique_position_per_post", + "keys": [ + "position", + "post_id" + ], + "base_filter": null, + "index_name": "posts_tags_unique_position_per_post_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/tags/20231120222259.json b/priv/resource_snapshots/test_repo/tags/20231120222259.json new file mode 100644 index 00000000..472b3363 --- /dev/null +++ b/priv/resource_snapshots/test_repo/tags/20231120222259.json @@ -0,0 +1,48 @@ +{ + "attributes": [ + { + "default": "fragment(\"uuid_generate_v4()\")", + "size": null, + "type": "uuid", + "source": "id", + "references": null, + "allow_nil?": false, + "generated?": false, + "primary_key?": true + }, + { + "default": "nil", + "size": null, + "type": "text", + "source": "name", + "references": null, + "allow_nil?": false, + "generated?": false, + "primary_key?": false + } + ], + "table": "tags", + "hash": "61637330BF5FBC9CF074FDAB63DBCB94E33A0352F686A63C87C90133E651DF0E", + "repo": "Elixir.AshPostgres.TestRepo", + "identities": [ + { + "name": "name", + "keys": [ + "name" + ], + "base_filter": null, + "index_name": "tags_name_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/test_repo/migrations/20231120222259_add_tags.exs b/priv/test_repo/migrations/20231120222259_add_tags.exs new file mode 100644 index 00000000..2f928e97 --- /dev/null +++ b/priv/test_repo/migrations/20231120222259_add_tags.exs @@ -0,0 +1,62 @@ +defmodule AshPostgres.TestRepo.Migrations.AddTags 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 table(:tags, primary_key: false) do + add :id, :uuid, null: false, default: fragment("uuid_generate_v4()"), primary_key: true + add :name, :text, null: false + end + + create unique_index(:tags, [:name], name: "tags_name_index") + + create table(:posts_tags, primary_key: false) do + add :position, :bigint, null: false + + add :post_id, + references(:posts, + column: :id, + name: "posts_tags_post_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + + add :tag_id, + references(:tags, + column: :id, + name: "posts_tags_tag_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + end + + create unique_index(:posts_tags, [:position, :post_id], + name: "posts_tags_unique_position_per_post_index" + ) + end + + def down do + drop_if_exists unique_index(:posts_tags, [:position, :post_id], + name: "posts_tags_unique_position_per_post_index" + ) + + drop constraint(:posts_tags, "posts_tags_post_id_fkey") + + drop constraint(:posts_tags, "posts_tags_tag_id_fkey") + + drop table(:posts_tags) + + drop_if_exists unique_index(:tags, [:name], name: "tags_name_index") + + drop table(:tags) + end +end \ No newline at end of file diff --git a/test/sort_test.exs b/test/sort_test.exs index 25f6a8b9..5a26cb8a 100644 --- a/test/sort_test.exs +++ b/test/sort_test.exs @@ -1,7 +1,7 @@ defmodule AshPostgres.SortTest do @moduledoc false use AshPostgres.RepoCase, async: false - alias AshPostgres.Test.{Api, Comment, Post, PostLink} + alias AshPostgres.Test.{Api, Comment, Post, PostLink, Tag} require Ash.Query require Ash.Sort @@ -224,4 +224,25 @@ defmodule AshPostgres.SortTest do |> Ash.Query.load(linked_posts: posts_query) |> Api.read!() end + + test "minimal failing test on expr_sort many_to_many sorting + on_lookup" do + Tag + |> Ash.Changeset.new(%{name: "foo"}) + |> Api.create!() + + tags1 = [%{name: "foo", position: 0}] + + post1 = + Post + |> Ash.Changeset.new() + |> Ash.Changeset.manage_relationship(:ordered_tags, tags1, + on_lookup: {:relate_and_update, :create, :read, [:position]} + ) + |> Api.create!() + + assert %{ordered_tags: [%{name: "foo"}]} = + Post + |> Api.get!(post1.id) + |> Api.load!(:ordered_tags) + end end diff --git a/test/support/registry.ex b/test/support/registry.ex index fe0544c4..152b00eb 100644 --- a/test/support/registry.ex +++ b/test/support/registry.ex @@ -15,5 +15,7 @@ defmodule AshPostgres.Test.Registry do entry(AshPostgres.Test.Account) entry(AshPostgres.Test.Organization) entry(AshPostgres.Test.Manager) + entry(AshPostgres.Test.PostTag) + entry(AshPostgres.Test.Tag) end end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index 6195a000..ab205d85 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -6,6 +6,8 @@ defmodule AshPostgres.Test.Post do Ash.Policy.Authorizer ] + require Ash.Sort + policies do bypass action_type(:read) do # Check that the post is in the same org as actor @@ -149,6 +151,14 @@ defmodule AshPostgres.Test.Post do ) has_many(:views, AshPostgres.Test.PostView) + + has_many(:post_tags, AshPostgres.Test.PostTag) + + many_to_many(:ordered_tags, AshPostgres.Test.Tag, + through: AshPostgres.Test.PostTag, + join_relationship: :post_tags, + sort: Ash.Sort.expr_sort(parent(post_tags.position)) + ) end validations do diff --git a/test/support/resources/post_tag.ex b/test/support/resources/post_tag.ex new file mode 100644 index 00000000..58174bb2 --- /dev/null +++ b/test/support/resources/post_tag.ex @@ -0,0 +1,36 @@ +defmodule AshPostgres.Test.PostTag do + @moduledoc false + use Ash.Resource, + data_layer: AshPostgres.DataLayer + + postgres do + table "posts_tags" + repo AshPostgres.TestRepo + end + + actions do + defaults([:update, :read, :destroy]) + + create :create do + primary?(true) + upsert?(true) + upsert_identity(:unique_position_per_post) + upsert_fields([:tag_id]) + end + end + + attributes do + attribute :position, :integer do + allow_nil?(false) + end + end + + relationships do + belongs_to(:post, AshPostgres.Test.Post, primary_key?: true, allow_nil?: false) + belongs_to(:tag, AshPostgres.Test.Tag, primary_key?: true, allow_nil?: false) + end + + identities do + identity(:unique_position_per_post, [:position, :post_id]) + end +end diff --git a/test/support/resources/tag.ex b/test/support/resources/tag.ex new file mode 100644 index 00000000..97a3caf8 --- /dev/null +++ b/test/support/resources/tag.ex @@ -0,0 +1,29 @@ +defmodule AshPostgres.Test.Tag do + @moduledoc false + use Ash.Resource, + data_layer: AshPostgres.DataLayer + + postgres do + table("tags") + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:read, :update, :destroy]) + + create :create do + primary?(true) + upsert?(true) + upsert_identity(:name) + end + end + + attributes do + uuid_primary_key(:id) + attribute(:name, :string, allow_nil?: false) + end + + identities do + identity(:name, [:name]) + end +end