From 8612b41155b4c45765f80c38c46526e1b37efe1b Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 18 Jul 2024 11:26:14 -0400 Subject: [PATCH] improvement: add `exclude_upsert_actions` configuration this allows for upserting records that factor in archived records. Most commonly, this would be seen as a "create or unarchive" action, so you'd add `change set_attribute(:archived_at, nil)` --- .formatter.exs | 3 ++- .../changes/filter_archived_for_upserts.ex | 5 +++- lib/ash_archival/resource/resource.ex | 7 ++++++ test/archival_test.exs | 23 +++++++++++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/.formatter.exs b/.formatter.exs index 0071c17..a8add4d 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -3,7 +3,8 @@ spark_locals_without_parens = [ attribute: 1, base_filter?: 1, exclude_destroy_actions: 1, - exclude_read_actions: 1 + exclude_read_actions: 1, + exclude_upsert_actions: 1 ] [ diff --git a/lib/ash_archival/resource/changes/filter_archived_for_upserts.ex b/lib/ash_archival/resource/changes/filter_archived_for_upserts.ex index e01156a..050b66f 100644 --- a/lib/ash_archival/resource/changes/filter_archived_for_upserts.ex +++ b/lib/ash_archival/resource/changes/filter_archived_for_upserts.ex @@ -3,7 +3,10 @@ defmodule AshArchival.Resource.Changes.FilterArchivedForUpserts do use Ash.Resource.Change def change(changeset, _, _) do - if changeset.context.private[:upsert?] && + excluded_actions = + AshArchival.Resource.Info.archive_exclude_upsert_actions!(changeset.resource) + + if changeset.action.name not in excluded_actions && changeset.context.private[:upsert?] && !AshArchival.Resource.Info.archive_base_filter?(changeset.resource) do attribute = AshArchival.Resource.Info.archive_attribute!(changeset.resource) Ash.Changeset.filter(changeset, expr(is_nil(^ref(attribute)))) diff --git a/lib/ash_archival/resource/resource.ex b/lib/ash_archival/resource/resource.ex index 61e1e1a..3334f01 100644 --- a/lib/ash_archival/resource/resource.ex +++ b/lib/ash_archival/resource/resource.ex @@ -20,6 +20,13 @@ defmodule AshArchival.Resource do A read action or actions that should show archived items. They will not get the automatic `is_nil(archived_at)` filter. """ ], + exclude_upsert_actions: [ + type: {:wrap_list, :atom}, + default: [], + doc: """ + A create action or actions that should not filter archived records out while upserting. + """ + ], exclude_destroy_actions: [ type: {:wrap_list, :atom}, default: [], diff --git a/test/archival_test.exs b/test/archival_test.exs index a2caa72..548d0bf 100644 --- a/test/archival_test.exs +++ b/test/archival_test.exs @@ -67,11 +67,13 @@ defmodule ArchivalTest do archive do archive_related([:comments]) exclude_read_actions :all_posts + exclude_upsert_actions :upsert end actions do default_accept(:*) defaults([:create, :read, :update, :destroy]) + create(:upsert) read(:all_posts) end @@ -225,6 +227,27 @@ defmodule ArchivalTest do |> Ash.read!() end + test "upserts do consider archived records if the create action is excluded" do + post = + Post + |> Ash.Changeset.for_create(:create, %{name: "fred"}) + |> Ash.create!() + + assert :ok = post |> Ash.destroy!() + + Post + |> Ash.Changeset.for_create(:upsert, %{name: "fred"}, + upsert?: true, + upsert_identity: :unique_name + ) + |> Ash.create!() + + assert [_] = + Post + |> Ash.Query.for_read(:all_posts) + |> Ash.read!() + end + test "destroying a record archives any `archive_related` it has configured" do post = Post