Expand description
Chekov is a CQRS/ES Framework built on top of Actix actor framework.
Getting started
Installation
chekov = "0.1"
Chekov is using [::event_store] in background to interact with backend.
Application
Chekov is using Application as a way to separate usecases. You can defined multiple
applications on the same runtime which can be useful to synchronise multiple domains.
But first, let’s define our first Application:
#[derive(Default)]
struct DefaultApp {}
// Application trait is here to preconfigure your chekov runtime.
// It tells that you want this `Application` to use a PostgresStorage.
impl chekov::Application for DefaultApp {
type Storage = chekov::prelude::PostgresStorage;
}If you want to know more about Application check the module documentation.
Defining our first Aggregate
One can create an aggregate that will be able to hold a state and execute commands on demand.
Each Aggregate is unique and can’t be duplicated meaning that you can’t have the same
aggregate instance running twice.
#[derive(chekov::Aggregate, Default, Clone)]
#[aggregate(identity = "user")]
struct User {
user_id: uuid::Uuid,
name: String
}
If you want to know more about aggregate check the module documentation.
Creating our first Event
An Aggregate produces events based on command execution. Defining an Event is pretty
straightforward.
#[derive(Clone, chekov::Event, Deserialize, Serialize)]
struct UserCreated{}
#[derive(Clone, chekov::Event, Deserialize, Serialize)]
enum UserUpdated {
NamedChanged(uuid::Uuid, String, String),
Disabled {
reason: String
}
}
If you want to know more about Event check the module documentation.
Defining our first Command
The purpose of a command is to been executed on an Aggregate (or a CommandHandler but we
will see that later). Each commands need to provide some basic information on how to deal with
them. But let’s keep that simple for now:
#[derive(Clone, Debug, chekov::Command, Serialize, Deserialize)]
#[command(event = "UserCreated", aggregate = "User", handler = "UserValidator")]
struct CreateUser {
#[command(identifier)]
pub user_id: Uuid,
pub name: String,
}
#[derive(Clone, Debug, chekov::Command, Serialize, Deserialize)]
#[command(event = "UserUpdated", aggregate = "User")]
struct UpdateUser {
#[command(identifier)]
pub user_id: Uuid,
pub name: String,
}
Modules
- Aggregates produce events based on commands
- Struct and Trait correlated to Application
- Struct and Trait correlated to Event
Structs
- Struct to configure and launch an
Applicationinstance - A
RecordedEventrepresents anEventwhich have been append to aStream - Deal with Application subscriptions
Traits
- Define an Aggregate
- Application are high order logical seperator.
- Define a Command which can be dispatch
- Receives a command and an immutable Executor and optionally returns events
- Define an Event which can be produced and consumed
- Define an event applier
- Define a struct as an EventHandler