Packages
ash_phoenix
2.1.22
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.ex
defmodule AshPhoenix do
@moduledoc """
An extension to add form builders to the code interface.
There is currently no DSL for this extension.
This defines a `form_to_<name>` function for each code interface
function. Positional arguments are ignored, given that in forms,
all input typically comes from the `params` map.
The generated function passes all options through to
`AshPhoenix.Form.for_action/3`
Update and destroy actions take the record being updated/destroyed
as the first argument.
For example, given this code interface definition on a domain
called `MyApp.Accounts`:
```elixir
resources do
resource MyApp.Accounts.User do
define :register_with_password, args: [:email, :password]
define :update_user, action: :update, args: [:email, :password]
end
end
```
Adding the `AshPhoenix` extension would define
`form_to_register_with_password/2`.
## Usage
Without options:
```elixir
MyApp.Accounts.form_to_register_with_password()
#=> %AshPhoenix.Form{}
```
With options:
```elixir
MyApp.Accounts.form_to_register_with_password(params: %{"email" => "placeholder@email"})
#=> %AshPhoenix.Form{}
```
With
```elixir
MyApp.Accounts.form_to_update_user(params: %{"email" => "placeholder@email"})
#=> %AshPhoenix.Form{}
```
"""
defmodule AddFormCodeInterfaces do
@moduledoc false
use Spark.Dsl.Transformer
def after?(_), do: true
def transform(dsl_state) do
case Ash.Domain.Info.resource_references(dsl_state) do
[] ->
resource = Spark.Dsl.Transformer.get_persisted(dsl_state, :module)
dsl_state
|> Ash.Resource.Info.interfaces()
|> Enum.filter(&match?(%Ash.Resource.Interface{}, &1))
|> Enum.uniq_by(& &1.name)
|> Enum.reduce(dsl_state, &add_form_interface(&1, &2, resource, true))
|> then(&{:ok, &1})
references ->
references
|> Enum.reduce(dsl_state, fn reference, dsl_state ->
reference.definitions
|> Enum.filter(&match?(%Ash.Resource.Interface{}, &1))
|> Enum.uniq_by(& &1.name)
|> Enum.reduce(dsl_state, &add_form_interface(&1, &2, reference.resource))
end)
|> then(&{:ok, &1})
end
end
# sobelow_skip ["DOS.BinToAtom"]
defp add_form_interface(interface, dsl_state, resource, resource? \\ false) do
name = :"form_to_#{interface.name}"
action =
if resource? do
Ash.Resource.Info.action(dsl_state, interface.action || interface.name)
else
Ash.Resource.Info.action(resource, interface.action || interface.name)
end
cond do
!action ->
dsl_state
action.type in [:update, :destroy] and interface.require_reference? ->
define =
quote do
@doc """
#{unquote(action.description) || "Creates a form for the #{unquote(action.name)} action on #{unquote(inspect(resource))}."}
## Options
#{Spark.Options.docs(AshPhoenix.Form.for_opts())}
Any *additional* options will be passed to the underlying call to build the source, i.e
`Ash.ActionInput.for_action/4`, or `Ash.Changeset.for_*`. This means you can set things
like the tenant/actor. These will be retained, and provided again when
`Form.submit/3` is called.
## Nested Form Options
#{Spark.Options.docs(AshPhoenix.Form.nested_form_opts())}
"""
|> Ash.CodeInterface.trim_double_newlines()
def unquote(name)(record, opts \\ []) do
AshPhoenix.Form.for_action(record, unquote(action.name), opts)
end
end
Spark.Dsl.Transformer.eval(dsl_state, [], define)
true ->
define =
quote do
@doc """
#{unquote(action.description) || "Creates a form for the #{unquote(action.name)} action on #{unquote(inspect(resource))}."}
## Options
#{Spark.Options.docs(AshPhoenix.Form.for_opts())}
Any *additional* options will be passed to the underlying call to build the source, i.e
`Ash.ActionInput.for_action/4`, or `Ash.Changeset.for_*`. This means you can set things
like the tenant/actor. These will be retained, and provided again when
`Form.submit/3` is called.
## Nested Form Options
#{Spark.Options.docs(AshPhoenix.Form.nested_form_opts())}
"""
|> Ash.CodeInterface.trim_double_newlines()
def unquote(name)(opts \\ []) do
AshPhoenix.Form.for_action(unquote(resource), unquote(action.name), opts)
end
end
Spark.Dsl.Transformer.eval(dsl_state, [], define)
end
end
end
use Spark.Dsl.Extension, transformers: [AddFormCodeInterfaces]
end