Projection With FromEvery
Use an every-event mapping in a declarative projection when a read model property should update whenever any event handled by the projection is processed. This is most useful for audit metadata, event source identifiers, and other fields that should stay synchronized with the latest event.
The exact API name depends on the client. .NET and TypeScript expose FromEvery / fromEvery, while Elixir exposes from_every.
Basic Usage
Section titled “Basic Usage”Map event context metadata when the read model needs to know when it was last touched.
using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record UserCreatedDeclarativeEvery(string Name, string Email);
[EventType]public record UserEmailChangedDeclarativeEvery(string Email);
public record UserProfileDeclarativeEvery( string Name, string Email, DateTimeOffset LastUpdated);
public class UserProfileDeclarativeEveryProjection : IProjectionFor<UserProfileDeclarativeEvery>{ public void Define(IProjectionBuilderFor<UserProfileDeclarativeEvery> builder) => builder .From<UserCreatedDeclarativeEvery>() .From<UserEmailChangedDeclarativeEvery>() .FromEvery(_ => _ .Set(m => m.LastUpdated) .ToEventContextProperty(c => c.Occurred));}Kotlin does not support this workflow yet.Java does not support this workflow yet.defmodule MyApp.Events.UserCreatedDeclarativeEvery do use Chronicle.Events.EventType, id: "user-created-declarative-every-v1"
defstruct [:name, :email]end
defmodule MyApp.Events.UserEmailChangedDeclarativeEvery do use Chronicle.Events.EventType, id: "user-email-changed-declarative-every-v1"
defstruct [:email]end
defmodule MyApp.ReadModels.UserProfileDeclarativeEvery do use Chronicle.ReadModels.ReadModel
defstruct [:name, :email, :last_updated]end
defmodule MyApp.Projections.UserProfileDeclarativeEveryProjection do use Chronicle.Projections.Projection, model: MyApp.ReadModels.UserProfileDeclarativeEvery
alias MyApp.Events.{UserCreatedDeclarativeEvery, UserEmailChangedDeclarativeEvery}
from UserCreatedDeclarativeEvery, set: [ name: :name, email: :email ]
from UserEmailChangedDeclarativeEvery, set: [email: :email]
from_every set: [last_updated: :occurred]endimport { eventType, IProjectionBuilderFor, IProjectionFor, projection, readModel } from '@cratis/chronicle';
@eventType()class UserCreatedDeclarativeEvery { constructor(readonly name: string, readonly email: string) {}}
@eventType()class UserEmailChangedDeclarativeEvery { constructor(readonly email: string) {}}
@readModel()class UserProfileDeclarativeEvery { name = ''; email = ''; lastUpdated = new Date();}
@projection('', UserProfileDeclarativeEvery)class UserProfileDeclarativeEveryProjection implements IProjectionFor<UserProfileDeclarativeEvery> { define(builder: IProjectionBuilderFor<UserProfileDeclarativeEvery>): void { builder .from(UserCreatedDeclarativeEvery) .from(UserEmailChangedDeclarativeEvery) .fromEvery(_ => _ .set(m => m.lastUpdated) .toEventContextProperty('occurred')); }}Event Context Fields
Section titled “Event Context Fields”Every-event mappings can map more than one context field.
using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record AccountTouchedDeclarativeEvery(string Reason);
public record AccountAuditDeclarativeEvery( DateTimeOffset LastUpdated, EventSequenceNumber LastEventSequence, string LastCorrelationId);
public class AccountAuditDeclarativeEveryProjection : IProjectionFor<AccountAuditDeclarativeEvery>{ public void Define(IProjectionBuilderFor<AccountAuditDeclarativeEvery> builder) => builder .From<AccountTouchedDeclarativeEvery>() .FromEvery(_ => _ .Set(m => m.LastUpdated).ToEventContextProperty(c => c.Occurred) .Set(m => m.LastEventSequence).ToEventContextProperty(c => c.SequenceNumber) .Set(m => m.LastCorrelationId).ToEventContextProperty(c => c.CorrelationId));}Kotlin does not support this workflow yet.Java does not support this workflow yet.defmodule MyApp.Events.AccountTouchedDeclarativeEvery do use Chronicle.Events.EventType, id: "account-touched-declarative-every-v1"
defstruct [:reason]end
defmodule MyApp.ReadModels.AccountAuditDeclarativeEvery do use Chronicle.ReadModels.ReadModel
defstruct [:last_updated, :last_event_sequence, :last_correlation_id]end
defmodule MyApp.Projections.AccountAuditDeclarativeEveryProjection do use Chronicle.Projections.Projection, model: MyApp.ReadModels.AccountAuditDeclarativeEvery
alias MyApp.Events.AccountTouchedDeclarativeEvery
from AccountTouchedDeclarativeEvery
from_every set: [ last_updated: :occurred, last_event_sequence: "$context.sequenceNumber", last_correlation_id: "$context.correlationId" ]endimport { eventType, IProjectionBuilderFor, IProjectionFor, projection, readModel } from '@cratis/chronicle';
@eventType()class AccountTouchedDeclarativeEvery { constructor(readonly reason: string) {}}
@readModel()class AccountAuditDeclarativeEvery { lastUpdated = new Date(); lastEventSequence = 0n; lastCorrelationId = '';}
@projection('', AccountAuditDeclarativeEvery)class AccountAuditDeclarativeEveryProjection implements IProjectionFor<AccountAuditDeclarativeEvery> { define(builder: IProjectionBuilderFor<AccountAuditDeclarativeEvery>): void { builder .from(AccountTouchedDeclarativeEvery) .fromEvery(_ => _ .set(m => m.lastUpdated).toEventContextProperty('occurred') .set(m => m.lastEventSequence).toEventContextProperty('sequenceNumber') .set(m => m.lastCorrelationId).toEventContextProperty('correlationId')); }}Event Source Id
Section titled “Event Source Id”Map the event source id when the read model’s primary identifier is not otherwise populated from each event payload.
using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record AccountOpenedDeclarativeEvery(string OwnerName);
public record AccountSummaryDeclarativeEvery( string AccountId, string OwnerName);
public class AccountSummaryDeclarativeEveryProjection : IProjectionFor<AccountSummaryDeclarativeEvery>{ public void Define(IProjectionBuilderFor<AccountSummaryDeclarativeEvery> builder) => builder .From<AccountOpenedDeclarativeEvery>() .FromEvery(_ => _ .Set(m => m.AccountId) .ToEventSourceId());}Kotlin does not support this workflow yet.Java does not support this workflow yet.defmodule MyApp.Events.AccountOpenedDeclarativeEvery do use Chronicle.Events.EventType, id: "account-opened-declarative-every-v1"
defstruct [:owner_name]end
defmodule MyApp.ReadModels.AccountSummaryDeclarativeEvery do use Chronicle.ReadModels.ReadModel
defstruct [:account_id, :owner_name]end
defmodule MyApp.Projections.AccountSummaryDeclarativeEveryProjection do use Chronicle.Projections.Projection, model: MyApp.ReadModels.AccountSummaryDeclarativeEvery
alias MyApp.Events.AccountOpenedDeclarativeEvery
from AccountOpenedDeclarativeEvery, set: [owner_name: :owner_name]
from_every set: [account_id: :event_source_id]endimport { eventType, IProjectionBuilderFor, IProjectionFor, projection, readModel } from '@cratis/chronicle';
@eventType()class AccountOpenedDeclarativeEvery { constructor(readonly ownerName: string) {}}
@readModel()class AccountSummaryDeclarativeEvery { accountId = ''; ownerName = '';}
@projection('', AccountSummaryDeclarativeEvery)class AccountSummaryDeclarativeEveryProjection implements IProjectionFor<AccountSummaryDeclarativeEvery> { define(builder: IProjectionBuilderFor<AccountSummaryDeclarativeEvery>): void { builder .from(AccountOpenedDeclarativeEvery) .fromEvery(_ => _ .set(m => m.accountId) .toEventSourceId()); }}Child Projection Inclusion
Section titled “Child Projection Inclusion”Some clients let the projection decide whether child projection events should update parent-level every-event fields.
using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record OrderCreatedDeclarativeEveryExclude(string OrderNumber);
public record OrderAuditDeclarativeEveryExclude( string OrderNumber, DateTimeOffset LastUpdated);
public class OrderAuditDeclarativeEveryExcludeProjection : IProjectionFor<OrderAuditDeclarativeEveryExclude>{ public void Define(IProjectionBuilderFor<OrderAuditDeclarativeEveryExclude> builder) => builder .From<OrderCreatedDeclarativeEveryExclude>() .FromEvery(_ => _ .Set(m => m.LastUpdated) .ToEventContextProperty(c => c.Occurred) .ExcludeChildProjections());}Kotlin does not support this workflow yet.Java does not support this workflow yet.defmodule MyApp.Events.OrderCreatedDeclarativeEveryExclude do use Chronicle.Events.EventType, id: "order-created-declarative-every-exclude-v1"
defstruct [:order_number]end
defmodule MyApp.ReadModels.OrderAuditDeclarativeEveryExclude do use Chronicle.ReadModels.ReadModel
defstruct [:order_number, :last_updated]end
defmodule MyApp.Projections.OrderAuditDeclarativeEveryExcludeProjection do use Chronicle.Projections.Projection, model: MyApp.ReadModels.OrderAuditDeclarativeEveryExclude
alias MyApp.Events.OrderCreatedDeclarativeEveryExclude
from OrderCreatedDeclarativeEveryExclude
from_every set: [last_updated: :occurred], include_children: falseendimport { eventType, IProjectionBuilderFor, IProjectionFor, projection, readModel } from '@cratis/chronicle';
@eventType()class OrderCreatedDeclarativeEveryExclude { constructor(readonly orderNumber: string) {}}
@readModel()class OrderAuditDeclarativeEveryExclude { orderNumber = ''; lastUpdated = new Date();}
@projection('', OrderAuditDeclarativeEveryExclude)class OrderAuditDeclarativeEveryExcludeProjection implements IProjectionFor<OrderAuditDeclarativeEveryExclude> { define(builder: IProjectionBuilderFor<OrderAuditDeclarativeEveryExclude>): void { builder .from(OrderCreatedDeclarativeEveryExclude) .fromEvery(_ => _ .set(m => m.lastUpdated) .toEventContextProperty('occurred') .excludeChildProjections()); }}When child projections are included, parent metadata can update for events that only affect a child item.
using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record OrderCreatedDeclarativeEveryChildren(string OrderNumber);
[EventType]public record ItemAddedDeclarativeEveryChildren(string OrderId, string ProductId, string ProductName, int Quantity);
[EventType]public record ItemQuantityChangedDeclarativeEveryChildren(string OrderId, string ProductId, int Quantity);
public record OrderDeclarativeEveryChildren( string OrderNumber, DateTimeOffset LastModified, IEnumerable<OrderItemDeclarativeEveryChildren> Items);
public record OrderItemDeclarativeEveryChildren( string ProductId, string ProductName, int Quantity);
public class OrderDeclarativeEveryChildrenProjection : IProjectionFor<OrderDeclarativeEveryChildren>{ public void Define(IProjectionBuilderFor<OrderDeclarativeEveryChildren> builder) => builder .From<OrderCreatedDeclarativeEveryChildren>() .FromEvery(_ => _ .Set(m => m.LastModified) .ToEventContextProperty(c => c.Occurred)) .Children(m => m.Items, children => children .IdentifiedBy(m => m.ProductId) .From<ItemAddedDeclarativeEveryChildren>(_ => _ .UsingKey(e => e.ProductId) .UsingParentKey(e => e.OrderId)) .From<ItemQuantityChangedDeclarativeEveryChildren>(_ => _ .UsingKey(e => e.ProductId) .UsingParentKey(e => e.OrderId)));}Multiple Declarations
Section titled “Multiple Declarations”Clients that support multiple every-event declarations merge the property mappings into one projection definition.
using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record UserChangedDeclarativeEveryMultiple(string Name);
public record UserAuditDeclarativeEveryMultiple( string Name, DateTimeOffset LastUpdated, string ModifiedBy);
public class UserAuditDeclarativeEveryMultipleProjection : IProjectionFor<UserAuditDeclarativeEveryMultiple>{ public void Define(IProjectionBuilderFor<UserAuditDeclarativeEveryMultiple> builder) => builder .From<UserChangedDeclarativeEveryMultiple>() .FromEvery(_ => _ .Set(m => m.LastUpdated) .ToEventContextProperty(c => c.Occurred)) .FromEvery(_ => _ .Set(m => m.ModifiedBy) .ToEventContextProperty(c => c.CausedBy));}Kotlin does not support this workflow yet.Java does not support this workflow yet.Elixir does not support this workflow yet.import { eventType, IProjectionBuilderFor, IProjectionFor, projection, readModel } from '@cratis/chronicle';
@eventType()class UserChangedDeclarativeEveryMultiple { constructor(readonly name: string) {}}
@readModel()class UserAuditDeclarativeEveryMultiple { name = ''; lastUpdated = new Date(); modifiedBy = '';}
@projection('', UserAuditDeclarativeEveryMultiple)class UserAuditDeclarativeEveryMultipleProjection implements IProjectionFor<UserAuditDeclarativeEveryMultiple> { define(builder: IProjectionBuilderFor<UserAuditDeclarativeEveryMultiple>): void { builder .from(UserChangedDeclarativeEveryMultiple) .fromEvery(_ => _ .set(m => m.lastUpdated) .toEventContextProperty('occurred')) .fromEvery(_ => _ .set(m => m.modifiedBy) .toEventContextProperty('causedBy')); }}Common Use Cases
Section titled “Common Use Cases”| Use case | Typical source |
|---|---|
| Audit timestamp | Event context occurrence time |
| Event sequencing | Event context sequence number |
| Correlation tracking | Event context correlation id |
| Event source identification | Event source id |
Use event-specific mappings when the property should update only for selected event types.