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
Application
instance - A
RecordedEvent
represents anEvent
which 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