Module chekov::aggregate

source ·
Expand description

Aggregates produce events based on commands

An Aggregate is a simple Rust struct which will hold the state of the Aggregate. The Default trait is mandatory because of the way the Aggregate works.

An Aggregate is a simple struct and a bunch of functions that react to events or commands to alter the state. The state of an aggregate must remain private and accessible only by the aggregate itself. (Not even his parent). This prevent coupling between aggregates which is a bad practice.

An Aggregate must have a unique identity accros all Aggregate to perform well. See identity.

An Aggregate will start with a blank state (this is why it needs Default). It will then use EventApplier to receive and apply domain events on his state. You don’t need to worry about event number, stream and all the complexity of the event management, all of it are handle by the parent process which is automatically generated. You just have to decide whether you apply the event to the state or not. An Aggregate can’t apply multiple event at a time meaning that their is no concurrency state alteration.

An Aggregate will also be the root producer of all events. Aggregates generate events based on Command which are pushed to him. An Aggregate can’t execute multiple commands at a time.

Examples

#[derive(Debug, Clone, Default, Aggregate)]
#[aggregate(identity = "account")]
pub struct Account {
    account_id: Option<uuid::Uuid>,
    name: String,
    status: AccountStatus
}

// Executing commands
impl CommandExecutor<OpenAccount> for Account {
    fn execute(cmd: OpenAccount, state: &Self) -> ExecutionResult<AccountOpened> {
        match state.status {
            AccountStatus::Initialized => Ok(vec![AccountOpened {
                account_id: cmd.account_id,
                name: cmd.name,
            }]),
            _ => Err(CommandExecutorError::InternalRouterError),
        }
    }
}


#[chekov::applier]
impl EventApplier<AccountOpened> for Account {
    fn apply(&mut self, event: &AccountOpened) -> Result<(), ApplyError> {
        self.account_id = Some(event.account_id);
        self.status = AccountStatus::Active;

        Ok(())
    }
}

Traits

Type Definitions