mirror of
https://github.com/ash-project/ash_phoenix.git
synced 2024-09-20 07:12:49 +12:00
improvement: many fixes around relationship forms
This commit is contained in:
parent
e726fb2ee8
commit
162383c750
3 changed files with 156 additions and 56 deletions
|
@ -241,22 +241,15 @@ defmodule AshPhoenix do
|
|||
[^outer_form_name, key | path] = decode_path(path)
|
||||
|
||||
{argument, argument_manages} =
|
||||
if changeset.action do
|
||||
{nil, nil}
|
||||
with action when not is_nil(action) <- changeset.action,
|
||||
argument when not is_nil(argument) <-
|
||||
Enum.find(changeset.action.arguments, &(to_string(&1.name) == key)),
|
||||
manage_change when not is_nil(manage_change) <-
|
||||
find_manage_change(argument, changeset.action) do
|
||||
{argument, manage_change}
|
||||
else
|
||||
# This is some magic to avoid having to pass in the relationship name
|
||||
# when we can figure it out from the action
|
||||
argument =
|
||||
changeset.action.arguments
|
||||
|> Enum.find(&(to_string(&1.name) == key))
|
||||
|
||||
if argument do
|
||||
manage_change = find_manage_change(argument, changeset.action)
|
||||
|
||||
if manage_change do
|
||||
{argument, manage_change}
|
||||
end
|
||||
end
|
||||
_ ->
|
||||
{nil, nil}
|
||||
end
|
||||
|
||||
changeset.resource
|
||||
|
@ -350,22 +343,15 @@ defmodule AshPhoenix do
|
|||
[^outer_form_name, key | path] = decode_path(path)
|
||||
|
||||
{argument, argument_manages} =
|
||||
if changeset.action do
|
||||
{nil, nil}
|
||||
with action when not is_nil(action) <- changeset.action,
|
||||
argument when not is_nil(argument) <-
|
||||
Enum.find(changeset.action.arguments, &(to_string(&1.name) == key)),
|
||||
manage_change when not is_nil(manage_change) <-
|
||||
find_manage_change(argument, changeset.action) do
|
||||
{argument, manage_change}
|
||||
else
|
||||
# This is some magic to avoid having to pass in the relationship name
|
||||
# when we can figure it out from the action
|
||||
argument =
|
||||
changeset.action.arguments
|
||||
|> Enum.find(&(to_string(&1.name) == key))
|
||||
|
||||
if argument do
|
||||
manage_change = find_manage_change(argument, changeset.action)
|
||||
|
||||
if manage_change do
|
||||
{argument, manage_change}
|
||||
end
|
||||
end
|
||||
_ ->
|
||||
{nil, nil}
|
||||
end
|
||||
|
||||
changeset.resource
|
||||
|
@ -455,6 +441,8 @@ defmodule AshPhoenix do
|
|||
{Map.update!(changeset.data, rel, &hide/1), nil}
|
||||
end
|
||||
end
|
||||
else
|
||||
{changeset.data, []}
|
||||
end
|
||||
|
||||
changeset = mark_removed(changeset, new_value, rel)
|
||||
|
@ -470,20 +458,15 @@ defmodule AshPhoenix do
|
|||
end
|
||||
|
||||
defp find_manage_change(argument, action) do
|
||||
Enum.find(action.changes, fn
|
||||
{Ash.Resource.Change.ManageRelationship, opts} ->
|
||||
opts[:argument] == argument.name
|
||||
Enum.find_value(action.changes, fn
|
||||
%{change: {Ash.Resource.Change.ManageRelationship, opts}} ->
|
||||
if opts[:argument] == argument.name do
|
||||
opts[:relationship]
|
||||
end
|
||||
|
||||
_ ->
|
||||
false
|
||||
end)
|
||||
|> case do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
{_, opts} ->
|
||||
opts[:relationship_name]
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
@ -670,13 +653,21 @@ defmodule AshPhoenix do
|
|||
end
|
||||
|
||||
defp add_to_path(nil, [], add) do
|
||||
add
|
||||
List.wrap(add)
|
||||
end
|
||||
|
||||
defp add_to_path(value, [], add) when is_list(value) do
|
||||
value ++ List.wrap(add)
|
||||
end
|
||||
|
||||
defp add_to_path(value, [], add) when value == %{} do
|
||||
[value] ++ List.wrap(add)
|
||||
end
|
||||
|
||||
defp add_to_path(value, [key | rest], add) when is_integer(key) and value == %{} do
|
||||
add_to_path([value], [key | rest], add)
|
||||
end
|
||||
|
||||
defp add_to_path(value, [key | rest], add) when is_integer(key) and is_list(value) do
|
||||
List.update_at(value, key, &add_to_path(&1, rest, add))
|
||||
end
|
||||
|
@ -706,6 +697,8 @@ defmodule AshPhoenix do
|
|||
%{key => add_to_path(nil, rest, add)}
|
||||
end
|
||||
|
||||
defp add_to_path(_, _, add), do: add
|
||||
|
||||
defp remove_from_path(value, [key]) when is_integer(key) and is_list(value) do
|
||||
List.delete_at(value, key)
|
||||
end
|
||||
|
@ -754,7 +747,15 @@ defmodule AshPhoenix do
|
|||
|
||||
defp remove_from_path(value, _), do: value
|
||||
|
||||
defp decode_path(path) do
|
||||
@doc """
|
||||
A utility for decoding the path of a form into a list.
|
||||
|
||||
For example:
|
||||
change[posts][0][comments][1]
|
||||
["change", "posts", 0, "comments", 1]
|
||||
|
||||
"""
|
||||
def decode_path(path) do
|
||||
path = Plug.Conn.Query.decode(path)
|
||||
do_decode_path(path)
|
||||
end
|
||||
|
|
|
@ -95,6 +95,13 @@ defimpl Phoenix.HTML.FormData, for: Ash.Changeset do
|
|||
rel = Ash.Resource.Info.relationship(changeset.resource, field) ->
|
||||
data = relationship_data(changeset, rel, use_data?, opts[:id] || rel.name)
|
||||
|
||||
data =
|
||||
if rel.cardinality == :many && data do
|
||||
List.wrap(data)
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
{rel, rel.destination, data}
|
||||
|
||||
attr = Ash.Resource.Info.attribute(changeset.resource, field) ->
|
||||
|
@ -171,11 +178,25 @@ defimpl Phoenix.HTML.FormData, for: Ash.Changeset do
|
|||
[] ->
|
||||
nil
|
||||
|
||||
data when is_list(data) ->
|
||||
List.last(data)
|
||||
|
||||
value ->
|
||||
value
|
||||
value =
|
||||
if is_list(value) do
|
||||
List.last(value)
|
||||
else
|
||||
value
|
||||
end
|
||||
|
||||
if use_data? do
|
||||
data = changeset_data(changeset, rel)
|
||||
|
||||
if data do
|
||||
Ash.Changeset.new(data, value)
|
||||
else
|
||||
value
|
||||
end
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -190,10 +211,29 @@ defimpl Phoenix.HTML.FormData, for: Ash.Changeset do
|
|||
end
|
||||
|
||||
{manage, _opts} ->
|
||||
manage
|
||||
if use_data? do
|
||||
changeset
|
||||
|> changeset_data(rel)
|
||||
|> zip_changes(manage)
|
||||
else
|
||||
manage
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp zip_changes([], manage) do
|
||||
manage
|
||||
end
|
||||
|
||||
defp zip_changes([record | rest_data], [manage | rest_manage]) do
|
||||
[Ash.Changeset.new(record, manage) |> Map.put(:params, manage)] ++
|
||||
zip_changes(rest_data, rest_manage)
|
||||
end
|
||||
|
||||
defp zip_changes(records, []) do
|
||||
records
|
||||
end
|
||||
|
||||
defp get_managed(changeset, relationship_name, id) do
|
||||
manage = changeset.relationships[relationship_name] || []
|
||||
|
||||
|
|
|
@ -61,7 +61,17 @@ defmodule AshPhoenix.FormData.Helpers do
|
|||
update_action = Ash.Resource.Info.primary_action(resource, :update)
|
||||
|
||||
if update_action do
|
||||
Ash.Changeset.for_update(data, update_action.name, %{})
|
||||
accepted_relationships =
|
||||
resource
|
||||
|> accepted_relationships(update_action)
|
||||
|> Enum.map(fn relationship ->
|
||||
{relationship.name, {:manage, [meta: [id: relationship.name]]}}
|
||||
end)
|
||||
|
||||
Ash.Changeset.for_update(data, update_action.name, %{},
|
||||
relationships: accepted_relationships,
|
||||
actor: opts[:actor]
|
||||
)
|
||||
else
|
||||
Ash.Changeset.new(data)
|
||||
end
|
||||
|
@ -69,7 +79,17 @@ defmodule AshPhoenix.FormData.Helpers do
|
|||
create_action = Ash.Resource.Info.primary_action(resource, :create)
|
||||
|
||||
if create_action do
|
||||
Ash.Changeset.for_create(resource, create_action.name, data)
|
||||
accepted_relationships =
|
||||
resource
|
||||
|> accepted_relationships(create_action)
|
||||
|> Enum.map(fn relationship ->
|
||||
{relationship.name, {:manage, [meta: [id: relationship.name]]}}
|
||||
end)
|
||||
|
||||
Ash.Changeset.for_create(resource, create_action.name, data,
|
||||
relationships: accepted_relationships,
|
||||
actor: opts[:actor]
|
||||
)
|
||||
else
|
||||
Ash.Changeset.new(resource, data)
|
||||
end
|
||||
|
@ -128,7 +148,17 @@ defmodule AshPhoenix.FormData.Helpers do
|
|||
cond do
|
||||
is_struct(data) ->
|
||||
if update_action do
|
||||
Ash.Changeset.for_update(data, update_action.name, %{})
|
||||
accepted_relationships =
|
||||
resource
|
||||
|> accepted_relationships(update_action)
|
||||
|> Enum.map(fn relationship ->
|
||||
{relationship.name, {:manage, [meta: [id: relationship.name]]}}
|
||||
end)
|
||||
|
||||
Ash.Changeset.for_update(data, update_action.name, %{},
|
||||
relationships: accepted_relationships,
|
||||
actor: opts[:actor]
|
||||
)
|
||||
else
|
||||
data
|
||||
|> Ash.Changeset.new()
|
||||
|
@ -140,7 +170,17 @@ defmodule AshPhoenix.FormData.Helpers do
|
|||
|
||||
true ->
|
||||
if create_action do
|
||||
Ash.Changeset.for_create(resource, create_action.name, data)
|
||||
accepted_relationships =
|
||||
resource
|
||||
|> accepted_relationships(create_action)
|
||||
|> Enum.map(fn relationship ->
|
||||
{relationship.name, {:manage, [meta: [id: relationship.name]]}}
|
||||
end)
|
||||
|
||||
Ash.Changeset.for_create(resource, create_action.name, data,
|
||||
relationships: accepted_relationships,
|
||||
actor: opts[:actor]
|
||||
)
|
||||
else
|
||||
resource
|
||||
|> Ash.Changeset.new(data)
|
||||
|
@ -202,9 +242,9 @@ defmodule AshPhoenix.FormData.Helpers do
|
|||
data
|
||||
|> Enum.map(fn data ->
|
||||
if is_struct(data) do
|
||||
Ash.Changeset.for_update(data, update_action, %{})
|
||||
Ash.Changeset.for_update(data, update_action, %{}, actor: opts[:actor])
|
||||
else
|
||||
Ash.Changeset.for_create(resource, create_action, data)
|
||||
Ash.Changeset.for_create(resource, create_action, data, actor: opts[:actor])
|
||||
end
|
||||
end)
|
||||
|
||||
|
@ -263,13 +303,13 @@ defmodule AshPhoenix.FormData.Helpers do
|
|||
changeset =
|
||||
cond do
|
||||
is_struct(data) ->
|
||||
Ash.Changeset.for_update(data, update_action, %{})
|
||||
Ash.Changeset.for_update(data, update_action, %{}, actor: opts[:actor])
|
||||
|
||||
is_nil(data) ->
|
||||
nil
|
||||
|
||||
true ->
|
||||
Ash.Changeset.for_create(resource, create_action, data)
|
||||
Ash.Changeset.for_create(resource, create_action, data, actor: opts[:actor])
|
||||
end
|
||||
|
||||
if changeset do
|
||||
|
@ -303,4 +343,23 @@ defmodule AshPhoenix.FormData.Helpers do
|
|||
}
|
||||
end
|
||||
end
|
||||
|
||||
defp accepted_relationships(resource, action) do
|
||||
accepted =
|
||||
if action.accept do
|
||||
resource
|
||||
|> Ash.Resource.Info.relationships()
|
||||
|> Enum.filter(&(&1.name in action.accept))
|
||||
else
|
||||
Ash.Resource.Info.relationships(resource)
|
||||
end
|
||||
|
||||
if action.reject do
|
||||
resource
|
||||
|> Ash.Resource.Info.relationships()
|
||||
|> Enum.reject(&(&1.name in action.reject))
|
||||
else
|
||||
accepted
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue