Simple projection
A projection in Cratis is a way to create read models from events in the event store. The simplest projection automatically maps event properties to read model properties with matching names using the default AutoMap behavior.
Defining a simple projection
Section titled “Defining a simple projection”A projection implements IProjectionFor<TReadModel> and defines its behavior in the Define method:
using Cratis.Chronicle.Projections;
public class DecSimpleUserProjection : IProjectionFor<DecSimpleUser>{ public void Define(IProjectionBuilderFor<DecSimpleUser> builder) => builder .From<DecSimpleUserCreated>();}import io.cratis.chronicle.projections.IProjectionBuilderForimport io.cratis.chronicle.projections.IProjectionFor
class DecSimpleUserProjection : IProjectionFor<DecSimpleUser> { override fun define(builder: IProjectionBuilderFor<DecSimpleUser>) { builder.from(DecSimpleUserCreated::class) }}Java does not support this workflow yet.defmodule MyApp.Projections.DecSimpleUserProjection do use Chronicle.Projections.Projection, model: MyApp.ReadModels.DecSimpleUser
alias MyApp.Events.DecSimpleUserCreated
from DecSimpleUserCreatedendimport { IProjectionBuilderFor, IProjectionFor, projection } from '@cratis/chronicle';
@projection()class DecSimpleUserProjection implements IProjectionFor<DecSimpleUser> { define(builder: IProjectionBuilderFor<DecSimpleUser>): void { builder.from(DecSimpleUserCreated); }}This projection:
- Automatically maps properties from
UserCreatedevent to theUserread model (AutoMap is enabled by default) - Uses the event source ID as the key for the read model
- Properties with matching names are automatically mapped
Note: AutoMap is enabled by default at the top level. You don’t need to call
.AutoMap()explicitly unless you want to ensure it’s enabled in contexts where it might be disabled. Read more about auto mapping
Read model definition
Section titled “Read model definition”The read model is a simple record or class representing the projected data:
public record DecSimpleUser(string Name, string Email, DateTimeOffset CreatedAt);import java.time.OffsetDateTime
data class DecSimpleUser( val name: String = "", val email: String = "", val createdAt: OffsetDateTime? = null)Java does not support this workflow yet.defmodule MyApp.ReadModels.DecSimpleUser do use Chronicle.ReadModels.ReadModel
defstruct [:name, :email, :created_at]endclass DecSimpleUser { name = ''; email = ''; createdAt = new Date();}Event definition
Section titled “Event definition”The event should match the read model structure for auto-mapping to work:
using Cratis.Chronicle.Events;
[EventType]public record DecSimpleUserCreated(string Name, string Email, DateTimeOffset CreatedAt);import io.cratis.chronicle.events.EventTypeimport java.time.OffsetDateTime
@EventType(id = "dec-simple-user-created")data class DecSimpleUserCreated(val name: String, val email: String, val createdAt: OffsetDateTime)Java does not support this workflow yet.defmodule MyApp.Events.DecSimpleUserCreated do use Chronicle.Events.EventType, id: "dec-simple-user-created"
defstruct [:name, :email, :created_at]endclass DecSimpleUserCreated { name = ''; email = ''; createdAt = new Date();}How it works
Section titled “How it works”When a UserCreated event is appended to the event log:
- The projection automatically creates or updates a
Userread model - The event source ID becomes the key for the read model
- Properties with matching names are copied from event to read model
- The read model is stored and can be queried
Auto-mapping works when property names and types match between the event and read model. For more control over the mapping, see projection with custom properties.