fix: properly rollback transactions on returned errors in generic actions

This commit is contained in:
Zach Daniel 2023-10-06 13:39:05 -04:00
parent b8be1123ba
commit 49042b737d
2 changed files with 23 additions and 11 deletions

View file

@ -57,8 +57,9 @@ defmodule Ash.Actions.Action do
end
try do
resources = Enum.reject(resources, &Ash.DataLayer.in_transaction?/1)
resources
|> Enum.reject(&Ash.DataLayer.in_transaction?/1)
|> Ash.DataLayer.transaction(
fn ->
case authorize(api, opts[:actor], input) do
@ -67,12 +68,15 @@ defmodule Ash.Actions.Action do
{:ok, result} ->
{:ok, result, []}
{:error, error} ->
Ash.DataLayer.rollback(resources, error)
other ->
other
raise_invalid_manual_action_return!(input, other)
end
{:error, error} ->
{:error, error}
Ash.DataLayer.rollback(resources, error)
end
end,
nil,
@ -135,13 +139,7 @@ defmodule Ash.Actions.Action do
{:error, error}
other ->
raise """
Invalid return from generic action #{input.resource}.#{input.action.name}.
Expected {:ok, result} or {:error, error}, got:
#{inspect(other)}
"""
raise_invalid_manual_action_return!(input, other)
end
{:error, error} ->
@ -152,6 +150,16 @@ defmodule Ash.Actions.Action do
end
end
defp raise_invalid_manual_action_return!(input, other) do
raise """
Invalid return from generic action #{input.resource}.#{input.action.name}.
Expected {:ok, result} or {:error, error}, got:
#{inspect(other)}
"""
end
defp authorize(api, actor, input) do
input.resource
|> Ash.Resource.Info.authorizers()

View file

@ -350,7 +350,11 @@ defmodule Ash.DataLayer do
end
@doc "Rolls back the current transaction"
@spec rollback(Ash.Resource.t(), term) :: no_return
@spec rollback(Ash.Resource.t() | list(Ash.Resource.t()), term) :: no_return
def rollback([resource | _], term) do
rollback(resource, term)
end
def rollback(resource, term) do
data_layer(resource).rollback(resource, term)
end