View Source Commanded.Aggregate.Multi (Commanded v1.4.6)

Use Commanded.Aggregate.Multi to generate multiple events from a single command.

This can be useful when you want to emit multiple events that depend upon the aggregate state being updated.

Example

In the example below, money is withdrawn from the bank account and the updated balance is used to check whether the account is overdrawn.

defmodule BankAccount do
  alias Commanded.Aggregate.Multi

  defstruct [:account_number, :state, balance: 0]

  def withdraw(
    %BankAccount{state: :active} = account,
    %WithdrawMoney{amount: amount})
    when is_number(amount) and amount > 0
  do
    account
    |> Multi.new()
    |> Multi.execute(&withdraw_money(&1, amount))
    |> Multi.execute(&check_balance/1)
  end

  defp withdraw_money(%BankAccount{account_number: account_number, balance: balance}, amount) do
    %MoneyWithdrawn{
      account_number: account_number,
      amount: amount,
      balance: balance - amount
    }
  end

  defp check_balance(%BankAccount{account_number: account_number, balance: balance})
    when balance < 0
  do
    %AccountOverdrawn{account_number: account_number, balance: balance}
  end
  defp check_balance(%BankAccount{}), do: []
end

Summary

Functions

Adds a command execute function to the multi.

Reduce an enumerable by executing the function for each item.

Run the execute functions contained within the multi, returning the updated aggregate state, the aggregate state for each named step and all created events.

Types

@type t() :: %Commanded.Aggregate.Multi{
  aggregate: struct(),
  executions: [{step_name :: atom(), function()}]
}

Functions

Link to this function

execute(multi, step_name \\ false, execute_fun)

View Source
@spec execute(t(), atom(), function()) :: t()

Adds a command execute function to the multi.

If step_name is provided, the aggregate state after that step is stored under that name. That can be useful in a long multi step multi in which one needs to know what was the agg state while procesisng the multi. It's possible, then, to pattern match the step name in the second parameter of the anonymous function to be executed.

Example

alias Commanded.Aggregate.Multi

aggregate
|> Multi.new()
|> Multi.execute(:interesting_event, fn aggregate ->
  %Event{data: 1}
end)
|> Multi.execute(fn aggregate, %{interesting_event: aggregate_state_after_interesting_event} ->
  %Event{data: 2}
end)
@spec new(aggregate :: struct()) :: t()

Create a new Commanded.Aggregate.Multi struct.

Link to this function

reduce(multi, step_name \\ false, enumerable, execute_fun)

View Source
@spec reduce(t(), atom(), Enum.t(), function()) :: t()

Reduce an enumerable by executing the function for each item.

The aggregate apply/2 function will be called after each event returned by the execute function. This allows you to calculate values from the aggregate state based upon events produced by previous items in the enumerable, such as running totals.

If step_name is provided, the aggregate state after that step will be stored under that name. That can be useful in a long multi step multi in which one needs to know what was the agg state while procesisng the multi. It's possible, then, to pattern match the step name in the third parameter of the anonymous function to be executed.

Examples

alias Commanded.Aggregate.Multi

aggregate
|> Multi.new()
|> Multi.reduce([1, 2, 3], fn aggregate, item ->
  %AnEvent{item: item, total: aggregate.total + item}
end)

Example with named steps

alias Commanded.Aggregate.Multi

aggregate
|> Multi.new()
|> Multi.execute(:first, fn aggregate ->
  %AnEvent{item: nil, total: 0}
end)
|> Multi.reduce(:second, [1, 2, 3], fn aggregate, item ->
  %AnEvent{item: item, total: aggregate.total + item}
end)
|> Multi.reduce([4, 5, 6], fn aggregate, item, steps ->
   %{
     first: aggregate_state_after_first_event,
     second: aggregate_state_after_second_event
   } = steps

    %AnEvent{item: item, total: aggregate.total + item}
end)
@spec run(t()) ::
  {aggregate :: struct(), [event :: struct()]} | {:error, reason :: any()}

Run the execute functions contained within the multi, returning the updated aggregate state, the aggregate state for each named step and all created events.