ash/documentation/dsls/DSL:-Ash.Reactor.md
James Harton 86d74ed789
feat(Ash.Reactor): Add a Reactor extension that makes working with resources easy. (#683)
* feat: Add `Ash.Reactor` with create support.

* improvement: Add `Ash.Reactor` update support.

* improvement: Add `Ash.Reactor` destroy support.

* improvement(Ash.Reactor): Support for transactional handling of notifications.

* improvement(Ash.Reactor): Add `read` and `get` steps.

* docs: Add the beginnings of a Reactor topic.

* improvement(Ash.Reactor): add support for generic actions.

* improvement: Add `undo` capability to `create` step.

* improvement: transaction and undo working.

* docs: Start documenting undo behaviour.

* chore: Update to Reactor 0.6.

* improvement: Automatically thread Ash tracers through Reactor.

* improvement(Ash.Reactor): Add undo to generic actions.

* docs: Improve reactor documentation.

* fix: Mimic copying `Ash.Notifier` seems to break the compiler for some reason.
2024-03-02 10:26:25 +13:00

34 KiB

DSL: Ash.Reactor

Ash.Reactor is a Reactor extension which provides steps for working with Ash resources and actions.

See the Ash Reactor Guide for more information.

ash

Ash-related configuration for the Ash.Reactor extension

Options

Name Type Default Docs
default_api{: #ash-default_api } module An API to use by default when calling actions

reactor.action

action name, resource, action \\ nil

Declares a step that will call a generic action on a resource.

Nested DSLs

Arguments

Name Type Default Docs
name{: #reactor-action-name .spark-required} atom A unique name for the step. This is used when choosing the return value of the Reactor and for arguments into other steps.
resource{: #reactor-action-resource .spark-required} module The resource to call the action on.
action{: #reactor-action-action } atom The name of the action to call on the resource.

Options

Name Type Default Docs
api{: #reactor-action-api } module The API to use when calling the action. Defaults to the API set in the ash section.
async?{: #reactor-action-async? } boolean true When set to true the step will be executed asynchronously via Reactor's TaskSupervisor.
authorize?{: #reactor-action-authorize? } boolean | nil Explicitly enable or disable authorization for the action.
description{: #reactor-action-description } String.t A description for the step
undo_action{: #reactor-action-undo_action } atom The name of the action to call on the resource when the step is to be undone.
undo{: #reactor-action-undo } :always | :never | :outside_transaction :never What to do when the reactor is undoing it's work? * always - The undo action will always be run. * never - The action will never be undone. * outside_transaction - The action will only be undone if not running inside a transaction.

reactor.action.actor

actor source

Specifies the action actor

Arguments

Name Type Default Docs
source{: #reactor-action-actor-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the actor. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-action-actor-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the actor before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Actor

reactor.action.inputs

inputs template

Specify the inputs for an action

Examples

inputs %{
  author: result(:get_user),
  title: input(:title),
  body: input(:body)
}

inputs(author: result(:get_user))

Arguments

Name Type Default Docs
template{: #reactor-action-inputs-template .spark-required} %{optional(atom) => Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value} | keyword(Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value)

Options

Name Type Default Docs
transform{: #reactor-action-inputs-transform } (any -> any) | module | nil An optional transformation function which will transform the inputs before executing the action.

Introspection

Target: Ash.Reactor.Dsl.Inputs

reactor.action.tenant

tenant source

Specifies the action tenant

Arguments

Name Type Default Docs
source{: #reactor-action-tenant-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the tenant. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-action-tenant-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the tenant before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Tenant

reactor.action.wait_for

wait_for names

Wait for the named step to complete before allowing this one to start.

Desugars to argument :_, result(step_to_wait_for)

Examples

wait_for :create_user

Arguments

Name Type Default Docs
names{: #reactor-action-wait_for-names .spark-required} atom | list(atom) The name of the step to wait for.

Introspection

Target: Reactor.Dsl.WaitFor

Introspection

Target: Ash.Reactor.Dsl.Action

reactor.create

create name, resource, action \\ nil

Declares a step that will call a create action on a resource.

Nested DSLs

Examples

create :create_post, MyApp.Post, :create do
  inputs %{
    title: input(:post_title),
    author_id: result(:get_user, [:id])
  }
  actor result(:get_user)
  tenant result(:get_organisation, [:id])
end

Arguments

Name Type Default Docs
name{: #reactor-create-name .spark-required} atom A unique name for the step. This is used when choosing the return value of the Reactor and for arguments into other steps.
resource{: #reactor-create-resource .spark-required} module The resource to call the action on.
action{: #reactor-create-action } atom The name of the action to call on the resource.

Options

Name Type Default Docs
api{: #reactor-create-api } module The API to use when calling the action. Defaults to the API set in the ash section.
async?{: #reactor-create-async? } boolean true When set to true the step will be executed asynchronously via Reactor's TaskSupervisor.
authorize?{: #reactor-create-authorize? } boolean | nil Explicitly enable or disable authorization for the action.
description{: #reactor-create-description } String.t A description for the step
undo_action{: #reactor-create-undo_action } atom The name of the action to call on the resource when the step is to be undone.
undo{: #reactor-create-undo } :always | :never | :outside_transaction :never What to do when the reactor is undoing it's work? * always - The undo action will always be run. * never - The action will never be undone. * outside_transaction - The action will only be undone if not running inside a transaction.
upsert_identity{: #reactor-create-upsert_identity } atom The identity to use for the upsert
upsert?{: #reactor-create-upsert? } boolean false Whether or not this action should be executed as an upsert.

reactor.create.actor

actor source

Specifies the action actor

Arguments

Name Type Default Docs
source{: #reactor-create-actor-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the actor. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-create-actor-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the actor before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Actor

reactor.create.inputs

inputs template

Specify the inputs for an action

Examples

inputs %{
  author: result(:get_user),
  title: input(:title),
  body: input(:body)
}

inputs(author: result(:get_user))

Arguments

Name Type Default Docs
template{: #reactor-create-inputs-template .spark-required} %{optional(atom) => Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value} | keyword(Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value)

Options

Name Type Default Docs
transform{: #reactor-create-inputs-transform } (any -> any) | module | nil An optional transformation function which will transform the inputs before executing the action.

Introspection

Target: Ash.Reactor.Dsl.Inputs

reactor.create.tenant

tenant source

Specifies the action tenant

Arguments

Name Type Default Docs
source{: #reactor-create-tenant-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the tenant. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-create-tenant-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the tenant before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Tenant

reactor.create.wait_for

wait_for names

Wait for the named step to complete before allowing this one to start.

Desugars to argument :_, result(step_to_wait_for)

Examples

wait_for :create_user

Arguments

Name Type Default Docs
names{: #reactor-create-wait_for-names .spark-required} atom | list(atom) The name of the step to wait for.

Introspection

Target: Reactor.Dsl.WaitFor

Introspection

Target: Ash.Reactor.Dsl.Create

reactor.destroy

destroy name, resource, action \\ nil

Declares a step that will call a destroy action on a resource.

Nested DSLs

Examples

destroy :delete_post, MyApp.Post, :destroy do
  initial input(:post)
  actor result(:get_user)
  tenant result(:get_organisation, [:id])
end

Arguments

Name Type Default Docs
name{: #reactor-destroy-name .spark-required} atom A unique name for the step. This is used when choosing the return value of the Reactor and for arguments into other steps.
resource{: #reactor-destroy-resource .spark-required} module The resource to call the action on.
action{: #reactor-destroy-action } atom The name of the action to call on the resource.

Options

Name Type Default Docs
initial{: #reactor-destroy-initial .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value The record to update.
api{: #reactor-destroy-api } module The API to use when calling the action. Defaults to the API set in the ash section.
async?{: #reactor-destroy-async? } boolean true When set to true the step will be executed asynchronously via Reactor's TaskSupervisor.
authorize?{: #reactor-destroy-authorize? } boolean | nil Explicitly enable or disable authorization for the action.
description{: #reactor-destroy-description } String.t A description for the step
return_destroyed?{: #reactor-destroy-return_destroyed? } boolean false Whether or not the step should return the destroyed record upon completion.
undo_action{: #reactor-destroy-undo_action } atom The name of the action to call on the resource when the step is undone.
undo{: #reactor-destroy-undo } :always | :never | :outside_transaction :never What to do when the reactor is undoing it's work? * always - The undo action will always be run. * never - The action will never be undone. * outside_transaction - The action will only be undone if not running inside a transaction.

reactor.destroy.actor

actor source

Specifies the action actor

Arguments

Name Type Default Docs
source{: #reactor-destroy-actor-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the actor. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-destroy-actor-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the actor before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Actor

reactor.destroy.inputs

inputs template

Specify the inputs for an action

Examples

inputs %{
  author: result(:get_user),
  title: input(:title),
  body: input(:body)
}

inputs(author: result(:get_user))

Arguments

Name Type Default Docs
template{: #reactor-destroy-inputs-template .spark-required} %{optional(atom) => Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value} | keyword(Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value)

Options

Name Type Default Docs
transform{: #reactor-destroy-inputs-transform } (any -> any) | module | nil An optional transformation function which will transform the inputs before executing the action.

Introspection

Target: Ash.Reactor.Dsl.Inputs

reactor.destroy.tenant

tenant source

Specifies the action tenant

Arguments

Name Type Default Docs
source{: #reactor-destroy-tenant-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the tenant. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-destroy-tenant-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the tenant before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Tenant

reactor.destroy.wait_for

wait_for names

Wait for the named step to complete before allowing this one to start.

Desugars to argument :_, result(step_to_wait_for)

Examples

wait_for :create_user

Arguments

Name Type Default Docs
names{: #reactor-destroy-wait_for-names .spark-required} atom | list(atom) The name of the step to wait for.

Introspection

Target: Reactor.Dsl.WaitFor

Introspection

Target: Ash.Reactor.Dsl.Destroy

reactor.get

get name, resource, action \\ nil

Declares a step that will call a read action on a resource retuning a single record.

Nested DSLs

Examples

get :post_by_id, MyApp.Post, :read do
  inputs %{id: input(:post_id)}
end

Arguments

Name Type Default Docs
name{: #reactor-get-name .spark-required} atom A unique name for the step. This is used when choosing the return value of the Reactor and for arguments into other steps.
resource{: #reactor-get-resource .spark-required} module The resource to call the action on.
action{: #reactor-get-action } atom The name of the action to call on the resource.

Options

Name Type Default Docs
api{: #reactor-get-api } module The API to use when calling the action. Defaults to the API set in the ash section.
async?{: #reactor-get-async? } boolean true When set to true the step will be executed asynchronously via Reactor's TaskSupervisor.
authorize?{: #reactor-get-authorize? } boolean | nil Explicitly enable or disable authorization for the action.
description{: #reactor-get-description } String.t A description for the step
fail_on_not_found?{: #reactor-get-fail_on_not_found? } boolean false When set to true the step will fail if the resource is not found.

reactor.get.actor

actor source

Specifies the action actor

Arguments

Name Type Default Docs
source{: #reactor-get-actor-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the actor. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-get-actor-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the actor before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Actor

reactor.get.inputs

inputs template

Specify the inputs for an action

Examples

inputs %{
  author: result(:get_user),
  title: input(:title),
  body: input(:body)
}

inputs(author: result(:get_user))

Arguments

Name Type Default Docs
template{: #reactor-get-inputs-template .spark-required} %{optional(atom) => Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value} | keyword(Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value)

Options

Name Type Default Docs
transform{: #reactor-get-inputs-transform } (any -> any) | module | nil An optional transformation function which will transform the inputs before executing the action.

Introspection

Target: Ash.Reactor.Dsl.Inputs

reactor.get.tenant

tenant source

Specifies the action tenant

Arguments

Name Type Default Docs
source{: #reactor-get-tenant-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the tenant. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-get-tenant-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the tenant before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Tenant

reactor.get.wait_for

wait_for names

Wait for the named step to complete before allowing this one to start.

Desugars to argument :_, result(step_to_wait_for)

Examples

wait_for :create_user

Arguments

Name Type Default Docs
names{: #reactor-get-wait_for-names .spark-required} atom | list(atom) The name of the step to wait for.

Introspection

Target: Reactor.Dsl.WaitFor

Introspection

Target: Ash.Reactor.Dsl.Get

reactor.read

read name, resource, action \\ nil

Declares a step that will call a read action on a resource.

Nested DSLs

Examples

read :read_posts, MyApp.Post, :read

read :read_posts_in_range, MyApp.Post, :read_in_range do
  inputs %{min_date: input(:min_date), max_date: input(:max_date)}
end

Arguments

Name Type Default Docs
name{: #reactor-read-name .spark-required} atom A unique name for the step. This is used when choosing the return value of the Reactor and for arguments into other steps.
resource{: #reactor-read-resource .spark-required} module The resource to call the action on.
action{: #reactor-read-action } atom The name of the action to call on the resource.

Options

Name Type Default Docs
api{: #reactor-read-api } module The API to use when calling the action. Defaults to the API set in the ash section.
async?{: #reactor-read-async? } boolean true When set to true the step will be executed asynchronously via Reactor's TaskSupervisor.
authorize?{: #reactor-read-authorize? } boolean | nil Explicitly enable or disable authorization for the action.
description{: #reactor-read-description } String.t A description for the step

reactor.read.actor

actor source

Specifies the action actor

Arguments

Name Type Default Docs
source{: #reactor-read-actor-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the actor. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-read-actor-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the actor before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Actor

reactor.read.inputs

inputs template

Specify the inputs for an action

Examples

inputs %{
  author: result(:get_user),
  title: input(:title),
  body: input(:body)
}

inputs(author: result(:get_user))

Arguments

Name Type Default Docs
template{: #reactor-read-inputs-template .spark-required} %{optional(atom) => Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value} | keyword(Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value)

Options

Name Type Default Docs
transform{: #reactor-read-inputs-transform } (any -> any) | module | nil An optional transformation function which will transform the inputs before executing the action.

Introspection

Target: Ash.Reactor.Dsl.Inputs

reactor.read.tenant

tenant source

Specifies the action tenant

Arguments

Name Type Default Docs
source{: #reactor-read-tenant-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the tenant. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-read-tenant-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the tenant before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Tenant

reactor.read.wait_for

wait_for names

Wait for the named step to complete before allowing this one to start.

Desugars to argument :_, result(step_to_wait_for)

Examples

wait_for :create_user

Arguments

Name Type Default Docs
names{: #reactor-read-wait_for-names .spark-required} atom | list(atom) The name of the step to wait for.

Introspection

Target: Reactor.Dsl.WaitFor

Introspection

Target: Ash.Reactor.Dsl.Read

reactor.transaction

transaction name, resources

Creates a group of steps which will be executed inside a data layer transaction.

Nested DSLs

Arguments

Name Type Default Docs
name{: #reactor-transaction-name .spark-required} atom A unique name for the step. This is used when choosing the return value of the Reactor and for arguments into other steps.
resources{: #reactor-transaction-resources .spark-required} module | list(module) A resource or list of resources to consider in the transaction.

Options

Name Type Default Docs
return{: #reactor-transaction-return } atom The name of the step whose result will be returned as the return value of the transaction.
timeout{: #reactor-transaction-timeout } pos_integer | :infinity 15000 How long to allow the transaction to run before timing out.

reactor.transaction.wait_for

wait_for names

Wait for the named step to complete before allowing this one to start.

Desugars to argument :_, result(step_to_wait_for)

Examples

wait_for :create_user

Arguments

Name Type Default Docs
names{: #reactor-transaction-wait_for-names .spark-required} atom | list(atom) The name of the step to wait for.

Introspection

Target: Reactor.Dsl.WaitFor

Introspection

Target: Ash.Reactor.Dsl.Transaction

reactor.update

update name, resource, action \\ nil

Declares a step that will call an update action on a resource.

Nested DSLs

Examples

update :publish_post, MyApp.Post, :update do
  initial input(:post)
  inputs %{
    published: value(true)
  }
  actor result(:get_user)
  tenant result(:get_organisation, [:id])
end

Arguments

Name Type Default Docs
name{: #reactor-update-name .spark-required} atom A unique name for the step. This is used when choosing the return value of the Reactor and for arguments into other steps.
resource{: #reactor-update-resource .spark-required} module The resource to call the action on.
action{: #reactor-update-action } atom The name of the action to call on the resource.

Options

Name Type Default Docs
initial{: #reactor-update-initial .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value The record to update.
api{: #reactor-update-api } module The API to use when calling the action. Defaults to the API set in the ash section.
async?{: #reactor-update-async? } boolean true When set to true the step will be executed asynchronously via Reactor's TaskSupervisor.
authorize?{: #reactor-update-authorize? } boolean | nil Explicitly enable or disable authorization for the action.
description{: #reactor-update-description } String.t A description for the step
undo_action{: #reactor-update-undo_action } atom The name of the action to call on the resource when the step is undone.
undo{: #reactor-update-undo } :always | :never | :outside_transaction :never What to do when the reactor is undoing it's work? * always - The undo action will always be run. * never - The action will never be undone. * outside_transaction - The action will only be undone if not running inside a transaction.

reactor.update.actor

actor source

Specifies the action actor

Arguments

Name Type Default Docs
source{: #reactor-update-actor-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the actor. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-update-actor-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the actor before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Actor

reactor.update.inputs

inputs template

Specify the inputs for an action

Examples

inputs %{
  author: result(:get_user),
  title: input(:title),
  body: input(:body)
}

inputs(author: result(:get_user))

Arguments

Name Type Default Docs
template{: #reactor-update-inputs-template .spark-required} %{optional(atom) => Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value} | keyword(Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value)

Options

Name Type Default Docs
transform{: #reactor-update-inputs-transform } (any -> any) | module | nil An optional transformation function which will transform the inputs before executing the action.

Introspection

Target: Ash.Reactor.Dsl.Inputs

reactor.update.tenant

tenant source

Specifies the action tenant

Arguments

Name Type Default Docs
source{: #reactor-update-tenant-source .spark-required} Reactor.Template.Input | Reactor.Template.Result | Reactor.Template.Value What to use as the source of the tenant. See Reactor.Dsl.Argument for more information.

Options

Name Type Default Docs
transform{: #reactor-update-tenant-transform } (any -> any) | module | nil An optional transformation function which can be used to modify the tenant before it is passed to the action.

Introspection

Target: Ash.Reactor.Dsl.Tenant

reactor.update.wait_for

wait_for names

Wait for the named step to complete before allowing this one to start.

Desugars to argument :_, result(step_to_wait_for)

Examples

wait_for :create_user

Arguments

Name Type Default Docs
names{: #reactor-update-wait_for-names .spark-required} atom | list(atom) The name of the step to wait for.

Introspection

Target: Reactor.Dsl.WaitFor

Introspection

Target: Ash.Reactor.Dsl.Update