fix: properly leverage atomic upgrade read action for an update action

This commit is contained in:
Zach Daniel 2024-09-05 15:04:38 -04:00
parent de35b8049a
commit ec12332e95
3 changed files with 27 additions and 7 deletions

View file

@ -1512,7 +1512,7 @@ update :flag_for_review, primary?: true
| [`manual`](#actions-update-manual){: #actions-update-manual } | `(any, any -> any) \| module` | | Override the update behavior. Accepts a module or module and opts, or a function that takes the changeset and context. See the [manual actions guide](/documentation/topics/manual-actions.md) for more. |
| [`require_atomic?`](#actions-update-require_atomic?){: #actions-update-require_atomic? } | `boolean` | `true` | Require that the update be atomic. This means that all changes and validations implement the `atomic` callback. See the guide on atomic updates for more. |
| [`atomic_upgrade?`](#actions-update-atomic_upgrade?){: #actions-update-atomic_upgrade? } | `boolean` | `false` | If set to `true`, atomic upgrades will be performed. Ignored if `required_atomic?` is `true`. See the update actions guide for more. |
| [`atomic_upgrade_with`](#actions-update-atomic_upgrade_with){: #actions-update-atomic_upgrade_with } | `:atom \| nil` | | Configure the read action used when performing atomic upgrades. Defaults to the primary read action. |
| [`atomic_upgrade_with`](#actions-update-atomic_upgrade_with){: #actions-update-atomic_upgrade_with } | `atom \| nil` | | Configure the read action used when performing atomic upgrades. Defaults to the primary read action. |
| [`primary?`](#actions-update-primary?){: #actions-update-primary? } | `boolean` | `false` | Whether or not this action should be used when no action is specified by the caller. |
| [`description`](#actions-update-description){: #actions-update-description } | `String.t` | | An optional description for the action |
| [`transaction?`](#actions-update-transaction?){: #actions-update-transaction? } | `boolean` | | Whether or not the action should be run in transactions. Reads default to false, while create/update/destroy actions default to `true`. |
@ -1755,7 +1755,7 @@ end
| [`manual`](#actions-destroy-manual){: #actions-destroy-manual } | `(any, any -> any) \| module` | | Override the update behavior. Accepts a module or module and opts, or a function that takes the changeset and context. See the [manual actions guide](/documentation/topics/manual-actions.md) for more. |
| [`require_atomic?`](#actions-destroy-require_atomic?){: #actions-destroy-require_atomic? } | `boolean` | `true` | Require that the update be atomic. Only relevant if `soft?` is set to `true`. This means that all changes and validations implement the `atomic` callback. See the guide on atomic updates for more. |
| [`atomic_upgrade?`](#actions-destroy-atomic_upgrade?){: #actions-destroy-atomic_upgrade? } | `boolean` | `false` | If set to `true`, atomic upgrades will be performed. See the update actions guide for more. |
| [`atomic_upgrade_with`](#actions-destroy-atomic_upgrade_with){: #actions-destroy-atomic_upgrade_with } | `:atom \| nil` | | Configure the read action used when performing atomic upgrades. Defaults to the primary read action. |
| [`atomic_upgrade_with`](#actions-destroy-atomic_upgrade_with){: #actions-destroy-atomic_upgrade_with } | `atom \| nil` | | Configure the read action used when performing atomic upgrades. Defaults to the primary read action. |
| [`primary?`](#actions-destroy-primary?){: #actions-destroy-primary? } | `boolean` | `false` | Whether or not this action should be used when no action is specified by the caller. |
| [`description`](#actions-destroy-description){: #actions-destroy-description } | `String.t` | | An optional description for the action |
| [`transaction?`](#actions-destroy-transaction?){: #actions-destroy-transaction? } | `boolean` | | Whether or not the action should be run in transactions. Reads default to false, while create/update/destroy actions default to `true`. |

View file

@ -29,7 +29,7 @@ defmodule Ash.Actions.Update.Bulk do
query =
Ash.Query.for_read(
query,
get_read_action(query.resource, opts).name,
get_read_action(query.resource, action, opts).name,
%{},
actor: opts[:actor],
tenant: opts[:tenant]
@ -928,7 +928,7 @@ defmodule Ash.Actions.Update.Bulk do
defp do_run(domain, stream, action, input, opts, metadata_key, context_key, not_atomic_reason) do
resource = opts[:resource]
opts = Ash.Actions.Helpers.set_opts(opts, domain)
read_action = get_read_action(resource, opts)
read_action = get_read_action(resource, action, opts)
{context_cs, opts} =
Ash.Actions.Helpers.set_context_and_get_opts(domain, Ash.Changeset.new(resource), opts)
@ -1053,7 +1053,7 @@ defmodule Ash.Actions.Update.Bulk do
fn batch ->
pkeys = [or: Enum.map(batch, &Map.take(&1, pkey))]
read_action = get_read_action(resource, opts).name
read_action = get_read_action(resource, action, opts).name
resource
|> Ash.Query.for_read(read_action, %{},
@ -2918,10 +2918,29 @@ defmodule Ash.Actions.Update.Bulk do
)
end
defp get_read_action(resource, opts) do
defp get_read_action(resource, action, opts) do
case opts[:read_action] do
nil ->
Ash.Resource.Info.primary_action!(resource, :read)
case action do
%{atomic_upgrade_with: read_action} when not is_nil(read_action) ->
Ash.Resource.Info.action(resource, read_action) ||
raise "No such read action in #{inspect(resource)}.#{action.name}.atomic_upgrade_with: #{read_action}"
action when is_atom(action) and not is_nil(action) ->
action =
Ash.Resource.Info.action(resource, action) ||
raise "No such destroy action #{inspect(resource)}.#{action}"
if read_action = action.atomic_upgrade_with do
Ash.Resource.Info.action(resource, read_action) ||
raise "No such read action in #{inspect(resource)}.#{action.name}.atomic_upgrade_with: #{read_action}"
else
Ash.Resource.Info.primary_action!(resource, :read)
end
_ ->
Ash.Resource.Info.primary_action!(resource, :read)
end
action ->
Ash.Resource.Info.action(resource, action)

View file

@ -162,6 +162,7 @@ defmodule Ash.Actions.Update do
Keyword.merge(opts,
strategy: [:atomic, :stream],
resource: atomic_changeset.resource,
read_action: atomic_upgrade_read.name,
authorize_query?: false,
return_records?: true,
atomic_changeset: atomic_changeset,