improvement: experimental Form.params options

fix: don't allow embeds to be sparse
This commit is contained in:
Zach Daniel 2021-08-27 01:46:21 -04:00
parent ce9e7fc639
commit 2075d4e975
2 changed files with 80 additions and 50 deletions

View file

@ -69,7 +69,8 @@ defmodule AshPhoenix.Form.Auto do
],
sparse_lists?: [
type: :boolean,
doc: "Sets all list type forms to `sparse?: true` by default.",
doc:
"Sets all list type forms to `sparse?: true` by default. Has no effect on forms derived for embedded resources.",
default: false
]
]
@ -451,9 +452,9 @@ defmodule AshPhoenix.Form.Auto do
[
type: type,
resource: embed,
sparse?: auto_opts[:sparse_lists?],
create_action: create_action.name,
update_action: update_action.name,
embed?: true,
data: data,
forms: [],
updater: fn opts ->

View file

@ -1260,8 +1260,12 @@ defmodule AshPhoenix.Form do
"""
@spec params(t()) :: map
def params(form, opts \\ []) do
# These options aren't documented because they are still experimental
hidden? = opts[:hidden?] || false
indexed_lists? = opts[:indexed_lists?] || false
indexer = opts[:indexer]
indexed_lists? = opts[:indexed_lists?] || not is_nil(indexer) || false
transform = opts[:transform]
only_touched? = Keyword.get(opts, :only_touched?, true)
form_keys =
form.form_keys
@ -1279,57 +1283,79 @@ defmodule AshPhoenix.Form do
params
end
form.form_keys
|> Enum.filter(fn {key, _} ->
untransformed_params =
form.form_keys
|> only_touched(form, only_touched?)
|> Enum.reduce(params, fn {key, config}, params ->
case config[:type] || :single do
:single ->
if form.forms[key] do
nested_params =
if form.forms[key] do
params(form.forms[key], opts)
else
nil
end
if form.form_keys[key][:merge?] do
Map.merge(nested_params || %{}, params)
else
Map.put(params, to_string(config[:for] || key), nested_params)
end
else
Map.put(params, to_string(config[:for] || key), nil)
end
:list ->
for_name = to_string(config[:for] || key)
if indexed_lists? do
params
|> Map.put_new(for_name, %{})
|> Map.update!(for_name, fn current ->
if indexer do
Enum.reduce(form.forms[key], current, fn form, current ->
Map.put(current, indexer.(form), params(form, opts))
end)
else
max =
current
|> Map.keys()
|> Enum.map(&String.to_integer/1)
|> Enum.max(fn -> -1 end)
form.forms[key]
|> Enum.reduce({current, max + 1}, fn form, {current, i} ->
{Map.put(current, to_string(i), params(form, opts)), i + 1}
end)
|> elem(0)
end
end)
else
params
|> Map.put_new(for_name, [])
|> Map.update!(for_name, fn current ->
current ++ Enum.map(form.forms[key] || [], &params(&1, opts))
end)
end
end
end)
if transform do
Map.new(untransformed_params, transform)
else
untransformed_params
end
end
defp only_touched(form_keys, true, form) do
Enum.filter(form_keys, fn {key, _} ->
MapSet.member?(form.touched_forms, to_string(key))
end)
|> Enum.reduce(params, fn {key, config}, params ->
case config[:type] || :single do
:single ->
if form.forms[key] do
nested_params =
if form.forms[key] do
params(form.forms[key], opts)
else
nil
end
if form.form_keys[key][:merge?] do
Map.merge(nested_params || %{}, params)
else
Map.put(params, to_string(config[:for] || key), nested_params)
end
else
Map.put(params, to_string(config[:for] || key), nil)
end
:list ->
for_name = to_string(config[:for] || key)
if indexed_lists? do
params
|> Map.put_new(for_name, %{})
|> Map.update!(for_name, fn current ->
max =
current |> Map.keys() |> Enum.map(&String.to_integer/1) |> Enum.max(fn -> -1 end)
form.forms[key]
|> Enum.reduce({current, max + 1}, fn form, {current, i} ->
{Map.put(current, to_string(i), params(form, opts)), i + 1}
end)
|> elem(0)
end)
else
params
|> Map.put_new(for_name, [])
|> Map.update!(for_name, fn current ->
current ++ Enum.map(form.forms[key] || [], &params(&1, opts))
end)
end
end
end)
end
defp only_touched(form_keys, _, _), do: form_keys
@add_form_opts [
prepend: [
type: :boolean,
@ -2851,6 +2877,9 @@ defmodule AshPhoenix.Form do
|> Enum.sort_by(fn {params, key} ->
params["_index"] || key
end)
# rescue
# _ ->
end
defp indexed_list(other) do