Expand description
§sourcery
Building blocks for pragmatic event-sourced systems in Rust.
§Highlights
- Domain-first API – events are plain structs that implement
DomainEvent; IDs and metadata live in an envelope rather than in your payloads. - Aggregate derive –
#[derive(Aggregate)]generates the event enum plus serialisation/deserialisation glue so command handlers stay focused on behaviour. - Repository orchestration –
Repositoryloads aggregates, executes commands viaHandle<C>, and persists the resulting events in a single transaction. - Metadata-aware projections – projections receive aggregate IDs, events, and metadata
via
ApplyProjection, enabling cross-aggregate correlation using causation, timestamps, or custom metadata. - Store agnostic – ships with an in-memory store for demos/tests; implement the
EventStoretrait to plug in your own persistence.
§Quick Look
ⓘ
use sourcery::{Apply, DomainEvent, Handle};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FundsDeposited { pub amount_cents: i64 }
impl DomainEvent for FundsDeposited {
const KIND: &'static str = "bank.account.deposited";
}
#[derive(Debug, Default, sourcery::Aggregate)]
#[aggregate(id = String, error = String, events(FundsDeposited))]
pub struct Account { balance_cents: i64 }
impl Apply<FundsDeposited> for Account {
fn apply(&mut self, event: &FundsDeposited) {
self.balance_cents += event.amount_cents;
}
}
pub struct DepositFunds { pub amount_cents: i64 }
impl Handle<DepositFunds> for Account {
fn handle(&self, cmd: &DepositFunds) -> Result<Vec<Self::Event>, Self::Error> {
Ok(vec![FundsDeposited { amount_cents: cmd.amount_cents }.into()])
}
}§Key Concepts
| Concept | Description |
|---|---|
| Aggregates | Rebuild state from events and validate commands via Apply<E> and Handle<C>. |
| Projections | Read models that replay events via ApplyProjection<E>, potentially across multiple aggregates. |
| Repository | Orchestrates loading, command execution, and persistence in a single transaction. |
| EventStore | Trait defining the persistence boundary—implement for Postgres, DynamoDB, S3, etc. |
§Documentation
- Full documentation — Conceptual guides and tutorials
- API docs — Type and trait reference
- How sourcery compares — Design trade-offs vs other Rust event-sourcing crates
§Examples
| Example | Description |
|---|---|
quickstart | Minimal aggregate + projection |
inventory_report | Cross-aggregate projection |
subscription_billing | Real-world billing domain |
versioned_events | Schema migration via serde |
optimistic_concurrency | Conflict detection and retry |
snapshotting | Aggregate snapshots for performance |
cargo run --example quickstart§Status
Pre-1.0. APIs will evolve as real-world usage grows. Feedback and contributions welcome!
§Licensing
This project is publicly available under the GNU General Public License v3.0. It may optionally be distributed under the MIT licence by commercial arrangement.
Was this useful? Buy me a coffee
Modules§
- aggregate
- Command-side domain primitives.
- event
- Domain event marker.
- projection
- Read-side primitives.
- repository
- Command execution and aggregate lifecycle management.
- snapshot
- store
- subscription
- Push-based projection subscriptions.
Structs§
- Filters
- Combined filter configuration and handler map for a subscriber.
- Repository
- Command execution and aggregate lifecycle orchestrator.
- Subscription
Builder - Builder for configuring and starting a subscription.
- Subscription
Handle - Handle to a running subscription.
Enums§
- Event
Decode Error - Error returned when deserialising a stored event fails.
- Subscription
Error - Errors that can occur during subscription lifecycle.
Traits§
- Aggregate
- Command-side entities that produce domain events.
- Apply
- Mutate an aggregate with a domain event.
- Apply
Projection - Apply an event to a projection with access to envelope context.
- Domain
Event - Marker trait for events that can be persisted by the event store.
- Event
Kind - Extension trait for getting the event kind from an event instance.
- Handle
- Entry point for command handling.
- Projection
- Trait implemented by read models that can be constructed from an event stream.
- Projection
Event - Trait for event sum types that can deserialise themselves from stored events.
- Projection
Filters - Base trait for types that subscribe to events.
- Subscribable
Store - A store that supports push-based event subscriptions.
Type Aliases§
- Optimistic
Repository - Repository type alias with optimistic concurrency and no snapshots.
- Optimistic
Snapshot Repository - Repository type alias with optimistic concurrency and snapshot support.
- Unchecked
Repository - Repository type alias with unchecked concurrency and no snapshots.
Derive Macros§
- Aggregate
- Derives the
Aggregatetrait for a struct. - Projection
- Derives the
Projectiontrait for a struct.