Aggregate trait.
The aggregate root maintains our application’s internal state. This state is rebuilt by replaying events, and is used to validate incoming commands.
1. Defining the Aggregate Root Struct
Create your aggregate root struct. It should contain fields representing the internal state (such asbalance, owner, or id). The framework tracks the stream revision for you via LoadedAggregate:
2. Implementing the Aggregate Trait
Now, implement the Aggregate trait for the BankAccount struct. This binds all components together:
Important Rules of Aggregates
When implementing your own aggregates, always follow these rules:- Deterministic
apply: Theapplymethod is run every time your aggregate state is reconstituted from history. It must be completely deterministic, have no side effects, and only mutate fields. Never perform validations or log actions insideapply. - Stateless
handle: Thehandlemethod only reads from the reconstituted state to validate business rules and emit events. It must never mutate any fields of the aggregate directly. State mutation is deferred entirely toapply.
Aggregate trait:
- Decider:
Aggregate::handleis the decision function. It receives the current aggregate state plus a command, validates invariants, and returns the new events to persist or a domain error. - Evolver:
Aggregate::applyis the evolve function. It receives an event fact and mutates only in-memory aggregate state so replay can deterministically rebuild the current state.
handle and apply names for compatibility with existing users and generated code.