improvement: handle the case where managed relationship input is an embed

This commit is contained in:
Zach Daniel 2022-08-22 19:48:22 -04:00
parent a18f91bd59
commit 80833c3f58
2 changed files with 52 additions and 21 deletions

View file

@ -166,7 +166,7 @@ defmodule Ash.Actions.ManagedRelationships do
) )
{_key, _create_or_update, read} -> {_key, _create_or_update, read} ->
if is_struct(input) do if is_struct(input, relationship.destination) do
changeset = changeset =
changeset changeset
|> Ash.Changeset.set_context(%{ |> Ash.Changeset.set_context(%{
@ -839,7 +839,7 @@ defmodule Ash.Actions.ManagedRelationships do
case Ash.Filter.get_filter(relationship.destination, input) do case Ash.Filter.get_filter(relationship.destination, input) do
{:ok, keys} -> {:ok, keys} ->
if is_struct(input) do if is_struct(input, relationship.destination) do
{:ok, input} {:ok, input}
else else
relationship.destination relationship.destination
@ -986,10 +986,15 @@ defmodule Ash.Actions.ManagedRelationships do
type when type in [:has_many, :has_one] -> type when type in [:has_many, :has_one] ->
{found, input} = {found, input} =
if is_struct(input) do cond do
{input, %{}} is_struct(input, relationship.destination) ->
else {input, %{}}
{found, input}
is_struct(input) ->
{found, Map.from_struct(input)}
true ->
{found, input}
end end
found found
@ -1041,9 +1046,16 @@ defmodule Ash.Actions.ManagedRelationships do
case changeset.context[:private][:belongs_to_manage_created][relationship.name][index] do case changeset.context[:private][:belongs_to_manage_created][relationship.name][index] do
nil -> nil ->
created = created =
if is_struct(input) do if is_struct(input, relationship.destination) do
{:ok, input, []} {:ok, input, []}
else else
input =
if is_struct(input) do
Map.from_struct(input)
else
input
end
relationship.destination relationship.destination
|> Ash.Changeset.new() |> Ash.Changeset.new()
|> Ash.Changeset.for_create(action_name, input, |> Ash.Changeset.for_create(action_name, input,
@ -1078,16 +1090,21 @@ defmodule Ash.Actions.ManagedRelationships do
join_keys = params ++ Enum.map(params, &to_string/1) join_keys = params ++ Enum.map(params, &to_string/1)
input = input =
if is_map(input) do cond do
input is_struct(input, relationship.destination) ->
else input
Enum.into(input, %{})
is_struct(input) ->
Map.from_struct(input)
true ->
input
end end
{join_params, regular_params} = split_join_keys(input, join_keys) {join_params, regular_params} = split_join_keys(input, join_keys)
created = created =
if is_struct(input) do if is_struct(input, relationship.destination) do
{:ok, input, [], [input]} {:ok, input, [], [input]}
else else
relationship.destination relationship.destination
@ -1213,10 +1230,15 @@ defmodule Ash.Actions.ManagedRelationships do
{:update, action_name} -> {:update, action_name} ->
{match, input} = {match, input} =
if is_struct(input) do cond do
{input, %{}} is_struct(input, relationship.destination) ->
else {input, %{}}
{match, input}
is_struct(input) ->
Map.from_struct(input)
true ->
{match, input}
end end
match match
@ -1242,10 +1264,15 @@ defmodule Ash.Actions.ManagedRelationships do
{join_params, regular_params} = split_join_keys(input, join_keys) {join_params, regular_params} = split_join_keys(input, join_keys)
{match, regular_params} = {match, regular_params} =
if is_struct(regular_params) do cond do
{regular_params, %{}} is_struct(regular_params, relationship.destination) ->
else {regular_params, %{}}
{match, regular_params}
is_struct(regular_params) ->
Map.from_struct(regular_params)
true ->
{match, regular_params}
end end
source_value = Map.get(source_record, relationship.source_field) source_value = Map.get(source_record, relationship.source_field)

View file

@ -14,4 +14,8 @@ end
### Primary Actions ### Primary Actions
Primary actions have been simplified for 2.0.0. If there was a single action of a given type before, it would have been marked as `primary?` automatically. Now, `primary?` actions are fully optional, although you may still want to configure them. Certain things like [managing relationships](managing_relationships.md) can be much simpler when paired with primary actions. For a fully explicit experience everywhere, however, you may want to skip primary actions altogether. To make sure your application behaves the same, go to each of your resources and check to see if they only have one action of each type. If they do, mark that single action as `primary?`. Additionally, the `primary_actions?` option has been removed now that all primary actions are explicit. Primary actions have been simplified for 2.0.0. If there was a single action of a given type before, it would have been marked as `primary?` automatically. Now, `primary?` actions are fully optional, although you may still want to configure them. Certain things like [managing relationships](managing_relationships.md) can be much simpler when paired with primary actions. For a fully explicit experience everywhere, however, you may want to skip primary actions altogether. To make sure your application behaves the same, go to each of your resources and check to see if they only have one action of each type. If they do, mark that single action as `primary?`. Additionally, the `primary_actions?` option has been removed now that all primary actions are explicit.
### Ash.Error.Query.NotFound
We used to return/raise this error directly when something wasn't found, but it was the only place in the framework not using an Error Class. So if you had anything matching on `%Ash.Error.Query.NotFound{}` it should instead now match on `%Ash.Error.Invalid{errors: [%Ash.Error.Query.NotFound{}]}`.