Commands
Commands describe an intent to change the system's state. They have side-effects and interact with the write model. They are used to encapsulate application logic and are often used to implement use cases. They don't return a value, but they can fail.
- Intent-Driven: Commands represent a clear intention to change the system's state.
- Action-Oriented: Unlike queries, which request data, commands perform actions that modify state.
- Task-Specific: Each command is designed for a specific operation, ensuring clarity and purpose.
Creating Commands
It is recommended to create a command for each application use case.
application/src/command.rs
pub enum Command {
AddTask { name: String },
RemoveTask { index: usize },
CompleteTask { index: usize },
}
Implementing Commands
application/src/command.rs
#[async_trait]
impl<R> Execute<R> for Command
where
R: TodoListRepository + TodoListStore + Send + Sync,
{
async fn execute(&self, runtime: &R) -> AnyResult<()> {
let message = self.try_into()?;
// Pull the current state and apply the message
let todolist = TodoListStore::pull(runtime).await?;
let new_events = todolist.send(&message)?;
TodoListStore::push(runtime, &new_events).await?;
// Save the projection
let mut projection = TodoListRepository::fetch(runtime).await?;
projection.apply(&new_events);
TodoListRepository::save(runtime, &projection).await?;
Ok(())
}
}