diff --git a/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json b/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json new file mode 100644 index 0000000..6a4201e --- /dev/null +++ b/priv/resource_snapshots/test_repo/post_permalinks/20240906170759.json @@ -0,0 +1,58 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "post_permalinks_post_id_fkey", + "on_delete": "nothing", + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "posts" + }, + "size": null, + "source": "post_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "2B9B1A4022280ABA644CD2AEB55F765ECC0DFAD3E41F247BFA953ECCB0DCB2F9", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.AshPostgres.TestRepo", + "schema": null, + "table": "post_permalinks" +} \ No newline at end of file diff --git a/priv/test_repo/migrations/20240906170759_migrate_resources38.exs b/priv/test_repo/migrations/20240906170759_migrate_resources38.exs new file mode 100644 index 0000000..f121114 --- /dev/null +++ b/priv/test_repo/migrations/20240906170759_migrate_resources38.exs @@ -0,0 +1,33 @@ +defmodule AshPostgres.TestRepo.Migrations.MigrateResources38 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(:post_permalinks, primary_key: false) do + add(:id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true) + + add( + :post_id, + references(:posts, + column: :id, + name: "post_permalinks_post_id_fkey", + type: :uuid, + prefix: "public", + on_delete: :nothing + ), + null: false + ) + end + end + + def down do + drop(constraint(:post_permalinks, "post_permalinks_post_id_fkey")) + + drop(table(:post_permalinks)) + end +end diff --git a/test/bulk_destroy_test.exs b/test/bulk_destroy_test.exs index dafc292..e30b62d 100644 --- a/test/bulk_destroy_test.exs +++ b/test/bulk_destroy_test.exs @@ -1,5 +1,6 @@ defmodule AshPostgres.BulkDestroyTest do use AshPostgres.RepoCase, async: false + alias AshPostgres.Test.Permalink alias AshPostgres.Test.Post require Ash.Expr @@ -68,4 +69,39 @@ defmodule AshPostgres.BulkDestroyTest do assert [] = Ash.read!(Post) end + + test "bulk destroys errors on constraint violation" do + post = Ash.create!(Post, %{title: "fred"}) + Ash.create!(Permalink, %{post_id: post.id}) + + assert %Ash.BulkResult{ + status: :error, + error_count: 1, + errors: [%Ash.Error.Invalid{}] + } = + Post + |> Ash.read!() + |> Ash.bulk_destroy(:destroy, %{}, + return_records?: true, + return_errors?: true + ) + end + + test "bulk destroys returns error on constraint violation with strategy stream" do + post = Ash.create!(Post, %{title: "fred"}) + Ash.create!(Permalink, %{post_id: post.id}) + + assert %Ash.BulkResult{ + status: :error, + error_count: 1, + errors: [%Ash.Error.Invalid{}] + } = + Post + |> Ash.read!() + |> Ash.bulk_destroy(:destroy, %{}, + strategy: :stream, + return_records?: true, + return_errors?: true + ) + end end diff --git a/test/support/domain.ex b/test/support/domain.ex index a1037a4..353ca4d 100644 --- a/test/support/domain.ex +++ b/test/support/domain.ex @@ -18,6 +18,7 @@ defmodule AshPostgres.Test.Domain do resource(AshPostgres.Test.Manager) resource(AshPostgres.Test.Entity) resource(AshPostgres.Test.TempEntity) + resource(AshPostgres.Test.Permalink) resource(AshPostgres.Test.Record) resource(AshPostgres.Test.PostFollower) resource(AshPostgres.Test.StatefulPostFollower) diff --git a/test/support/resources/permalink.ex b/test/support/resources/permalink.ex new file mode 100644 index 0000000..21df795 --- /dev/null +++ b/test/support/resources/permalink.ex @@ -0,0 +1,33 @@ +defmodule AshPostgres.Test.Permalink do + @moduledoc false + use Ash.Resource, + domain: AshPostgres.Test.Domain, + data_layer: AshPostgres.DataLayer + + actions do + default_accept(:*) + + defaults([:create, :read]) + end + + attributes do + uuid_primary_key(:id) + end + + relationships do + belongs_to :post, AshPostgres.Test.Post do + public?(true) + allow_nil?(false) + attribute_writable?(true) + end + end + + postgres do + table "post_permalinks" + repo AshPostgres.TestRepo + + references do + reference :post, on_delete: :nothing + end + end +end diff --git a/test/support/resources/post.ex b/test/support/resources/post.ex index fabbdc6..31b2272 100644 --- a/test/support/resources/post.ex +++ b/test/support/resources/post.ex @@ -504,6 +504,8 @@ defmodule AshPostgres.Test.Post do has_many(:views, AshPostgres.Test.PostView) do public?(true) end + + has_many(:permalinks, AshPostgres.Test.Permalink) end validations do