Reactor.Builder (reactor v0.12.1)

View Source

Build a new Reactor programmatically.

You don't have to use the Reactor DSL to create a Reactor. The functions in this module allow you to define a Reactor programmatically. This is especially useful if you need to create a reactor dynamically (maybe based on a UI such as React Flow).

Example

reactor = Builder.new()
{:ok, reactor} = Builder.add_input(reactor, :name)
argument = Argument.from_input(:name)
{:ok, reactor} = Builder.add_step(reactor, :greet, [argument])
{:ok, reactor} = Builder.return(reactor, :greet)

Summary

Types

Optionally transform all the arguments into new arguments

Should the step be run asynchronously?

Optional context which will be merged with the reactor context when calling this step.

An optional step description

How many times is the step allowed to retry?

Functions

Add a named input to the Reactor.

Raising version of add_input/2..3.

Add a middleware to the Reactor.

Ensure that a middleware is present on the Reactor.

Build a new, empty Reactor.

Build a step which can be added to a reactor at runtime.

Raising version of new_step/2..4.

Specify the return value of the Reactor.

Raising version of return/2.

Types

arguments_transform()

@type arguments_transform() ::
  {:transform,
   nil
   | (%{optional(atom()) => any()} -> %{optional(atom()) => any()})
   | {module() | keyword()}
   | mfa()}

Optionally transform all the arguments into new arguments

async?()

@type async?() :: {:async?, boolean() | (keyword() -> boolean())}

Should the step be run asynchronously?

context()

@type context() :: Reactor.context()

Optional context which will be merged with the reactor context when calling this step.

description()

@type description() :: nil | String.t()

An optional step description

guards()

@type guards() :: {:guards, [Reactor.Guard.Build.t()]}

impl()

@type impl() :: module() | {module(), keyword()}

max_retries()

@type max_retries() :: {:max_retries, :infinity | non_neg_integer()}

How many times is the step allowed to retry?

ref()

@type ref() :: {:ref, :step_name | :make_ref}

step_argument()

@type step_argument() :: Reactor.Argument.t() | {atom(), {:input | :result, any()}}

step_options()

@type step_options() :: [
  async?()
  | description()
  | guards()
  | max_retries()
  | arguments_transform()
  | context()
  | ref()
]

Functions

add_input(reactor, name, transform \\ nil)

@spec add_input(Reactor.t(), any(), nil | (any() -> any())) ::
  {:ok, Reactor.t()} | {:error, any()}

Add a named input to the Reactor.

This both places the input in the Reactor for later input validation and adds steps to the Reactor which will emit and (possibly) transform the input.

add_input!(reactor, name, transform \\ nil)

@spec add_input!(Reactor.t(), any(), nil | (any() -> any())) ::
  Reactor.t() | no_return()

Raising version of add_input/2..3.

add_middleware(reactor, middleware)

@spec add_middleware(Reactor.t(), Reactor.Middleware.t()) ::
  {:ok, Reactor.t()} | {:error, any()}

Add a middleware to the Reactor.

Returns an error if the middleware is already present on the Reactor.

add_middleware!(reactor, middleware)

@spec add_middleware!(Reactor.t(), Reactor.Middleware.t()) ::
  Reactor.t() | no_return()

Raising version of add_middleware/2.

add_step(reactor, name, impl, arguments \\ [], options \\ [])

@spec add_step(
  Reactor.t(),
  name :: any(),
  impl(),
  [step_argument()],
  step_options()
) :: {:ok, Reactor.t()} | {:error, any()}

Add a step to the Reactor.

Add a new step to the Reactor. Rewrites input arguments to use the result of the input steps and injects transformation steps as required.

add_step!(reactor, name, impl, arguments \\ [], options \\ [])

@spec add_step!(Reactor.t(), name :: any(), impl(), [step_argument()], step_options()) ::
  Reactor.t() | no_return()

Raising version of add_step/3..5.

compose(reactor, name, inner_reactor, arguments \\ [], options \\ [])

@spec compose(
  Reactor.t(),
  atom(),
  Reactor.t() | module(),
  [step_argument()],
  Keyword.t()
) ::
  {:ok, Reactor.t()} | {:error, any()}

Compose another Reactor inside this one.

Whenever possible this function will extract the steps from inner Reactor and place them inside the parent Reactor. In order to achieve this the composer will rename the steps to ensure that there are no conflicts.

If you're attempting to create a recursive Reactor (ie compose a Reactor within itself) then this will be detected and runtime composition will be used instead. See Reactor.Step.Compose for more details.

compose!(reactor, name, inner_reactor, arguments, options \\ [])

@spec compose!(
  Reactor.t(),
  atom(),
  Reactor.t() | module(),
  [step_argument()],
  Keyword.t()
) ::
  Reactor.t() | no_return()

Raising version of compose/4.

ensure_middleware(reactor, middleware)

@spec ensure_middleware(Reactor.t(), Reactor.Middleware.t()) ::
  {:ok, Reactor.t()} | {:error, any()}

Ensure that a middleware is present on the Reactor.

ensure_middleware!(reactor, middleware)

@spec ensure_middleware!(Reactor.t(), Reactor.Middleware.t()) ::
  Reactor.t() | no_return()

Raising version of ensure_middleware/2.

new(id \\ make_ref())

@spec new(any()) :: Reactor.t()

Build a new, empty Reactor.

Optionally an identifier for the Reactor. This is primarily used for recursive composition tracking.

new_step(name, impl, arguments \\ [], options \\ [])

@spec new_step(any(), impl(), [step_argument()], step_options()) ::
  {:ok, Reactor.Step.t()} | {:error, any()}

Build a step which can be added to a reactor at runtime.

Note that the built step doesn't support transformations - you should add an additional step to do the transformation needed (this is what add_step/5 does anyway).

new_step!(name, impl, arguments \\ [], options \\ [])

@spec new_step!(any(), impl(), [step_argument()], step_options()) ::
  Reactor.Step.t() | no_return()

Raising version of new_step/2..4.

return(reactor, name)

@spec return(Reactor.t(), any()) :: {:ok, Reactor.t()} | {:error, any()}

Specify the return value of the Reactor.

The return value must be the name of a step.

return!(reactor, name)

@spec return!(Reactor.t(), any()) :: Reactor.t() | no_return()

Raising version of return/2.