Packages
ash_phoenix
0.4.20
2.3.24
2.3.23
2.3.22
2.3.21
2.3.20
2.3.19
2.3.18
2.3.17
2.3.16
2.3.15
2.3.14
2.3.13
2.3.12
2.3.11
2.3.10
2.3.9
2.3.8
2.3.7
2.3.6
2.3.5
2.3.4
2.3.3
2.3.2
2.3.1
2.3.0
2.2.0
2.1.26
2.1.25
2.1.24
2.1.23
2.1.22
2.1.21
2.1.20
2.1.19
2.1.18
2.1.17
2.1.16
2.1.15
2.1.14
2.1.13
2.1.12
2.1.11
2.1.10
2.1.9
2.1.8
2.1.7
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-rc.8
2.0.0-rc.7
2.0.0-rc.6
2.0.0-rc.5
2.0.0-rc.4
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
1.3.7
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.26
1.2.25
1.2.24
1.2.23
1.2.22
1.2.21
1.2.20
1.2.19
1.2.18
1.2.17
1.2.16
1.2.15
1.2.14
1.2.13
1.2.12
1.2.11
1.2.10
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.1.0-rc.3
1.1.0-rc.2
1.1.0-rc.1
1.1.0-rc.0
1.0.0-rc.1
1.0.0-rc.0
1.0.0-pre.2
1.0.0-pre.1
1.0.0-pre.0
0.7.7
0.7.6-rc.0
0.7.5
0.7.4
0.7.3
0.7.2-rc.2
0.7.2-rc.1
0.7.2-rc.0
0.7.1
0.7.0
0.6.0-rc.7
0.6.0-rc.6
0.6.0-rc.5
0.6.0-rc.4
0.6.0-rc.3
0.6.0-rc.2
0.6.0-rc.1
0.6.0-rc.0
0.5.19-rc.2
0.5.19-rc.1
0.5.19-rc.0
0.5.18
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.24
0.4.23
0.4.23-rc.1
0.4.23-rc.0
0.4.22-rc2
0.4.22-rc1
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Utilities for integrating Ash and Phoenix
Current section
Files
Jump to
Current section
Files
lib/ash_phoenix/form_data/helpers.ex
defmodule AshPhoenix.FormData.Helpers do
@moduledoc false
def get_argument(nil, _), do: nil
def get_argument(action, field) when is_atom(field) do
Enum.find(action.arguments, &(&1.name == field))
end
def get_argument(action, field) when is_binary(field) do
Enum.find(action.arguments, &(to_string(&1.name) == field))
end
def argument_and_manages(changeset, key) do
with action when not is_nil(action) <- changeset.action,
argument when not is_nil(argument) <-
Enum.find(changeset.action.arguments, &(&1.name == key || to_string(&1.name) == key)),
manage_change when not is_nil(manage_change) <-
find_manage_change(argument, changeset.action) do
{argument, manage_change}
else
_ ->
{nil, nil}
end
end
defp find_manage_change(argument, action) do
Enum.find_value(action.changes, fn
%{change: {Ash.Resource.Change.ManageRelationship, opts}} ->
if opts[:argument] == argument.name do
opts[:relationship]
end
_ ->
nil
end)
end
def type_to_form_type(type) do
case Ash.Type.ecto_type(type) do
:integer -> :number_input
:boolean -> :checkbox
:date -> :date_select
:time -> :time_select
:utc_datetime -> :datetime_select
:naive_datetime -> :datetime_select
_ -> :text_input
end
end
def form_for_errors(query, _opts) do
AshPhoenix.errors_for(query)
end
def form_for_name(resource) do
resource
|> Module.split()
|> List.last()
|> Macro.underscore()
end
def get_embedded({:array, type}), do: get_embedded(type)
def get_embedded(type) when is_atom(type) do
if Ash.Resource.Info.embedded?(type) do
type
end
end
def get_embedded(_), do: nil
def relationship_data(changeset, %{cardinality: :one} = rel, use_data?, id) do
case get_managed(changeset, rel.name, id) do
nil ->
if use_data? do
changeset_data(changeset, rel)
else
nil
end
{manage, _opts} ->
case manage do
nil ->
nil
[] ->
nil
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
data
|> Ash.Changeset.new()
|> Map.put(:params, value)
else
value
end
else
value
end
end
end
end
def relationship_data(changeset, rel, use_data?, id) do
case get_managed(changeset, rel.name, id) do
nil ->
if use_data? do
changeset_data(changeset, rel)
else
[]
end
{manage, _opts} ->
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, %{})
|> Map.put(:params, manage)
] ++
zip_changes(rest_data, rest_manage)
end
defp zip_changes(records, []) do
records
end
defp changeset_data(changeset, rel) do
data = Map.get(changeset.data, rel.name)
case data do
%Ash.NotLoaded{} ->
default_data(rel)
data ->
if is_list(data) do
Enum.reject(data, &hidden?/1)
else
if hidden?(data) do
nil
else
data
end
end
end
end
defp default_data(%{cardinality: :many}), do: []
defp default_data(%{cardinality: :one}), do: nil
defp get_managed(changeset, relationship_name, id) do
manage = changeset.relationships[relationship_name] || []
Enum.find(manage, fn {_, opts} -> opts[:meta][:id] == id end)
end
@doc false
def to_nested_form(
data,
original_changeset,
%{cardinality: _} = relationship,
resource,
id,
name,
opts
)
when is_list(data) do
changesets =
Enum.map(
data,
&related_data_to_changeset(resource, &1, opts, relationship, original_changeset)
)
changesets =
if AshPhoenix.hiding_errors?(original_changeset) do
Enum.map(changesets, &AshPhoenix.hide_errors/1)
else
changesets
end
for {changeset, index} <- Enum.with_index(changesets) do
index_string = Integer.to_string(index)
hidden =
if changeset.action_type in [:update, :destroy] do
changeset.data
|> Map.take(Ash.Resource.Info.primary_key(changeset.resource))
|> Enum.to_list()
else
[]
end
%Phoenix.HTML.Form{
source: changeset,
impl: Phoenix.HTML.FormData.impl_for(changeset),
id: id <> "_" <> index_string,
name: name <> "[" <> index_string <> "]",
index: index,
errors: form_for_errors(changeset, opts),
data: changeset.data,
params: changeset.params,
hidden: hidden,
options: opts
}
end
end
def to_nested_form(nil, _, _, _, _, _, _) do
nil
end
def to_nested_form(
data,
original_changeset,
%{cardinality: _} = relationship,
resource,
id,
name,
opts
) do
changeset = related_data_to_changeset(resource, data, opts, relationship, original_changeset)
changeset =
if AshPhoenix.hiding_errors?(original_changeset) do
AshPhoenix.hide_errors(changeset)
else
changeset
end
hidden =
if changeset.action_type in [:update, :destroy] do
changeset.data
|> Map.take(Ash.Resource.Info.primary_key(changeset.resource))
|> Enum.to_list()
else
[]
end
%Phoenix.HTML.Form{
source: changeset,
impl: Phoenix.HTML.FormData.impl_for(changeset),
id: id,
name: name,
errors: form_for_errors(changeset, opts),
data: changeset.data,
params: changeset.params,
hidden: hidden,
options: opts
}
end
def to_nested_form(
data,
original_changeset,
attribute,
resource,
id,
name,
opts
)
when is_list(data) do
create_action =
action!(resource, :create, attribute.constraints[:create_action] || opts[:create_action]).name
update_action =
action!(resource, :update, attribute.constraints[:update_action] || opts[:update_action]).name
changesets =
data
|> Enum.map(fn data ->
if is_struct(data) do
Ash.Changeset.for_update(data, update_action, params(data), actor: opts[:actor])
else
Ash.Changeset.for_create(resource, create_action, params(data), actor: opts[:actor])
end
end)
changesets =
if AshPhoenix.hiding_errors?(original_changeset) do
Enum.map(changesets, &AshPhoenix.hide_errors/1)
else
changesets
end
for {changeset, index} <- Enum.with_index(changesets) do
index_string = Integer.to_string(index)
hidden =
if changeset.action_type in [:update, :destroy] do
changeset.data
|> Map.take(Ash.Resource.Info.primary_key(changeset.resource))
|> Enum.to_list()
else
[]
end
%Phoenix.HTML.Form{
source: changeset,
impl: Phoenix.HTML.FormData.impl_for(changeset),
id: id <> "_" <> index_string,
name: name <> "[" <> index_string <> "]",
index: index,
errors: form_for_errors(changeset, opts),
data: changeset.data,
params: changeset.params,
hidden: hidden,
options: opts
}
end
end
def to_nested_form(
data,
original_changeset,
attribute,
resource,
id,
name,
opts
) do
create_action =
action!(resource, :create, attribute.constraints[:create_action] || opts[:create_action]).name
update_action =
action!(resource, :update, attribute.constraints[:update_action] || opts[:update_action]).name
changeset =
cond do
is_struct(data) ->
Ash.Changeset.for_update(data, update_action, params(data), actor: opts[:actor])
is_nil(data) ->
nil
true ->
Ash.Changeset.for_create(resource, create_action, params(data), actor: opts[:actor])
end
if changeset do
changeset =
if AshPhoenix.hiding_errors?(original_changeset) do
AshPhoenix.hide_errors(changeset)
else
changeset
end
hidden =
if changeset.action_type in [:update, :destroy] do
changeset.data
|> Map.take(Ash.Resource.Info.primary_key(changeset.resource))
|> Enum.to_list()
else
[]
end
%Phoenix.HTML.Form{
source: changeset,
impl: Phoenix.HTML.FormData.impl_for(changeset),
id: id,
name: name,
errors: form_for_errors(changeset, opts),
data: changeset.data,
params: changeset.params,
hidden: hidden,
options: opts
}
end
end
def hidden?(nil), do: false
def hidden?(%_{} = data) do
Ash.Resource.Info.get_metadata(data, :private)[:hidden?]
end
def hidden?(_), do: false
def hide(nil), do: nil
def hide(record) do
Ash.Resource.Info.put_metadata(record, :private, %{hidden?: true})
end
defp related_data_to_changeset(resource, data, opts, relationship, source_changeset) do
if is_struct(data) do
if opts[:update_action] == :_raw do
Ash.Changeset.new(data)
else
update_action = action!(resource, :update, opts[:update_action])
data
|> case do
%Ash.Changeset{} = changeset ->
changeset
other ->
Ash.Changeset.new(other)
end
|> set_source_context({relationship, source_changeset})
|> Ash.Changeset.for_update(update_action.name, params(data), actor: opts[:actor])
end
else
if opts[:create_action] == :_raw do
resource
|> Ash.Changeset.new(take_attributes(data, resource))
|> set_source_context({relationship, source_changeset})
|> Map.put(:params, data)
else
create_action = action!(resource, :create, opts[:create_action])
resource
|> Ash.Changeset.new()
|> set_source_context({relationship, source_changeset})
|> Ash.Changeset.for_create(create_action.name, data, actor: opts[:actor])
end
end
end
defp params(%Ash.Changeset{params: params}), do: params
defp params(_), do: nil
defp set_source_context(changeset, {relationship, original_changeset}) do
case original_changeset.context[:manage_relationship_source] do
nil ->
Ash.Changeset.set_context(changeset, %{
manage_relationship_source: [
{relationship.source, relationship.name, original_changeset}
]
})
value ->
Ash.Changeset.set_context(changeset, %{
manage_relationship_source:
value ++ [{relationship.source, relationship.name, original_changeset}]
})
end
end
def take_attributes(data, resource) do
attributes =
resource
|> Ash.Resource.Info.attributes()
|> Enum.map(&to_string(&1.name))
Map.take(data, attributes)
end
def action!(resource, type, nil) do
case Ash.Resource.Info.primary_action(resource, type) do
nil ->
raise """
No `#{type}_action` configured, and no primary action of type #{type} found on #{
inspect(resource)
}
"""
action ->
action
end
end
def action!(resource, _type, action) do
case Ash.Resource.Info.action(resource, action) do
nil ->
raise """
No such action #{action} on resource #{inspect(resource)}
"""
action ->
action
end
end
end