Mutations

A mutation is the rule that connects an event to a projection. It says: "when this event happens, change that field of the projection in this way". Mutations are declared through the dashboard — you don't need to write boilerplate event handlers.

Anatomy of a mutation

  • Trigger event — the event name (and optional version) that fires this mutation.
  • Target field — the projection field that should change.
  • Action — what to do (set, increment, append, etc.).
  • Source — where the new value comes from (event payload, a literal, an expression).
  • Filter (optional) — a condition the event must satisfy.

Built-in actions

  • Set — replace the field with a value.
  • Increment / Decrement — adjust numeric fields.
  • Append — add an item to a list field.
  • Remove — remove a matching item from a list.
  • Merge — deep-merge an object into a JSON field.
  • Compute — apply a small expression (e.g. totalAmount + event.amount).

Example: a basket summary

Projection BasketSummary with fields itemCount: Integer and total: Integer:

  • On ItemAddedToBasketIncrement itemCount by 1.
  • On ItemAddedToBasketCompute total = total + event.amount.
  • On ItemRemovedFromBasketDecrement itemCount by 1.
  • On BasketClearedSet itemCount = 0 and total = 0.

Custom mutation actions

You aren't limited to the built-ins. Through the extension API you can register a custom mutation action that runs inside the EventSourcerer server. This lets you encode domain-specific logic (e.g. tax calculation, currency conversion) once and reuse it across projections.

final class ApplyDiscount implements MutationAction
{
    public function name(): string { return 'apply_discount'; }

    public function apply(mixed $current, array $event, array $args): mixed
    {
        $rate = (float) ($args['rate'] ?? 0);
        return (int) round($current * (1 - $rate));
    }
}
Mutations execute in event order and are deterministic — the same events always produce the same projection state, which makes rebuilds safe and predictable.