chekov

Crates.iochekov
lib.rschekov
version0.1.1
sourcesrc
created_at2019-07-29 19:17:19.586186
updated_at2021-09-11 08:55:50.92843
descriptionCQRS/ES Framework
homepage
repositoryhttps://github.com/freyskeyd/chekov
max_upload_size
id152712
size65,810
Simon Paitrault (Freyskeyd)

documentation

https://docs.rs/chekov

README

Chekov

A CQRS/ES framework for building application in Rust

Actions Status Coverage Status dependency status Crates.io doc.rs doc-latest

Table of Contents


Features

  • Postgres EventStore backend
  • Dispatch Command to Aggregate
  • Generate Event from Aggregate
  • Store and notify Event with subscriptions
  • Dispatch Event to EventHandler

Getting started

Choosing an EventStore backend

Chekov works only with Postgres backend for now. The choice is easy to make!

But some more backends need to be implemented, see the related issue.

Defining Aggregates

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(())
  }
}

Defining Commands

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,
}

Defining Events

An Event can be a struct or an enum.

#[derive(Event, Deserialize, Serialize)]
struct UserCreated {
    user_id: Uuid,
    account_id: Uuid,
}

Defining Saga

Not implemented yet

Commit count: 150

cargo fmt