Skip to content

Projections

Projections are shared Chronicle read-model behavior. Use the shared docs for projection styles, model-bound projections, declarative projections, and client-tabbed examples.

Beyond @FromEvent and @SetFrom, the Kotlin client has annotations for structural shapes (joins, children, nested objects), arithmetic (counters, running totals), catch-all mappings, and rewind behavior. Full parameter tables are in the annotation reference.

AttributeUse it for
@JoinPulling in a property from another event type by id.
@ChildrenFromA collection built from child instances of an event type.
@NestedA nullable sub-object built from its own @FromEvent.
@ClearWithWhich event clears (nulls out) a @Nested property.
@CountAn occurrence counter for a specific event type.
@Increment / @DecrementBumping a numeric property by one.
@AddFrom / @SubtractFromAdding/subtracting an event value in.
@FromAll / @FromEveryA property populated from every event type.
@NotRewindableMarking a projection as forward-only.
@RemovedWithWhich event removes an instance or a child.
@RemovedWithJoinLike @RemovedWith, but resolving the id via a join.
@NoAutoMapDisabling AutoMap for a type or a single property.

@NotRewindable is worth considering for projections fed by events that can’t reliably be redelivered — e.g. from an event store subscription.

import io.cratis.chronicle.projections.Increment
import io.cratis.chronicle.projections.Join
import io.cratis.chronicle.readModels.ReadModel
@ReadModel
data class OrderOverview(
val id: String = "",
@Increment(OrderShipped::class) val shipmentCount: Int = 0,
@Join(
eventType = CustomerRegistered::class,
on = "customerId",
eventPropertyName = "email"
)
val customerEmail: String = ""
)

IProjectionBuilderFor<T> also supports .join(), .fromEvery()/.fromAll(), .removedWith()/.removedWithJoin(), .children(), .nested(), and .notRewindable() — the fluent equivalents of the attributes above, for projections defined with a separate IProjectionFor<T> class instead of model-bound annotations:

import io.cratis.chronicle.projections.IProjectionBuilderFor
import io.cratis.chronicle.projections.IProjectionFor
class OrderOverviewProjection : IProjectionFor<OrderOverview> {
override fun define(builder: IProjectionBuilderFor<OrderOverview>) {
builder
.from(OrderPlaced::class)
.join(CustomerRegistered::class) { join ->
join.on(OrderOverview::customerEmail)
.set(OrderOverview::customerEmail)
.toProperty("email")
}
.notRewindable()
}
}