Skip to content

The search box knows all the secrets -- try it!

Polecat is part of the Critter Stack ecosystem.

JasperFx Logo JasperFx provides formal support for Polecat and other Critter Stack libraries. Please check our Support Plans for more details.

Event Projections

Event projections process individual events to create, modify, or delete documents. Unlike aggregate projections, they don't maintain per-stream state.

Defining an Event Projection

cs
public class AuditLogProjection : EventProjection
{
    public void Project(IEvent<OrderCreated> @event, IDocumentOperations ops)
    {
        ops.Store(new AuditEntry
        {
            Id = Guid.NewGuid(),
            Action = "OrderCreated",
            StreamId = @event.StreamId,
            Timestamp = @event.Timestamp,
            Details = $"Order created for {@@event.Data.Amount:C}"
        });
    }

    public void Project(IEvent<OrderCancelled> @event, IDocumentOperations ops)
    {
        ops.Store(new AuditEntry
        {
            Id = Guid.NewGuid(),
            Action = "OrderCancelled",
            StreamId = @event.StreamId,
            Timestamp = @event.Timestamp,
            Details = "Order was cancelled"
        });
    }
}

Registration

cs
opts.Projections.Add<AuditLogProjection>(ProjectionLifecycle.Inline);
// or
opts.Projections.Add<AuditLogProjection>(ProjectionLifecycle.Async);

Use Cases

Event projections are ideal for:

  • Audit logs -- Create a record for each significant event
  • Search indexes -- Maintain denormalized documents for search
  • Notifications -- Create notification records per event
  • Cross-cutting concerns -- Track metrics, analytics, or compliance data

Accessing Session Operations

The IDocumentOperations parameter gives you full access to document operations:

cs
public void Project(IEvent<UserDeactivated> @event, IDocumentOperations ops)
{
    // Store new documents
    ops.Store(new DeactivationRecord { ... });

    // Delete documents
    ops.Delete<ActiveUser>(@event.Data.UserId);

    // Patch existing documents
    ops.Patch<UserStats>(@event.Data.UserId)
        .Set(x => x.IsActive, false);
}

Released under the MIT License.