Expand description
Procedural macros for the Evento event sourcing framework.
This crate provides macros that eliminate boilerplate when building event-sourced applications with Evento. It generates trait implementations, handler structs, and serialization code automatically.
§Macros
| Macro | Type | Purpose |
|---|---|---|
[aggregator] | Attribute | Transform enum into event structs with trait impls |
[handler] | Attribute | Create projection handler from async function |
[subscription] | Attribute | Create subscription handler for specific events |
[subscription_all] | Attribute | Create subscription handler for all events of an aggregate |
[projection] | Attribute | Add cursor field and implement ProjectionCursor |
Cursor | Derive | Generate cursor struct and trait implementations |
debug_handler | Attribute | Like handler but outputs generated code for debugging |
§Usage
This crate is typically used through the main evento crate with the macro feature
enabled (on by default):
[dependencies]
evento = "2"§Examples
§Defining Events with #[evento::aggregator]
Transform an enum into individual event structs:
#[evento::aggregator]
pub enum BankAccount {
/// Event raised when a new bank account is opened
AccountOpened {
owner_id: String,
owner_name: String,
initial_balance: i64,
},
MoneyDeposited {
amount: i64,
transaction_id: String,
},
MoneyWithdrawn {
amount: i64,
transaction_id: String,
},
}This generates:
AccountOpened,MoneyDeposited,MoneyWithdrawnstructsAggregatorandEventtrait implementations for each- Automatic derives:
Debug,Clone,PartialEq,Default, and bitcode serialization
§Creating Projection Handlers with #[evento::handler]
Projection handlers are used to build read models by replaying events:
use evento::metadata::Event;
#[evento::handler]
async fn handle_money_deposited(
event: Event<MoneyDeposited>,
projection: &mut AccountBalanceView,
) -> anyhow::Result<()> {
projection.balance += event.data.amount;
Ok(())
}
// Use in a projection
let projection = Projection::<AccountBalanceView, _>::new::<BankAccount>("account-123")
.handler(handle_money_deposited());§Creating Subscription Handlers with #[evento::subscription]
Subscription handlers process events in real-time with side effects:
use evento::{Executor, metadata::Event, subscription::Context};
#[evento::subscription]
async fn on_money_deposited<E: Executor>(
context: &Context<'_, E>,
event: Event<MoneyDeposited>,
) -> anyhow::Result<()> {
// Perform side effects: send notifications, update read models, etc.
println!("Deposited: {}", event.data.amount);
Ok(())
}
// Use in a subscription
let subscription = SubscriptionBuilder::<Sqlite>::new("deposit-notifier")
.handler(on_money_deposited())
.routing_key("accounts")
.start(&executor)
.await?;§Handling All Events with #[evento::subscription_all]
Handle all events from an aggregate type without deserializing:
use evento::{Executor, metadata::RawEvent, subscription::Context};
#[evento::subscription_all]
async fn on_any_account_event<E: Executor>(
context: &Context<'_, E>,
event: RawEvent<BankAccount>,
) -> anyhow::Result<()> {
println!("Event {} on account {}", event.name, event.aggregator_id);
Ok(())
}§Projection State with #[evento::projection]
Automatically add cursor tracking to projection structs:
#[evento::projection]
#[derive(Debug)]
pub struct AccountBalanceView {
pub balance: i64,
pub owner: String,
}
// Generates:
// - Adds `pub cursor: String` field
// - Implements `ProjectionCursor` trait
// - Adds `Default` and `Clone` derives§Requirements
When using these macros, your types must meet certain requirements:
- Events (from
#[aggregator]): Automatically derive required traits - Projections: Must implement
Default,Send,Sync,Clone - Projection handlers: Must be
asyncand returnanyhow::Result<()> - Subscription handlers: Must be
async, takeContextfirst, and returnanyhow::Result<()>
§Serialization
Events are serialized using bitcode for compact
binary representation. The #[aggregator] macro automatically adds the required
bitcode derives.
Attribute Macros§
- aggregator
- Transforms an enum into individual event structs with trait implementations.
- debug_
handler - Debug variant of [
handler] that writes generated code to a file. - handler
- Creates a projection handler from an async function.
- projection
- Adds a
cursor: Stringfield and implementsProjectionCursor. - subscription
- Creates a subscription handler for specific events.
- subscription_
all - Creates a subscription handler that processes all events of an aggregate type.
Derive Macros§
- Cursor
- Derive macro for generating cursor structs and trait implementations.