Skip to content

Event Store

The Event Store module generates event-sourced aggregate persistence from [EventStore] and [EventSourcedAggregate] attributes — per-aggregate store interfaces, in-memory implementations, effect methods, capability interfaces, stream extensions, and DI registration.

Quick Start

using Deepstaging.EventStore;
using Deepstaging.Ids;

// 1. Define a stream identity
[TypedId]
[StreamId]
public readonly partial struct OrderId;

// 2. Define events
public sealed record OrderCreated(OrderId OrderId, string CustomerName) : IAggregateEvent;
public sealed record OrderItemAdded(string Sku, int Quantity) : IAggregateEvent;
public sealed record OrderCompleted : IAggregateEvent;

// 3. Define the aggregate
[EventSourcedAggregate]
public partial record Order(OrderId Id, string CustomerName, int ItemCount, bool IsCompleted)
{
    public static Order Create(OrderCreated e) =>
        new(e.OrderId, e.CustomerName, 0, false);

    public Order Apply(OrderItemAdded e) =>
        this with { ItemCount = ItemCount + e.Quantity };

    public Order Apply(OrderCompleted _) =>
        this with { IsCompleted = true };
}

// 4. Declare the event store container
[EventStore]
public static partial class AppEventStore;

// 5. Use the generated Eff<RT, T> effect methods
var program =
    from id in AppEventStore.Orders.StartStream<AppRuntime>(
        new OrderCreated(OrderId.New(), "Alice"))
    from stream in AppEventStore.Orders.FetchForWriting<AppRuntime>(id)
    from order in stream.Append<AppRuntime>(new OrderItemAdded("SKU-001", 3))
                  >> AppEventStore.Commit<AppRuntime>()
                  >> AppEventStore.Orders.Aggregate<AppRuntime>(id)
    select order;

This generates:

  • IOrderEventStore — async event stream interface with optimistic concurrency
  • InMemoryOrderEventStoreConcurrentDictionary-backed test implementation
  • IHasAppEventStore — capability interface for runtime access
  • AppEventStore.Orders.*Eff<RT, T> effect methods (optional)
  • AppEventStoreStreamExtensions — fluent Append/AppendMany on IEventStream<T>
  • AppEventStoreRegistration — DI bootstrap

What's Next

Page Description
Attributes [EventStore], [EventSourcedAggregate], [StreamId], IAggregateEvent, and Create/Apply conventions
Generated Code Store interfaces, IEventStream<T>, EventEnvelope, in-memory implementation, DI registration, and plain async/await usage
Effects Capability interface, Eff<RT, T> methods, stream extensions, runtime integration, and OpenTelemetry instrumentation
Projections Read-model projections built from event streams
Upcasting Evolving event schemas without breaking existing streams
Marten Backend PostgreSQL-backed event store using Marten

Diagnostics

ID Severity Description
DSES01 Error [EventStore] class must be partial
DSES02 Warning [EventStore] class should be static
DSES03 Error [EventSourcedAggregate] class must be partial
DSES04 Error Only one [EventStore] per assembly
DSES05 Info [EventSourcedAggregate] exists but no [EventStore] container in assembly
DSES06 Error [EventSourcedAggregate] must have a property with a [StreamId] type