CQRS/ES
framework for building application in Rust
Postgres
EventStore backend- Dispatch
Command
toAggregate
orCommandHandler
- Generate
Event
fromAggregate
and persist them - Apply
Event
toAggregate
- Store and notify
Event
with subscriptions - Dispatch
Event
toEventHandler
Chekov works only with Postgres
backend for now (and InMemory
for test purpose). The choice is easy to make!
But some more backends need to be implemented, see the related issue.
An Aggregate is a struct that hold a domain state. Here's an example of a UserAggregate:
#[derive(Default, Aggregate)]
#[aggregate(identity = "user")]
struct User {
user_id: Option<Uuid>,
account_id: Option<Uuid>,
}
/// Define an Executor for the `CreateUser` command
/// The result is a list of events in case of success
impl CommandExecutor<CreateUser> for User {
fn execute(cmd: CreateUser, _state: &Self) -> Result<Vec<UserCreated>, CommandExecutorError> {
Ok(vec![UserCreated {
user_id: cmd.user_id,
account_id: cmd.account_id,
}])
}
}
/// Define an Applier for the `UserCreated` event
/// Applier is a mutation action on the aggregate
#[chekov::applier]
impl EventApplier<UserCreated> for User {
fn apply(&mut self, event: &UserCreated) -> Result<(), ApplyError> {
self.user_id = Some(event.user_id);
self.account_id = Some(event.account_id);
Ok(())
}
}
You need to create a struct per command, any type of struct can implement Command
but we advise to use struct for a better readability.
A command can only produce (or not) one type of events and it targets a single Aggregate.
A command must have a single and unique identifier
that is used to route the command to the right target.
#[derive(Debug, Command)]
#[command(event = "UserCreated", aggregate = "User")]
struct CreateUser {
#[command(identifier)]
user_id: Uuid,
account_id: Uuid,
}
An Event
can be a struct
or an enum
.
#[derive(Event, Deserialize, Serialize)]
struct UserCreated {
user_id: Uuid,
account_id: Uuid,
}
Not implemented yet
No its not. Some critical part of the project are still not implemented and a lot of code needs to be refactored before that.
Feel free to open issue in case of bugs or features requests. Discussions are also a great starts if you have issue that are not bugs nor features requests.
The project is really early staged and have a lot of pending tasks, one major tasks is to produce a roadmap or some issues that can be used to expose the project vision. Feel free to open a Discussions around it if you want !