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)`
This commit is contained in:
Zach Daniel 2024-07-18 11:26:14 -04:00
parent c23e6de7c6
commit 8612b41155
4 changed files with 36 additions and 2 deletions

View file

@ -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
]
[

View file

@ -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))))

View file

@ -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: [],

View file

@ -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