Projections
Projections declare how events are projected into a queryable read model. The body of a projection block is written in the Projection Declaration Language (PDL) — an embedded sub-grammar. The Screenplay parser delegates the indented body to the PDL parser (see Sub-language Pluggability).
The pages in this section document the full projection sub-language — every directive, operation, and expression the PDL supports. The same language is also used standalone by Cratis Chronicle to define projections without writing code; see Chronicle projections for how Chronicle hosts and executes it.
Syntax
Section titled “Syntax”projection <Name> => <ReadModel> <PDL grammar>Example
Section titled “Example”projection InvoiceDetails => InvoiceDetailsReadModel key invoiceId from InvoiceRegistered key invoiceId customerId = customerId invoiceNumber = invoiceNumber currency = currency status = "draft" registeredAt = $eventContext.occurred from InvoiceSent status = "sent" sentAt = sentAt from InvoicePaid status = "paid" paidAt = paidAt join customer on customerId with CustomerRegistered customerName = name children lineItems identified by lineNumber from InvoiceLineItemAdded key lineNumber parent invoiceId quantity = quantity unitPrice = unitPrice remove with InvoiceLineItemRemoved key lineNumber parent invoiceIdThe PDL vocabulary at a glance
Section titled “The PDL vocabulary at a glance”| Construct | Meaning |
|---|---|
key <property> | Which property identifies the read model instance. |
from <EventType> | Maps event properties onto the read model. Same-named properties map automatically. |
join <property> on <key> | Joins related state by a key property. |
children <collection> identified by <key> | Projects events into a child collection. |
parent <property> | Identifies the owning parent of a child. |
remove with <EventType> | Removes the instance (or child) when the event occurs. |
increment / decrement <property> | Counters maintained per event. |
$eventContext.occurred | The timestamp of the event being projected. |
An aggregating projection using counters:
projection InvoiceSummary => InvoiceSummaryReadModel from InvoiceRegistered key "global" increment totalCount increment draftCount from InvoiceSent decrement draftCount increment sentCount from InvoiceCancelled decrement totalCountSeveral projections in one slice
Section titled “Several projections in one slice”A slice is one behavior, and a behavior often needs more than one read model. The list a screen binds to is shaped for a reader; the state a command consults before it decides is shaped for a decision. Both are built from the same events by the same slice, so both projection blocks live in it:
slice StateView CustomerPortalReport query GetPortalReport => PortalReportReadModel by customerId CustomerId
projection PortalReport => PortalReportReadModel from PortalInvitationSent invitedAt = $eventContext.occurred
projection RevokedPortalToken => RevokedPortalTokenReadModel from PortalTokenRevoked revokedAt = $eventContext.occurredDeclare as many as the behavior needs. Each names its own read model, and printing writes them back out in the order they were declared. Splitting them across two slices would say the system has two behaviors where it has one.
Topics
Section titled “Topics”- From Event - Define rules that trigger when events occur
- Property Mapping - Map event data to read model properties
- Auto-Map - Automatically map matching properties
- Keys - Explicit and composite keys for projection instances
- Event Context - Access event metadata like timestamps and correlation IDs
- From Every - Apply rules to all events the projection subscribes to
- From All - Subscribe to all event types without filtering
- Counters - Increment, decrement, and count operations
- Arithmetic - Add and subtract operations
- Joins - Combine data from related events
- Children - Define nested collections
- Nested Objects - Single nullable child objects
- Removal - Remove projection instances based on events
- Expressions - Understanding expression syntax
- Grammar (EBNF) - Complete formal grammar specification