mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 21:43:02 +12:00
improvement: add on_match: :destroy
option
This commit is contained in:
parent
fed720bb59
commit
d786aadec7
3 changed files with 138 additions and 2 deletions
|
@ -228,7 +228,18 @@ defmodule Ash.Actions.ManagedRelationships do
|
||||||
end
|
end
|
||||||
|
|
||||||
_value ->
|
_value ->
|
||||||
{:cont, {changeset, instructions}}
|
if opts[:on_match] == :destroy do
|
||||||
|
changeset =
|
||||||
|
Ash.Changeset.force_change_attribute(
|
||||||
|
changeset,
|
||||||
|
relationship.source_field,
|
||||||
|
nil
|
||||||
|
)
|
||||||
|
|
||||||
|
{:cont, {changeset, instructions}}
|
||||||
|
else
|
||||||
|
{:cont, {changeset, instructions}}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
|
@ -488,7 +499,7 @@ defmodule Ash.Actions.ManagedRelationships do
|
||||||
{:cont, {:ok, new_value, all_notifications ++ notifications, all_used ++ used}}
|
{:cont, {:ok, new_value, all_notifications ++ notifications, all_used ++ used}}
|
||||||
|
|
||||||
{:error, %Ash.Error.Changes.InvalidRelationship{} = error} ->
|
{:error, %Ash.Error.Changes.InvalidRelationship{} = error} ->
|
||||||
{:error, error}
|
{:halt, {:error, error}}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
case Keyword.fetch(opts[:meta] || [], :inputs_was_list?) do
|
case Keyword.fetch(opts[:meta] || [], :inputs_was_list?) do
|
||||||
|
@ -1048,6 +1059,25 @@ defmodule Ash.Actions.ManagedRelationships do
|
||||||
:missing ->
|
:missing ->
|
||||||
{:ok, current_value, [], []}
|
{:ok, current_value, [], []}
|
||||||
|
|
||||||
|
{:destroy, action_name} ->
|
||||||
|
case destroy_data(
|
||||||
|
source_record,
|
||||||
|
match,
|
||||||
|
api,
|
||||||
|
actor,
|
||||||
|
opts,
|
||||||
|
action_name,
|
||||||
|
changeset.tenant,
|
||||||
|
relationship,
|
||||||
|
changeset
|
||||||
|
) do
|
||||||
|
{:ok, notifications} ->
|
||||||
|
{:ok, current_value, notifications, []}
|
||||||
|
|
||||||
|
{:error, error} ->
|
||||||
|
{:error, error}
|
||||||
|
end
|
||||||
|
|
||||||
{:unrelate, action_name} ->
|
{:unrelate, action_name} ->
|
||||||
case unrelate_data(
|
case unrelate_data(
|
||||||
source_record,
|
source_record,
|
||||||
|
@ -1525,4 +1555,79 @@ defmodule Ash.Actions.ManagedRelationships do
|
||||||
) do
|
) do
|
||||||
{:ok, []}
|
{:ok, []}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp destroy_data(
|
||||||
|
source_record,
|
||||||
|
record,
|
||||||
|
api,
|
||||||
|
actor,
|
||||||
|
opts,
|
||||||
|
action_name,
|
||||||
|
tenant,
|
||||||
|
%{type: :many_to_many} = relationship,
|
||||||
|
changeset
|
||||||
|
) do
|
||||||
|
action_name =
|
||||||
|
action_name || Ash.Resource.Info.primary_action(relationship.through, :destroy).name
|
||||||
|
|
||||||
|
source_value = Map.get(source_record, relationship.source_field)
|
||||||
|
destination_value = Map.get(record, relationship.destination_field)
|
||||||
|
|
||||||
|
relationship.through
|
||||||
|
|> Ash.Query.filter(ref(^relationship.source_field_on_join_table) == ^source_value)
|
||||||
|
|> Ash.Query.filter(ref(^relationship.destination_field_on_join_table) == ^destination_value)
|
||||||
|
|> Ash.Query.limit(1)
|
||||||
|
|> Ash.Query.set_tenant(tenant)
|
||||||
|
|> api.read_one(authorize?: opts[:authorize?], actor: actor)
|
||||||
|
|> case do
|
||||||
|
{:ok, result} ->
|
||||||
|
result
|
||||||
|
|> Ash.Changeset.new()
|
||||||
|
|> set_source_context({relationship, changeset})
|
||||||
|
|> Ash.Changeset.for_destroy(action_name, %{}, actor: actor)
|
||||||
|
|> Ash.Changeset.set_context(relationship.context)
|
||||||
|
|> Ash.Changeset.set_tenant(tenant)
|
||||||
|
|> api.destroy(
|
||||||
|
return_notifications?: true,
|
||||||
|
authorize?: opts[:authorize?],
|
||||||
|
actor: actor
|
||||||
|
)
|
||||||
|
|> case do
|
||||||
|
{:ok, notifications} ->
|
||||||
|
{:ok, notifications}
|
||||||
|
|
||||||
|
{:error, error} ->
|
||||||
|
{:error, error}
|
||||||
|
end
|
||||||
|
|
||||||
|
{:error, error} ->
|
||||||
|
{:error, error}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp destroy_data(
|
||||||
|
_source_record,
|
||||||
|
record,
|
||||||
|
api,
|
||||||
|
actor,
|
||||||
|
opts,
|
||||||
|
action_name,
|
||||||
|
tenant,
|
||||||
|
relationship,
|
||||||
|
changeset
|
||||||
|
) do
|
||||||
|
action_name =
|
||||||
|
action_name || Ash.Resource.Info.primary_action(relationship.destination, :update).name
|
||||||
|
|
||||||
|
record
|
||||||
|
|> Ash.Changeset.new()
|
||||||
|
|> set_source_context({relationship, changeset})
|
||||||
|
|> Ash.Changeset.for_destroy(action_name, %{},
|
||||||
|
relationships: opts[:relationships] || [],
|
||||||
|
actor: actor
|
||||||
|
)
|
||||||
|
|> Ash.Changeset.set_context(relationship.context)
|
||||||
|
|> Ash.Changeset.set_tenant(tenant)
|
||||||
|
|> api.destroy(return_notifications?: true, actor: actor, authorize?: opts[:authorize?])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1263,6 +1263,11 @@ defmodule Ash.Changeset do
|
||||||
* `{:update, :action_name}` - the record is updated using the specified action on the destination resource
|
* `{:update, :action_name}` - the record is updated using the specified action on the destination resource
|
||||||
* `{:update, :action_name, :join_table_action_name, [:list, :of, :params]}` - Same as `{:update, :action_name}` but takes
|
* `{:update, :action_name, :join_table_action_name, [:list, :of, :params]}` - Same as `{:update, :action_name}` but takes
|
||||||
the list of params specified out and applies them as an update to the join table row (only valid for many to many).
|
the list of params specified out and applies them as an update to the join table row (only valid for many to many).
|
||||||
|
* `{:destroy, :action_name}` - the record is destroyed using the specified action on the destination resource. The action should be:
|
||||||
|
* many_to_many - a destroy action on the join table
|
||||||
|
* has_many - a destroy action on the destination resource
|
||||||
|
* has_one - a destroy action on the destination resource
|
||||||
|
* belongs_to - a destroy action on the destination resource
|
||||||
* `:error` - an eror is returned indicating that a record would have been updated
|
* `:error` - an eror is returned indicating that a record would have been updated
|
||||||
* `:no_match` - ignores the primary key match and follows the on_no_match instructions with these records instead.
|
* `:no_match` - ignores the primary key match and follows the on_no_match instructions with these records instead.
|
||||||
* `:unrelate` - the related item is not destroyed, but the data is "unrelated", making this behave like `remove_from_relationship/3`. The action should be:
|
* `:unrelate` - the related item is not destroyed, but the data is "unrelated", making this behave like `remove_from_relationship/3`. The action should be:
|
||||||
|
|
|
@ -80,6 +80,14 @@ defmodule Ash.Changeset.ManagedRelationshipHelpers do
|
||||||
:unrelate ->
|
:unrelate ->
|
||||||
{:unrelate, nil}
|
{:unrelate, nil}
|
||||||
|
|
||||||
|
:destroy when relationship.type == :many_to_many ->
|
||||||
|
action = Ash.Resource.Info.primary_action!(relationship.through, :destroy)
|
||||||
|
{:destroy, action.name}
|
||||||
|
|
||||||
|
:destroy ->
|
||||||
|
action = Ash.Resource.Info.primary_action!(relationship.destination, :destroy)
|
||||||
|
{:destroy, action.name}
|
||||||
|
|
||||||
other ->
|
other ->
|
||||||
other
|
other
|
||||||
end)
|
end)
|
||||||
|
@ -135,6 +143,24 @@ defmodule Ash.Changeset.ManagedRelationshipHelpers do
|
||||||
opts[:on_match] == :missing ->
|
opts[:on_match] == :missing ->
|
||||||
on_missing_destination_actions(opts, relationship)
|
on_missing_destination_actions(opts, relationship)
|
||||||
|
|
||||||
|
unwrap(opts[:on_match]) == :destroy && relationship.type == :many_to_many ->
|
||||||
|
case opts[:on_match] do
|
||||||
|
:destroy ->
|
||||||
|
all(join(primary_action_name(relationship.through, :destroy), :all))
|
||||||
|
|
||||||
|
{:destroy, action_name} ->
|
||||||
|
all(join(action_name, :all))
|
||||||
|
end
|
||||||
|
|
||||||
|
unwrap(opts[:on_match]) == :destroy ->
|
||||||
|
case opts[:on_match] do
|
||||||
|
:destroy ->
|
||||||
|
all(destination(primary_action_name(relationship.destination, :destroy)))
|
||||||
|
|
||||||
|
{:destroy, action_name} ->
|
||||||
|
all(destination(action_name))
|
||||||
|
end
|
||||||
|
|
||||||
unwrap(opts[:on_match]) == :update ->
|
unwrap(opts[:on_match]) == :update ->
|
||||||
case opts[:on_match] do
|
case opts[:on_match] do
|
||||||
:update ->
|
:update ->
|
||||||
|
|
Loading…
Reference in a new issue