Commands
Commands request a state change. They can be rejected.
Basic Usage
- Define a command struct
- Implement
Handle<C>on your aggregate - Return events or a domain error
#[derive(Debug)]
pub struct Deposit {
pub amount: i64,
}
impl Handle<Deposit> for Account {
fn handle(&self, cmd: &Deposit) -> Result<Vec<Self::Event>, Self::Error> {
if cmd.amount <= 0 {
return Err(AccountError::InvalidAmount);
}
Ok(vec![FundsDeposited { amount: cmd.amount }.into()])
}
}
Executing Commands
repository
.execute_command::<Account, Deposit>(&account_id, &Deposit { amount: 100 }, &metadata)
.await?;
Validation Patterns
- Reject invalid input (
Result::Err) - Emit one or more events when valid
- Return
vec![]for valid no-op commands
if cmd.amount == 0 {
return Ok(vec![]);
}
Trait Reference
The Handle<C> Trait
pub trait Handle<C>: Aggregate {
/// Handle a command and produce events.
///
/// # Errors
///
/// Returns `Self::Error` if the command is invalid for the current
/// aggregate state.
fn handle(&self, command: &C) -> Result<Vec<Self::Event>, Self::Error>;
}
Key points:
- Takes
&self(validate against current state) - Returns
Vec<Event>(0..n events) - Returns
Result(commands can fail)
Command Naming
Commands are imperative:
| Good | Bad |
|---|---|
Deposit | FundsDeposited |
PlaceOrder | OrderPlaced |
RegisterUser | UserRegistered |
ChangePassword | PasswordChanged |
Next
Projections — Building read models from events