improvement: add get_and_lock/1 builtin change

This commit is contained in:
Zach Daniel 2023-05-16 14:59:47 -04:00
parent 2c8c8cafad
commit 7de83e8bb1
2 changed files with 44 additions and 0 deletions

View file

@ -107,6 +107,22 @@ defmodule Ash.Resource.Change.Builtins do
{Ash.Resource.Change.GetAndLockForUpdate, []}
end
@doc """
Re-fetches the record being updated and locks it for update.
Only usable with data layers that support locking `:for_update`.
This happens in a `before_action` hook (so that it is done as part of the transaction).
If your resource has global validations (in the top level `validations` block), you may
want to add `delay_global_validations? true` to your action to ensure they happen on the
locked record.
"""
@spec get_and_lock(lock :: Ash.DataLayer.lock_type()) :: Ash.Resource.Change.ref()
def get_and_lock(lock) do
{Ash.Resource.Change.GetAndLock, [lock: lock]}
end
@doc """
Sets the attribute to the value provided.

View file

@ -0,0 +1,28 @@
defmodule Ash.Resource.Change.GetAndLock do
@moduledoc """
Refetches the record being updated or destroyed, and locks it with the given type.
"""
use Ash.Resource.Change
def change(changeset, opts, context) do
Ash.Changeset.before_action(changeset, fn changeset ->
primary_key = Ash.Resource.Info.primary_key(changeset.resource)
pkey_values = changeset.data |> Map.take(primary_key) |> Map.to_list()
case changeset.api.get(
changeset.resource,
pkey_values,
tracer: context[:tracer],
tenant: context[:tenant],
authorize?: false,
lock: opts[:lock]
) do
{:ok, record} ->
%{changeset | data: record}
{:error, error} ->
Ash.Changeset.add_error(changeset, error)
end
end)
end
end