Packages

ash

2.21.11
3.29.3 3.29.2 3.29.1 3.29.0 3.28.0 3.27.8 3.27.7 3.27.6 3.27.5 3.27.4 3.27.3 3.27.2 3.27.1 3.27.0 3.26.0 3.25.2 3.25.1 3.25.0 retired 3.24.7 3.24.6 3.24.5 3.24.4 3.24.3 3.24.2 3.24.1 3.24.0 3.23.1 3.23.0 3.22.2 3.22.1 3.22.0 3.21.3 3.21.2 3.21.1 3.21.0 3.20.0 3.19.3 3.19.2 3.19.1 3.19.0 3.18.0 3.17.1 3.17.0 3.16.0 3.15.0 3.14.1 3.14.0 retired 3.13.2 3.13.1 3.13.0 3.12.0 3.11.3 3.11.2 3.11.1 3.11.0 3.10.1 3.10.0 3.9.0 3.8.0 3.7.6 3.7.5 3.7.4 3.7.3 3.7.2 3.7.1 3.7.0 retired 3.6.3 retired 3.6.2 3.6.1 3.6.0 3.5.43 3.5.42 3.5.41 3.5.40 3.5.39 3.5.38 3.5.37 3.5.36 3.5.35 3.5.34 3.5.33 3.5.32 3.5.31 3.5.30 3.5.29 3.5.28 3.5.27 3.5.26 3.5.25 3.5.24 3.5.23 3.5.22 3.5.21 3.5.20 3.5.19 3.5.18 3.5.17 3.5.16 3.5.15 3.5.14 3.5.13 3.5.12 3.5.11 3.5.10 3.5.9 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3 3.5.2 3.5.1 3.5.0 3.4.74 retired 3.4.73 3.4.72 3.4.71 3.4.70 3.4.69 3.4.68 3.4.67 3.4.66 3.4.65 3.4.64 3.4.63 3.4.62 3.4.61 3.4.60 3.4.59 3.4.58 3.4.57 3.4.56 3.4.55 3.4.54 3.4.53 3.4.52 3.4.51 3.4.50 3.4.49 3.4.48 3.4.47 3.4.46 3.4.45 3.4.44 3.4.43 3.4.42 3.4.41 3.4.40 3.4.39 3.4.38 3.4.37 3.4.36 3.4.35 3.4.34 3.4.33 3.4.32 3.4.31 3.4.30 3.4.29 3.4.28 3.4.27 3.4.26 3.4.25 3.4.24 3.4.23 3.4.22 3.4.21 3.4.20 3.4.19 3.4.18 3.4.17 3.4.16 3.4.15 3.4.14 3.4.13 3.4.12 3.4.11 3.4.10 3.4.9 3.4.8 3.4.7 3.4.6 3.4.5 3.4.4 3.4.3 3.4.2 3.4.1 3.4.0 3.3.3 3.3.2 3.3.1 3.3.0 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 3.2.0 3.1.8 3.1.7 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.16 3.0.15 3.0.14 3.0.13 3.0.12 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.4 3.0.3 3.0.2 3.0.1 3.0.0 3.0.0-rc.46 3.0.0-rc.45 3.0.0-rc.44 3.0.0-rc.43 3.0.0-rc.42 3.0.0-rc.41 3.0.0-rc.40 3.0.0-rc.39 3.0.0-rc.38 3.0.0-rc.37 3.0.0-rc.36 3.0.0-rc.35 3.0.0-rc.34 3.0.0-rc.33 3.0.0-rc.32 3.0.0-rc.31 3.0.0-rc.29 3.0.0-rc.28 3.0.0-rc.27 3.0.0-rc.26 3.0.0-rc.25 3.0.0-rc.24 3.0.0-rc.23 3.0.0-rc.22 3.0.0-rc.21 3.0.0-rc.20 3.0.0-rc.19 3.0.0-rc.18 3.0.0-rc.17 3.0.0-rc.16 3.0.0-rc.15 3.0.0-rc.14 3.0.0-rc.13 3.0.0-rc.12 3.0.0-rc.11 3.0.0-rc.10 3.0.0-rc.9 3.0.0-rc.8 3.0.0-rc.7 3.0.0-rc.6 3.0.0-rc.5 3.0.0-rc.4 3.0.0-rc.3 3.0.0-rc.1 3.0.0-rc.0 2.21.15 2.21.14 2.21.13 2.21.12 2.21.11 2.21.10 2.21.9 2.21.8 2.21.7 2.21.6 2.21.5 2.21.4 2.21.3 2.21.2 2.21.1 2.21.0 2.20.3 2.20.2 2.20.1 2.20.0 2.19.14 2.19.13 2.19.12 2.19.11 2.19.10 2.19.9 2.19.8 2.19.7 2.19.6 2.19.5 2.19.4 2.19.3 retired 2.19.2 retired 2.19.1 retired 2.19.0 retired 2.18.2 2.18.1 2.18.0 2.17.24 2.17.23 2.17.22 2.17.21 2.17.20 2.17.19 2.17.18 2.17.17 2.17.16 2.17.15 2.17.14 2.17.13 2.17.12 2.17.11 2.17.10 2.17.9 2.17.8 2.17.7 2.17.6 2.17.5 2.17.4 2.17.3 2.17.2 2.17.1 2.17.0 2.16.1 2.16.0 2.15.20 2.15.19 2.15.18 2.15.17 2.15.16 2.15.15 2.15.14 2.15.13 2.15.12 2.15.11 2.15.10 2.15.9 2.15.8 2.15.7 2.15.6 2.15.5 2.15.4 2.15.2 2.15.1 2.15.0 2.14.21 2.14.20 2.14.19 2.14.18 2.14.17 2.14.16 2.14.15 2.14.14 2.14.13 2.14.12 2.14.11 2.14.10 2.14.9 2.14.8 2.14.7 2.14.6 2.14.5 2.14.4 2.14.3 2.14.2 2.14.1 2.14.0 2.13.4 retired 2.13.3 2.13.2 2.13.1 2.13.0 2.12.1 2.12.0 2.11.11 2.11.10 2.11.9 2.11.8 2.11.7 2.11.6 2.11.5 2.11.4 2.11.3 2.11.2 2.11.1 2.11.0 2.11.0-rc.3 2.11.0-rc.2 2.11.0-rc.1 2.11.0-rc.0 2.10.2 2.10.1 2.10.0 2.9.29 2.9.28 2.9.27 2.9.26 2.9.25 2.9.24 2.9.23 2.9.22 2.9.21 2.9.20 2.9.19 2.9.18 2.9.17 2.9.16 2.9.15 2.9.14 2.9.13 2.9.12 2.9.11 2.9.10 2.9.9 2.9.8 2.9.7 2.9.6 2.9.5 2.9.4 2.9.3 2.9.2 2.9.1 2.9.0 2.8.1 2.8.0 2.7.1 2.7.0 2.6.31 2.6.30 2.6.29 2.6.28 2.6.27 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.6.2 2.6.1 2.6.0 2.5.16 2.5.15 2.5.14 2.5.13 2.5.12 2.5.11 2.5.10 2.5.9 2.5.8 2.5.7 2.5.6 2.5.5 2.5.4 2.5.3 2.5.2 2.5.1 2.5.0 2.5.0-rc.6 2.5.0-rc.5 2.5.0-rc.4 2.5.0-rc.3 2.5.0-rc.2 2.5.0-rc.1 2.5.0-rc.0 2.4.30 2.4.29 2.4.28 2.4.27 2.4.26 2.4.25 2.4.24 2.4.23 2.4.22 2.4.21 2.4.20 2.4.19 2.4.18 2.4.17 2.4.16 2.4.15 2.4.14 2.4.13 2.4.12 2.4.11 2.4.10 2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4.0 2.3.0 2.2.0 2.1.0 2.0.0 2.0.0-rc.15 2.0.0-rc.14 2.0.0-rc.13 2.0.0-rc.12 2.0.0-rc.11 2.0.0-rc.10 2.0.0-rc.9 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 2.0.0-pre.8 2.0.0-pre.7 2.0.0-pre.6 2.0.0-pre.5 2.0.0-pre.4 2.0.0-pre.3 2.0.0-pre.2 2.0.0-pre.1 2.0.0-pre.0 1.53.3 1.53.2 1.53.0 1.52.0-rc.22 1.52.0-rc.21 1.52.0-rc.20 1.52.0-rc.19 1.52.0-rc.18 1.52.0-rc.17 1.52.0-rc.16 1.52.0-rc.15 1.52.0-rc.14 1.52.0-rc.13 1.52.0-rc.12 1.52.0-rc.11 1.52.0-rc.10 1.52.0-rc.9 1.52.0-rc.8 1.52.0-rc.7 1.52.0-rc.6 1.52.0-rc.5 1.52.0-rc.4 1.52.0-rc.3 1.52.0-rc.2 1.52.0-rc.1 1.52.0-rc.0 1.51.2 1.51.1 retired 1.51.0 1.50.21 1.50.20 1.50.19 1.50.18 1.50.17 1.50.16 1.50.15 1.50.14 1.50.13 1.50.12 1.50.11 1.50.10 1.50.9 1.50.8 1.50.7 1.50.6 1.50.5 1.50.4 1.50.3 1.50.2 1.50.1 1.50.0 1.49.0 1.48.0-rc.30 1.48.0-rc.29 1.48.0-rc.28 1.48.0-rc.27 1.48.0-rc.26 1.48.0-rc.25 1.48.0-rc.24 1.48.0-rc.23 1.48.0-rc.22 1.48.0-rc.21 1.48.0-rc.20 1.48.0-rc.19 1.48.0-rc.18 1.48.0-rc.17 1.48.0-rc.16 1.48.0-rc.15 1.48.0-rc.14 1.48.0-rc.13 1.48.0-rc.12 1.48.0-rc.11 1.48.0-rc.10 1.48.0-rc.9 1.48.0-rc.8 1.48.0-rc.7 1.48.0-rc.6 1.48.0-rc.5 1.48.0-rc.4 1.48.0-rc.3 1.48.0-rc.2 1.48.0-rc.1 1.48.0-rc.0 1.47.12 1.47.11 1.47.10 1.47.9 1.47.8 1.47.7 1.47.6 1.47.5 1.47.4 1.47.3 1.47.2 1.47.1 1.47.0 1.46.13 1.46.12 1.46.11 1.46.10 1.46.9 1.46.8 1.46.7 1.46.6 1.46.5 1.46.4 1.46.3 1.46.2 1.46.1 1.46.0 1.45.0-rc9 1.45.0-rc8 1.45.0-rc7 1.45.0-rc6 1.45.0-rc5 1.45.0-rc4 1.45.0-rc3 1.45.0-rc20 1.45.0-rc2 1.45.0-rc19 1.45.0-rc18 1.45.0-rc17 1.45.0-rc16 1.45.0-rc15 1.45.0-rc14 1.45.0-rc13 1.45.0-rc12 1.45.0-rc11 1.45.0-rc10 1.45.0-rc1 1.45.0-rc0 1.44.13 1.44.12 1.44.11 1.44.10 1.44.9 1.44.8 1.44.7 1.44.6 1.44.5 1.44.4 1.44.3 1.44.2 1.44.1 1.44.0 1.43.12 1.43.11 1.43.10 1.43.9 1.43.8 1.43.7 1.43.6 1.43.5 1.43.4 1.43.3 1.43.2 1.43.1 1.43.0 1.42.0 1.41.12 1.41.11 1.41.10 1.41.9 1.41.8 1.41.7 1.41.6 1.41.5 1.41.4 1.41.3 1.41.2 1.41.1 1.41.0 1.40.0 1.39.7 1.39.6 1.39.5 1.39.4 1.39.3 1.39.2 1.39.1 1.39.0 1.38.0 1.37.2 1.37.1 1.37.0 1.36.22 1.36.21 1.36.19 1.36.18 1.36.17 1.36.16 1.36.15 1.36.14 1.36.13 1.36.12 1.36.11 1.36.10 1.36.9 1.36.8 1.36.7 1.36.6 1.36.5 1.36.4 1.36.3 1.36.2 1.36.0 1.35.1 1.35.0 1.34.9 1.34.8 1.34.7 1.34.6 1.34.5 1.34.4 1.34.3 1.34.2 1.34.1 1.34.0 1.33.0 1.32.2 1.32.1 1.32.0 1.31.1 1.31.0 1.30.2 1.30.1 1.29.0-rc1 1.29.0-rc0 1.28.1 1.28.0 1.27.1 1.27.0 1.26.13 1.26.12 1.26.11 1.26.10 1.26.9 1.26.8 1.26.7 1.26.6 1.26.5 1.26.4 1.26.2 1.26.1 1.26.0 1.25.8 1.25.7 1.25.6 1.25.5 1.25.4 1.25.3 1.25.2 1.25.1 1.25.0 1.24.2 1.24.1 1.24.0 1.23.3 1.23.2 1.23.1 1.23.0 1.22.1 1.22.0 1.20.1 1.20.0 1.19.1 1.19.0 1.18.1 1.18.0 1.17.1 1.17.0 1.16.2 1.15.1 1.15.0 1.14.0 1.13.4 1.13.3 1.13.2 1.13.1 1.13.0 1.12.0 1.11.1 1.11.0 1.10.0 1.9.0 1.8.0 1.7.0 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.1 1.5.0 1.4.1 1.4.0 1.3.1 1.3.0 1.2.1 1.2.0 1.1.3 1.1.2 1.1.0 1.0.3 1.0.2 1.0.1 1.0.0 0.13.1 0.13.0 0.12.0 0.10.0 0.9.1 0.9.0 0.8.0 0.7.0 0.6.5 0.6.4 0.6.3 0.6.2 0.6.1 0.6.0 0.5.2 0.5.1 0.5.0 0.4.0 0.3.0 0.2.0 0.1.9 0.1.8 0.1.3 0.1.1 0.1.0

A declarative, extensible framework for building Elixir applications.

Security advisory: This version has known vulnerabilities. View advisories

Current section

Files

Jump to
ash lib ash changeset managed_relationship_helpers.ex
Raw

lib/ash/changeset/managed_relationship_helpers.ex

defmodule Ash.Changeset.ManagedRelationshipHelpers do
@moduledoc """
Tools for introspecting managed relationships.
Extensions can use this to look at an argument that will be passed
to a `manage_relationship` change and determine what their behavior
should be. For example, AshAdmin uses these to find out what kind of
nested form it should offer for each argument that manages a relationship.
"""
def sanitize_opts(relationship, opts) do
is_many_to_many = relationship.type == :many_to_many
join_keys = opts[:join_keys] || []
[
on_no_match: :ignore,
on_missing: :ignore,
on_match: :ignore,
on_lookup: :ignore
]
|> Keyword.merge(opts)
|> Keyword.update!(:on_no_match, fn
:create when is_many_to_many ->
create = primary_action_name!(relationship.destination, :create)
join_create = primary_action_name!(relationship.through, :create)
{:create, create, join_create, join_keys}
{:create, create} when is_many_to_many ->
join_create = primary_action_name!(relationship.through, :create)
{:create, create, join_create, join_keys}
{:create, create, join_create} when is_many_to_many ->
{:create, create, join_create, join_keys}
:create ->
create = primary_action_name!(relationship.destination, :create)
{:create, create}
other ->
other
end)
|> Keyword.update!(:on_missing, fn
:unrelate when is_many_to_many ->
join_destroy = primary_action_name!(relationship.through, :destroy)
{:unrelate, join_destroy}
:unrelate when relationship.type in [:has_many, :has_one] ->
update = primary_action_name!(relationship.destination, :update)
{:unrelate, update}
:unrelate ->
{:unrelate, nil}
:destroy when is_many_to_many ->
destroy = primary_action_name!(relationship.destination, :destroy)
join_destroy = primary_action_name!(relationship.through, :destroy)
{:destroy, destroy, join_destroy}
{:destroy, destroy} when is_many_to_many ->
join_destroy = primary_action_name!(relationship.through, :destroy)
{:destroy, destroy, join_destroy}
:destroy ->
destroy = primary_action_name!(relationship.destination, :destroy)
{:destroy, destroy}
other ->
other
end)
|> Keyword.update!(:on_match, fn
:update when is_many_to_many ->
update = primary_action_name!(relationship.destination, :update)
join_update = primary_action_name!(relationship.through, :update)
{:update, update, join_update, join_keys}
{:update, update} when is_many_to_many ->
join_update = primary_action_name!(relationship.through, :update)
{:update, update, join_update, join_keys}
{:update, update, join_update} when is_many_to_many ->
{:update, update, join_update, join_keys}
:update ->
update = primary_action_name!(relationship.destination, :update)
{:update, update}
:update_join ->
join_update = primary_action_name!(relationship.through, :update)
{:update, nil, join_update, join_keys}
{:update_join, join_update} ->
{:update, nil, join_update, join_keys}
{:update_join, join_update, join_keys} ->
{:update, nil, join_update, join_keys}
:unrelate when is_many_to_many ->
join_destroy = primary_action_name!(relationship.through, :destroy)
{:unrelate, join_destroy}
:unrelate when relationship.type in [:has_many, :has_one] ->
update = primary_action_name!(relationship.destination, :update)
{:unrelate, update}
:unrelate ->
{:unrelate, nil}
:destroy when is_many_to_many ->
join_destroy = primary_action_name!(relationship.through, :destroy)
{:destroy, join_destroy}
:destroy ->
destroy = primary_action_name!(relationship.destination, :destroy)
{:destroy, destroy}
other ->
other
end)
|> Keyword.update!(:on_lookup, fn
key when is_many_to_many and key in [:relate, :relate_and_update] ->
join_create = primary_action_name!(relationship.through, :create)
read = primary_action_name!(relationship.destination, :read)
{key, join_create, read, join_keys}
{key, join_create} when is_many_to_many and key in [:relate, :relate_and_update] ->
read = primary_action_name!(relationship.destination, :read)
{key, join_create, read, join_keys}
{key, join_create, read} when is_many_to_many and key in [:relate, :relate_and_update] ->
{key, join_create, read, join_keys}
key
when relationship.type in [:has_many, :has_one] and key in [:relate, :relate_and_update] ->
update = primary_action_name!(relationship.destination, :update)
read = primary_action_name!(relationship.destination, :read)
{key, update, read}
key when key in [:relate, :relate_and_update] ->
read = primary_action_name!(relationship.destination, :read)
{key, nil, read}
{key, update} when key in [:relate, :relate_and_update] ->
read = primary_action_name!(relationship.destination, :read)
{key, update, read}
other ->
other
end)
end
def on_match_destination_actions(opts, relationship) do
opts = sanitize_opts(relationship, opts)
case opts[:on_match] do
key when key in [:ignore, :error] ->
nil
:no_match ->
on_no_match_destination_actions(opts, relationship)
:missing ->
on_missing_destination_actions(opts, relationship)
{:update, update, join_update, join_keys} ->
all([destination(update), join(join_update, join_keys)])
{:update, update} ->
all(destination(update))
{:unrelate, join_destroy} when relationship.type == :many_to_many ->
all(join(join_destroy, :all))
{:unrelate, update} when relationship.type in [:has_one, :has_many] ->
all(destination(update))
{:unrelate, _nil} ->
nil
{:destroy, join_destroy} when relationship.type == :many_to_many ->
all(join(join_destroy, :all))
{:destroy, destroy} ->
all(destination(destroy))
end
end
def on_no_match_destination_actions(opts, relationship) do
opts = sanitize_opts(relationship, opts)
case opts[:on_no_match] do
key when key in [:ignore, :error] ->
nil
:match ->
on_match_destination_actions(opts, relationship)
{:create, create, join_create, join_keys} ->
all([destination(create), join(join_create, join_keys)])
{:create, create} ->
all(destination(create))
end
end
def on_missing_destination_actions(opts, relationship) do
opts = sanitize_opts(relationship, opts)
case opts[:on_missing] do
key when key in [:ignore, :error] ->
nil
{:unrelate, join_destroy} when relationship.type == :many_to_many ->
all(join(join_destroy, []))
{:unrelate, update} when relationship.type in [:has_one, :has_many] ->
all(destination(update))
{:unrelate, _nil} ->
nil
{:destroy, destroy, join_destroy} ->
all([destination(destroy), join(join_destroy, [])])
{:destroy, destroy} ->
all(destination(destroy))
end
end
def on_lookup_update_action(opts, relationship) do
opts = sanitize_opts(relationship, opts)
case opts[:on_lookup] do
:ignore ->
nil
{key, join_create, _read, join_keys} when key in [:relate, :relate_and_update] ->
join(join_create, join_keys)
{key, update, _read}
when key in [:relate, :relate_and_update] and relationship.type in [:has_one, :has_many] ->
destination(update)
{key, _nil, _read} when key in [:relate, :relate_and_update] ->
nil
end
end
def on_lookup_read_action(opts, relationship) do
opts = sanitize_opts(relationship, opts)
case opts[:on_lookup] do
:ignore ->
nil
{key, _join_create, read, _join_keys} when key in [:relate, :relate_and_update] ->
destination(read)
{key, _update, read} when key in [:relate, :relate_and_update] ->
destination(read)
end
end
defp all(values) do
case Enum.filter(List.wrap(values), & &1) do
[] -> nil
values -> values
end
end
defp destination(nil), do: nil
defp destination(action), do: {:destination, action}
defp join(nil, _), do: nil
defp join(action, keys), do: {:join, action, keys}
def could_handle_missing?(opts) do
opts[:on_missing] not in [:ignore, :error]
end
def could_lookup?(opts) do
opts[:on_lookup] != :ignore
end
def could_create?(opts) do
unwrap(opts[:on_no_match]) == :create || opts[:on_match] == :no_match
end
def could_update?(opts) do
opts[:on_match] not in [:ignore, :no_match, :missing]
end
def must_load?(opts, must_load_opts \\ []) do
creating_and_cant_have_related? =
must_load_opts[:could_be_related_at_creation?] == false &&
must_load_opts[:action_type] == :create
allowed_on_no_match_values =
if creating_and_cant_have_related? do
[:create, :ignore, :error]
else
[:create, :ignore]
end
only_creates_or_ignores? =
creating_and_cant_have_related? ||
(opts[:on_match] in [:no_match, :ignore] &&
unwrap(opts[:on_no_match]) in allowed_on_no_match_values)
on_missing_can_skip_load? =
if must_load_opts[:could_be_related_at_creation?] == false &&
must_load_opts[:action_type] == :create do
true
else
opts[:on_missing] == :ignore
end
can_skip_load? = on_missing_can_skip_load? && only_creates_or_ignores?
not can_skip_load?
end
defp primary_action_name!(resource, type) do
Ash.Resource.Info.primary_action!(resource, type).name
end
defp unwrap(value) when is_atom(value), do: value
defp unwrap(tuple) when is_tuple(tuple), do: elem(tuple, 0)
defp unwrap(value), do: value
end