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 concurrencyInMemoryOrderEventStore—ConcurrentDictionary-backed test implementationIHasAppEventStore— capability interface for runtime accessAppEventStore.Orders.*—Eff<RT, T>effect methods (optional)AppEventStoreStreamExtensions— fluentAppend/AppendManyonIEventStream<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 |