View Source Reactor.Builder (reactor v0.9.0)

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.

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.

Compose another Reactor inside this one.

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

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

Optionally transform all the arguments into new arguments

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

Should the step be run asynchronously?

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

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

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

How many times is the step allowed to retry?

@type ref() :: {:ref, :step_name | :make_ref}
@type step_argument() :: Reactor.Argument.t() | {atom(), {:input | :result, any()}}
@type step_options() :: [
  async?() | max_retries() | arguments_transform() | context() | ref()
]

Functions

Link to this function

add_input(reactor, name, transform \\ nil)

View Source
@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.

Link to this function

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

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

Raising version of add_input/2..3.

Link to this function

add_middleware(reactor, middleware)

View Source
@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.

Link to this function

add_middleware!(reactor, middleware)

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

Raising version of add_middleware/2.

Link to this function

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

View Source
@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.

Link to this function

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

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

Raising version of add_step/3..5.

Link to this function

compose(reactor, name, inner_reactor, arguments)

View Source
@spec compose(Reactor.t(), atom(), Reactor.t() | module(), [step_argument()]) ::
  {: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.

Link to this function

compose!(reactor, name, inner_reactor, arguments)

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

Raising version of compose/4.

Link to this function

ensure_middleware(reactor, middleware)

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

Ensure that a middleware is present on the Reactor.

Link to this function

ensure_middleware!(reactor, middleware)

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

Raising version of ensure_middleware/2.

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

Build a new, empty Reactor.

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

Link to this function

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

View Source
@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).

Link to this function

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

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

Raising version of new_step/2..4.

@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.

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

Raising version of return/2.