Skip to main content

Crate evento_macro

Crate evento_macro 

Source
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

MacroTypePurpose
[aggregator]AttributeTransform enum into event structs with trait impls
[handler]AttributeCreate projection handler from async function
[subscription]AttributeCreate subscription handler for specific events
[subscription_all]AttributeCreate subscription handler for all events of an aggregate
[projection]AttributeAdd cursor field and implement ProjectionCursor
CursorDeriveGenerate cursor struct and trait implementations
debug_handlerAttributeLike 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, MoneyWithdrawn structs
  • Aggregator and Event trait 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 async and return anyhow::Result<()>
  • Subscription handlers: Must be async, take Context first, and return anyhow::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: String field and implements ProjectionCursor.
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.