mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 13:33:20 +12:00
improvement: support :no_rollback
and return_query/2
callback
This commit is contained in:
parent
b600b23803
commit
44761e7e3f
11 changed files with 69 additions and 25 deletions
|
@ -903,7 +903,7 @@ defmodule Ash.Actions.Create.Bulk do
|
||||||
must_return_records_for_changes?,
|
must_return_records_for_changes?,
|
||||||
tenant: opts[:tenant]
|
tenant: opts[:tenant]
|
||||||
})
|
})
|
||||||
|> Ash.Actions.Helpers.rollback_if_in_transaction(nil)
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(resource, nil)
|
||||||
|> Enum.flat_map(fn
|
|> Enum.flat_map(fn
|
||||||
{:ok, result} ->
|
{:ok, result} ->
|
||||||
[result]
|
[result]
|
||||||
|
@ -927,7 +927,7 @@ defmodule Ash.Actions.Create.Bulk do
|
||||||
tracer: opts[:tracer],
|
tracer: opts[:tracer],
|
||||||
api: api
|
api: api
|
||||||
})
|
})
|
||||||
|> Ash.Actions.Helpers.rollback_if_in_transaction(nil)
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(resource, nil)
|
||||||
|
|
||||||
case result do
|
case result do
|
||||||
{:ok, result} ->
|
{:ok, result} ->
|
||||||
|
@ -965,7 +965,7 @@ defmodule Ash.Actions.Create.Bulk do
|
||||||
tenant: opts[:tenant]
|
tenant: opts[:tenant]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|> Ash.Actions.Helpers.rollback_if_in_transaction(nil)
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(resource, nil)
|
||||||
else
|
else
|
||||||
[changeset] = batch
|
[changeset] = batch
|
||||||
upsert? = opts[:upsert?] || action.upsert? || false
|
upsert? = opts[:upsert?] || action.upsert? || false
|
||||||
|
|
|
@ -337,7 +337,10 @@ defmodule Ash.Actions.Create do
|
||||||
opts[:upsert?] ->
|
opts[:upsert?] ->
|
||||||
changeset.resource
|
changeset.resource
|
||||||
|> Ash.DataLayer.upsert(changeset, upsert_keys)
|
|> Ash.DataLayer.upsert(changeset, upsert_keys)
|
||||||
|> Ash.Actions.Helpers.rollback_if_in_transaction(changeset)
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(
|
||||||
|
changeset.resource,
|
||||||
|
changeset
|
||||||
|
)
|
||||||
|> add_tenant(changeset)
|
|> add_tenant(changeset)
|
||||||
|> manage_relationships(api, changeset,
|
|> manage_relationships(api, changeset,
|
||||||
actor: opts[:actor],
|
actor: opts[:actor],
|
||||||
|
@ -348,7 +351,10 @@ defmodule Ash.Actions.Create do
|
||||||
true ->
|
true ->
|
||||||
changeset.resource
|
changeset.resource
|
||||||
|> Ash.DataLayer.create(changeset)
|
|> Ash.DataLayer.create(changeset)
|
||||||
|> Ash.Actions.Helpers.rollback_if_in_transaction(changeset)
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(
|
||||||
|
changeset.resource,
|
||||||
|
changeset
|
||||||
|
)
|
||||||
|> add_tenant(changeset)
|
|> add_tenant(changeset)
|
||||||
|> manage_relationships(api, changeset,
|
|> manage_relationships(api, changeset,
|
||||||
actor: opts[:actor],
|
actor: opts[:actor],
|
||||||
|
|
|
@ -182,7 +182,7 @@ defmodule Ash.Actions.Destroy do
|
||||||
else
|
else
|
||||||
changeset.resource
|
changeset.resource
|
||||||
|> Ash.DataLayer.destroy(changeset)
|
|> Ash.DataLayer.destroy(changeset)
|
||||||
|> Ash.Actions.Helpers.rollback_if_in_transaction(changeset)
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(changeset.resource, changeset)
|
||||||
|> case do
|
|> case do
|
||||||
:ok ->
|
:ok ->
|
||||||
{:ok, data} = Ash.Changeset.apply_attributes(changeset, force?: true)
|
{:ok, data} = Ash.Changeset.apply_attributes(changeset, force?: true)
|
||||||
|
|
|
@ -3,23 +3,28 @@ defmodule Ash.Actions.Helpers do
|
||||||
require Logger
|
require Logger
|
||||||
require Ash.Flags
|
require Ash.Flags
|
||||||
|
|
||||||
def rollback_if_in_transaction({:error, error}, changeset) do
|
def rollback_if_in_transaction({:error, error}, resource, changeset) do
|
||||||
if Ash.DataLayer.in_transaction?(changeset.resource) do
|
if Ash.DataLayer.in_transaction?(resource) do
|
||||||
if changeset do
|
case changeset do
|
||||||
Ash.DataLayer.rollback(changeset.resource, Ash.Changeset.add_error(changeset, error))
|
%Ash.Changeset{} = changeset ->
|
||||||
else
|
Ash.DataLayer.rollback(resource, Ash.Changeset.add_error(changeset, error))
|
||||||
Ash.DataLayer.rollback(changeset.resource, Ash.Error.to_error_class(error))
|
|
||||||
|
%Ash.Query{} = query ->
|
||||||
|
Ash.DataLayer.rollback(resource, Ash.Query.add_error(query, error))
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
Ash.DataLayer.rollback(resource, Ash.Error.to_error_class(error))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
{:error, error}
|
{:error, error}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def rollback_if_in_transaction({:error, :no_rollback, error}, _changeset) do
|
def rollback_if_in_transaction({:error, :no_rollback, error}, _, _changeset) do
|
||||||
{:error, error}
|
{:error, error}
|
||||||
end
|
end
|
||||||
|
|
||||||
def rollback_if_in_transaction(success, _), do: success
|
def rollback_if_in_transaction(success, _, _), do: success
|
||||||
|
|
||||||
def validate_calculation_load!(%{__struct__: Ash.Query}, module) do
|
def validate_calculation_load!(%{__struct__: Ash.Query}, module) do
|
||||||
raise """
|
raise """
|
||||||
|
|
|
@ -1405,7 +1405,10 @@ defmodule Ash.Actions.Read do
|
||||||
])
|
])
|
||||||
|> Map.put(:context, ash_query.context)
|
|> Map.put(:context, ash_query.context)
|
||||||
|> Ash.Query.set_context(%{action: ash_query.action})
|
|> Ash.Query.set_context(%{action: ash_query.action})
|
||||||
|> Ash.Query.data_layer_query(only_validate_filter?: true),
|
|> Ash.Query.data_layer_query(
|
||||||
|
only_validate_filter?: true,
|
||||||
|
run_return_query?: false
|
||||||
|
),
|
||||||
{:ok, filter} <-
|
{:ok, filter} <-
|
||||||
filter_with_related(
|
filter_with_related(
|
||||||
Enum.map(filter_requests, & &1.path),
|
Enum.map(filter_requests, & &1.path),
|
||||||
|
@ -1450,7 +1453,11 @@ defmodule Ash.Actions.Read do
|
||||||
ash_query.resource
|
ash_query.resource
|
||||||
),
|
),
|
||||||
{:ok, query} <-
|
{:ok, query} <-
|
||||||
Ash.DataLayer.sort(query, ash_query.sort, ash_query.resource),
|
Ash.DataLayer.sort(
|
||||||
|
query,
|
||||||
|
ash_query.sort,
|
||||||
|
ash_query.resource
|
||||||
|
),
|
||||||
{:ok, query} <-
|
{:ok, query} <-
|
||||||
Ash.DataLayer.distinct_sort(query, ash_query.distinct_sort, ash_query.resource),
|
Ash.DataLayer.distinct_sort(query, ash_query.distinct_sort, ash_query.resource),
|
||||||
{:ok, query} <-
|
{:ok, query} <-
|
||||||
|
@ -2947,6 +2954,7 @@ defmodule Ash.Actions.Read do
|
||||||
else
|
else
|
||||||
query
|
query
|
||||||
|> Ash.DataLayer.run_query(resource)
|
|> Ash.DataLayer.run_query(resource)
|
||||||
|
|> Helpers.rollback_if_in_transaction(ash_query.resource, ash_query)
|
||||||
|> Helpers.select(ash_query)
|
|> Helpers.select(ash_query)
|
||||||
|> Helpers.load_runtime_types(ash_query, load_attributes?)
|
|> Helpers.load_runtime_types(ash_query, load_attributes?)
|
||||||
end
|
end
|
||||||
|
|
|
@ -272,7 +272,10 @@ defmodule Ash.Actions.Update do
|
||||||
|
|
||||||
changeset.resource
|
changeset.resource
|
||||||
|> Ash.DataLayer.update(changeset)
|
|> Ash.DataLayer.update(changeset)
|
||||||
|> Ash.Actions.Helpers.rollback_if_in_transaction(changeset)
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(
|
||||||
|
changeset.resource,
|
||||||
|
changeset
|
||||||
|
)
|
||||||
|> add_tenant(changeset)
|
|> add_tenant(changeset)
|
||||||
|> manage_relationships(api, changeset,
|
|> manage_relationships(api, changeset,
|
||||||
actor: opts[:actor],
|
actor: opts[:actor],
|
||||||
|
|
|
@ -1030,7 +1030,10 @@ defmodule Ash.Api do
|
||||||
|> Ash.Query.data_layer_query()
|
|> Ash.Query.data_layer_query()
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, data_layer_query} ->
|
{:ok, data_layer_query} ->
|
||||||
case Ash.DataLayer.run_query(data_layer_query, query.resource) do
|
data_layer_query
|
||||||
|
|> Ash.DataLayer.run_query(query.resource)
|
||||||
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(query.resource, query)
|
||||||
|
|> case do
|
||||||
{:ok, results} ->
|
{:ok, results} ->
|
||||||
if Enum.count(results) == Enum.count(data) do
|
if Enum.count(results) == Enum.count(data) do
|
||||||
{:ok, true}
|
{:ok, true}
|
||||||
|
@ -1065,7 +1068,10 @@ defmodule Ash.Api do
|
||||||
|> Ash.Query.data_layer_query()
|
|> Ash.Query.data_layer_query()
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, data_layer_query} ->
|
{:ok, data_layer_query} ->
|
||||||
case Ash.DataLayer.run_query(data_layer_query, resource) do
|
data_layer_query
|
||||||
|
|> Ash.DataLayer.run_query(resource)
|
||||||
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(query.resource, query)
|
||||||
|
|> case do
|
||||||
{:ok, [_]} ->
|
{:ok, [_]} ->
|
||||||
{:ok, true}
|
{:ok, true}
|
||||||
|
|
||||||
|
|
|
@ -378,13 +378,13 @@ defmodule Ash.DataLayer do
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec update(Ash.Resource.t(), Ash.Changeset.t()) ::
|
@spec update(Ash.Resource.t(), Ash.Changeset.t()) ::
|
||||||
{:ok, Ash.Resource.record()} | {:error, term}
|
{:ok, Ash.Resource.record()} | {:error, term} | {:error, :no_rollback, term}
|
||||||
def update(resource, changeset) do
|
def update(resource, changeset) do
|
||||||
Ash.DataLayer.data_layer(resource).update(resource, changeset)
|
Ash.DataLayer.data_layer(resource).update(resource, changeset)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec create(Ash.Resource.t(), Ash.Changeset.t()) ::
|
@spec create(Ash.Resource.t(), Ash.Changeset.t()) ::
|
||||||
{:ok, Ash.Resource.record()} | {:error, term}
|
{:ok, Ash.Resource.record()} | {:error, term} | {:error, :no_rollback, term}
|
||||||
def create(resource, changeset) do
|
def create(resource, changeset) do
|
||||||
Ash.DataLayer.data_layer(resource).create(resource, changeset)
|
Ash.DataLayer.data_layer(resource).create(resource, changeset)
|
||||||
end
|
end
|
||||||
|
@ -409,11 +409,13 @@ defmodule Ash.DataLayer do
|
||||||
:ok
|
:ok
|
||||||
| {:ok, Enumerable.t(Ash.Resource.record())}
|
| {:ok, Enumerable.t(Ash.Resource.record())}
|
||||||
| {:error, Ash.Error.t()}
|
| {:error, Ash.Error.t()}
|
||||||
|
| {:error, :no_rollback, Ash.Error.t()}
|
||||||
def bulk_create(resource, changesets, options) do
|
def bulk_create(resource, changesets, options) do
|
||||||
Ash.DataLayer.data_layer(resource).bulk_create(resource, changesets, options)
|
Ash.DataLayer.data_layer(resource).bulk_create(resource, changesets, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec destroy(Ash.Resource.t(), Ash.Changeset.t()) :: :ok | {:error, term}
|
@spec destroy(Ash.Resource.t(), Ash.Changeset.t()) ::
|
||||||
|
:ok | {:error, term} | {:error, :no_rollback, term}
|
||||||
def destroy(resource, changeset) do
|
def destroy(resource, changeset) do
|
||||||
Ash.DataLayer.data_layer(resource).destroy(resource, changeset)
|
Ash.DataLayer.data_layer(resource).destroy(resource, changeset)
|
||||||
end
|
end
|
||||||
|
@ -615,7 +617,7 @@ defmodule Ash.DataLayer do
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec run_query(data_layer_query(), central_resource :: Ash.Resource.t()) ::
|
@spec run_query(data_layer_query(), central_resource :: Ash.Resource.t()) ::
|
||||||
{:ok, list(Ash.Resource.record())} | {:error, term}
|
{:ok, list(Ash.Resource.record())} | {:error, term} | {:error, :no_rollback, term}
|
||||||
def run_query(query, central_resource) do
|
def run_query(query, central_resource) do
|
||||||
Ash.DataLayer.data_layer(central_resource).run_query(query, central_resource)
|
Ash.DataLayer.data_layer(central_resource).run_query(query, central_resource)
|
||||||
end
|
end
|
||||||
|
|
|
@ -919,6 +919,7 @@ defmodule Ash.Engine.Request do
|
||||||
{:ok, data_layer_query} ->
|
{:ok, data_layer_query} ->
|
||||||
data_layer_query
|
data_layer_query
|
||||||
|> Ash.DataLayer.run_query(request.resource)
|
|> Ash.DataLayer.run_query(request.resource)
|
||||||
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(request.resource, new_query)
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, results} ->
|
{:ok, results} ->
|
||||||
pkey = Ash.Resource.Info.primary_key(request.resource)
|
pkey = Ash.Resource.Info.primary_key(request.resource)
|
||||||
|
@ -971,6 +972,10 @@ defmodule Ash.Engine.Request do
|
||||||
{:ok, data_layer_query} ->
|
{:ok, data_layer_query} ->
|
||||||
data_layer_query
|
data_layer_query
|
||||||
|> Ash.DataLayer.run_query(request.resource)
|
|> Ash.DataLayer.run_query(request.resource)
|
||||||
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(
|
||||||
|
request.resource,
|
||||||
|
query_with_pkey_filter
|
||||||
|
)
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, []} ->
|
{:ok, []} ->
|
||||||
{:error,
|
{:error,
|
||||||
|
|
|
@ -588,7 +588,8 @@ defmodule Ash.Query.Aggregate do
|
||||||
Ash.DataLayer.run_query(
|
Ash.DataLayer.run_query(
|
||||||
data_layer_query,
|
data_layer_query,
|
||||||
query.resource
|
query.resource
|
||||||
) do
|
)
|
||||||
|
|> Ash.Actions.Helpers.rollback_if_in_transaction(query.resource, query) do
|
||||||
loaded_aggregates =
|
loaded_aggregates =
|
||||||
aggregates
|
aggregates
|
||||||
|> Enum.map(& &1.load)
|
|> Enum.map(& &1.load)
|
||||||
|
|
|
@ -2627,7 +2627,7 @@ defmodule Ash.Query do
|
||||||
{:ok, query} <-
|
{:ok, query} <-
|
||||||
Ash.DataLayer.offset(query, ash_query.offset, resource),
|
Ash.DataLayer.offset(query, ash_query.offset, resource),
|
||||||
{:ok, query} <- Ash.DataLayer.lock(query, ash_query.lock, resource),
|
{:ok, query} <- Ash.DataLayer.lock(query, ash_query.lock, resource),
|
||||||
{:ok, query} <- Ash.DataLayer.return_query(query, resource) do
|
{:ok, query} <- maybe_return_query(query, resource, opts) do
|
||||||
if opts[:no_modify?] || !ash_query.action || !ash_query.action.modify_query do
|
if opts[:no_modify?] || !ash_query.action || !ash_query.action.modify_query do
|
||||||
{:ok, query}
|
{:ok, query}
|
||||||
else
|
else
|
||||||
|
@ -2644,6 +2644,14 @@ defmodule Ash.Query do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp maybe_return_query(query, resource, opts) do
|
||||||
|
if Keyword.get(opts, :run_return_query?, true) do
|
||||||
|
Ash.DataLayer.return_query(query, resource)
|
||||||
|
else
|
||||||
|
{:ok, query}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp add_tenant(query, ash_query) do
|
defp add_tenant(query, ash_query) do
|
||||||
with :context <- Ash.Resource.Info.multitenancy_strategy(ash_query.resource),
|
with :context <- Ash.Resource.Info.multitenancy_strategy(ash_query.resource),
|
||||||
tenant when not is_nil(tenant) <- ash_query.tenant,
|
tenant when not is_nil(tenant) <- ash_query.tenant,
|
||||||
|
|
Loading…
Reference in a new issue