Event Sequence Source
By default, model-bound projections read from the event log. Use [EventSequence] to specify a different event sequence:
using Cratis.Chronicle.EventSequences;using Cratis.Chronicle.Keys;using Cratis.Chronicle.Projections.ModelBound;
[EventType]public record MbEventSeqOrderPlaced(decimal Amount);
[EventSequence("custom-sequence")]public record MbEventSeqOrderSummary( [Key] Guid Id,
[SetFrom<MbEventSeqOrderPlaced>(nameof(MbEventSeqOrderPlaced.Amount))] decimal TotalAmount);import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.observation.EventSequenceimport io.cratis.chronicle.projections.FromEventimport io.cratis.chronicle.projections.SetFromimport io.cratis.chronicle.readModels.ReadModel
@EventTypedata class MbEventSeqOrderPlaced(val amount: Double)
@ReadModel@EventSequence("custom-sequence")@FromEvent(MbEventSeqOrderPlaced::class)data class MbEventSeqOrderSummary( @SetFrom("amount", MbEventSeqOrderPlaced::class) val totalAmount: Double = 0.0)import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.observation.EventSequence;import io.cratis.chronicle.projections.FromEvent;import io.cratis.chronicle.projections.SetFrom;import io.cratis.chronicle.readModels.ReadModel;
@EventTyperecord MbEventSeqOrderPlaced(double amount) {}
@ReadModel@EventSequence("custom-sequence")@FromEvent(eventType = MbEventSeqOrderPlaced.class)record MbEventSeqOrderSummary( @SetFrom(propertyPath = "amount", eventType = MbEventSeqOrderPlaced.class) double totalAmount) {}Elixir does not support this workflow yet.import { eventSequence, eventType, fromEvent, readModel, setFrom } from '@cratis/chronicle';
@eventType()class MbEventSeqOrderPlaced { amount = 0;}
@readModel()@fromEvent(MbEventSeqOrderPlaced)@eventSequence('custom-sequence')class MbEventSeqOrderSummary { @setFrom(MbEventSeqOrderPlaced, 'amount') totalAmount = 0;}This corresponds to the fluent API for declarative projections:
using Cratis.Chronicle.EventSequences;using Cratis.Chronicle.Projections;
[EventType]public record MbEventSeqFluentOrderPlaced(decimal Amount);
public class MbEventSeqFluentOrderProjection : IProjectionFor<MbEventSeqFluentOrderSummary>{ public void Define(IProjectionBuilderFor<MbEventSeqFluentOrderSummary> builder) => builder .FromEventSequence(new EventSequenceId("custom-sequence")) .From<MbEventSeqFluentOrderPlaced>(_ => _ .Set(m => m.TotalAmount).To(e => e.Amount));}
public class MbEventSeqFluentOrderSummary{ public decimal TotalAmount { get; set; }}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.projections.IProjectionBuilderForimport io.cratis.chronicle.projections.IProjectionForimport io.cratis.chronicle.projections.Projection
@EventTypedata class MbEventSeqFluentOrderPlaced(val amount: Double)
data class MbEventSeqFluentOrderSummary(val totalAmount: Double = 0.0)
@Projection(eventSequence = "custom-sequence")class MbEventSeqFluentOrderProjection : IProjectionFor<MbEventSeqFluentOrderSummary> { override fun define(builder: IProjectionBuilderFor<MbEventSeqFluentOrderSummary>) { builder.from(MbEventSeqFluentOrderPlaced::class) { it.set(MbEventSeqFluentOrderSummary::totalAmount).to { e -> e.amount } } }}import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.projections.IProjectionBuilderFor;import io.cratis.chronicle.projections.IProjectionFor;import io.cratis.chronicle.projections.Projection;
@EventTyperecord MbEventSeqFluentOrderPlaced(double amount) {}
class MbEventSeqFluentOrderSummary { public double totalAmount = 0;}
@Projection(eventSequence = "custom-sequence")class MbEventSeqFluentOrderProjection implements IProjectionFor<MbEventSeqFluentOrderSummary> { @Override public void define(IProjectionBuilderFor<MbEventSeqFluentOrderSummary> builder) { builder.from(MbEventSeqFluentOrderPlaced.class, from -> from.<Double>set("totalAmount").to(MbEventSeqFluentOrderPlaced::amount)); }}Elixir does not support this workflow yet.import { eventType, IProjectionBuilderFor, IProjectionFor, projection } from '@cratis/chronicle';
@eventType()class MbEventSeqFluentOrderPlaced { amount = 0;}
// The event sequence is configured on the decorator rather than the builder@projection('', undefined, 'custom-sequence')class MbEventSeqFluentOrderProjection implements IProjectionFor<MbEventSeqFluentOrderSummary> { define(builder: IProjectionBuilderFor<MbEventSeqFluentOrderSummary>): void { builder.from(MbEventSeqFluentOrderPlaced, _ => _ .set(m => m.totalAmount).to(e => e.amount)); }}
class MbEventSeqFluentOrderSummary { totalAmount = 0;}Convenience: [EventLog]
Section titled “Convenience: [EventLog]”Use [EventLog] when you want to be explicit that the projection reads from the default event log, even when other event types in the assembly carry a [EventStore] attribute:
using Cratis.Chronicle.EventSequences;using Cratis.Chronicle.Keys;
[EventType]public record MbEventSeqLocalEvent(string Data);
[EventLog]public record MbEventSeqLocalSnapshot( [Key] Guid Id,
[SetFrom<MbEventSeqLocalEvent>(nameof(MbEventSeqLocalEvent.Data))] string Data);import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.projections.FromEventimport io.cratis.chronicle.projections.SetFromimport io.cratis.chronicle.readModels.ReadModel
@EventTypedata class MbEventSeqLocalEvent(val data: String)
// No @EventSequence needed — an observer with no event sequence specified observes the event log.@ReadModel@FromEvent(MbEventSeqLocalEvent::class)data class MbEventSeqLocalSnapshot( @SetFrom("data", MbEventSeqLocalEvent::class) val data: String = "")import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.projections.FromEvent;import io.cratis.chronicle.projections.SetFrom;import io.cratis.chronicle.readModels.ReadModel;
@EventTyperecord MbEventSeqLocalEvent(String data) {}
// No @EventSequence needed — an observer with no event sequence specified observes the event log.@ReadModel@FromEvent(eventType = MbEventSeqLocalEvent.class)record MbEventSeqLocalSnapshot( @SetFrom(propertyPath = "data", eventType = MbEventSeqLocalEvent.class) String data) {}Elixir does not support this workflow yet.import { eventLog, eventType, fromEvent, readModel, setFrom } from '@cratis/chronicle';
@eventType()class MbEventSeqLocalEvent { data = '';}
@readModel()@fromEvent(MbEventSeqLocalEvent)@eventLogclass MbEventSeqLocalSnapshot { @setFrom(MbEventSeqLocalEvent, 'data') data = '';}Automatic Inbox Routing
Section titled “Automatic Inbox Routing”When the event types used in a model-bound projection carry a [EventStore] attribute pointing to a different event store than the one the projection is registered in, Chronicle automatically routes the projection to the corresponding inbox sequence — no [EventSequence] annotation needed.
When the [EventStore] attribute points to the same event store as the current one, Chronicle routes to the event log instead.
When to use [EventSequence] explicitly
Section titled “When to use [EventSequence] explicitly”- When you need to read from a specific sequence other than the inferred one
- To suppress automatic inbox routing for a projection that handles foreign events
- For projections that target a specialized or partitioned event stream
Note: The old
[FromEventSequence]attribute has been removed. Use[EventSequence]instead.