Expand description
§Evento - Event Sourcing and CQRS Framework
Evento is a comprehensive library for building event-sourced applications using Domain-Driven Design (DDD) and Command Query Responsibility Segregation (CQRS) patterns in Rust.
§Overview
Event sourcing is a pattern where state changes are stored as a sequence of events. Instead of persisting just the current state, you persist all the events that led to the current state. This provides:
- Complete audit trail: Every change is recorded as an event
- Time travel: Replay events to see state at any point in time
- Event-driven architecture: React to events with handlers
- CQRS support: Separate read and write models
§Core Concepts
- Events: Immutable facts representing something that happened
- Aggregates: Domain objects that process events and maintain state
- Event Handlers: Functions that react to events and trigger side effects
- Event Store: Persistent storage for events (SQL databases supported)
- Snapshots: Periodic state captures to optimize loading
§Quick Start
use evento::{EventDetails, AggregatorName};
use serde::{Deserialize, Serialize};
use bincode::{Decode, Encode};
// Define events
#[derive(AggregatorName, Encode, Decode)]
struct UserCreated {
name: String,
email: String,
}
// Define aggregate
#[derive(Default, Serialize, Deserialize, Encode, Decode, Clone, Debug)]
struct User {
name: String,
email: String,
}
// Implement event handlers on the aggregate
#[evento::aggregator]
impl User {
async fn user_created(&mut self, event: EventDetails<UserCreated>) -> anyhow::Result<()> {
self.name = event.data.name;
self.email = event.data.email;
Ok(())
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Setup SQLite executor
let pool = sqlx::SqlitePool::connect("sqlite:events.db").await?;
let executor: evento::Sqlite = pool.into();
// Create and save events
let user_id = evento::create::<User>()
.data(&UserCreated {
name: "John Doe".to_string(),
email: "john@example.com".to_string(),
})?
.metadata(&true)?
.commit(&executor)
.await?;
// Load aggregate from events
let user = evento::load::<User, _>(&executor, &user_id).await?;
println!("User: {:?}", user.item);
Ok(())
}§Features
- SQL Database Support: SQLite, PostgreSQL, MySQL
- Event Handlers: Async event processing with retries
- Event Subscriptions: Continuous event processing
- Streaming: Real-time event streams (with
streamfeature) - Migrations: Database schema management
- Macros: Procedural macros for cleaner code
§Feature Flags
macro- Enable procedural macros (default)handler- Enable event handlers (default)stream- Enable streaming supportsql- Enable all SQL database backendssqlite- SQLite supportpostgres- PostgreSQL supportmysql- MySQL support
Modules§
Structs§
- Context
- Event
- Raw event stored in the event store
- Event
Cursor - Cursor for event pagination and positioning
- Event
Details - Event with typed data and metadata
- Evento
- Load
Result - Save
Builder - Skip
Handler - Subscribe
Builder - Subscription
Handle - Handle for managing a running subscription
Enums§
Traits§
- Aggregator
- Trait for domain aggregates that process events
- Aggregator
Name - Trait for types that have a name identifier
- Executor
- Subscribe
Handler
Functions§
- create
- Create a new aggregate with initial events
- create_
with - Create a new aggregate with a specific ID
- load
- Load an aggregate by replaying its events from the event store
- load_
optional - Load an aggregate by replaying its events, returning
Noneif not found - save
- Add events to an existing aggregate
- save_
with - Save events to an aggregate using a loaded aggregate state
- subscribe
- Create a new event subscription builder
Attribute Macros§
- aggregator
- Implements the [
evento::Aggregator] trait for structs with event handler methods - handler
- Creates an event handler for use with event subscriptions
Derive Macros§
- Aggregator
Name - Derives the [
evento::AggregatorName] trait for event types