Projection With FromAll
FromAll subscribes to every event type in the event sequence, not just event types declared by the projection. It can create or update a read-model instance for any event source, keyed by the event source id unless you configure another key. Use FromEvery instead when mappings should apply only to event types the projection already handles.
A declared Join event type is excluded from the separate all-events subscription to avoid processing a matched event twice. Its FromAll mapping runs through the join instead. Known limitation: if that join finds no read-model instance, the mapping does not fall back to creating one under the event source id. An event type that is also declared in From runs the mapping through From instead, once, and can construct its own keyed instance.
Use FromAll in .NET for sequence-wide mappings such as per-source event counts. The root all block in the declaration language has the same subscription scope: it observes child-projection event types as well as unrelated event types. FromAll sends child inclusion as true and has no child-exclusion switch. Child-only events apply the mappings once to their containing parent, using the child’s resolved parent key. Unrelated event types still use the configured all-events key. Use FromEvery with ExcludeChildProjections() (or every with exclude children) for mappings limited to one projection level.
Basic Usage
Section titled “Basic Usage”using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record UserCreatedDeclarativeAll(string Name, string Email);
[EventType]public record UserEmailChangedDeclarativeAll(string Email);
public record UserProfileDeclarativeAll( string Name, string Email, DateTimeOffset LastUpdated);
public class UserProfileDeclarativeAllProjection : IProjectionFor<UserProfileDeclarativeAll>{ public void Define(IProjectionBuilderFor<UserProfileDeclarativeAll> builder) => builder .From<UserCreatedDeclarativeAll>() .From<UserEmailChangedDeclarativeAll>() .FromAll(_ => _ .Set(m => m.LastUpdated) .ToEventContextProperty(c => c.Occurred));}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.projections.IProjectionBuilderForimport io.cratis.chronicle.projections.IProjectionFor
@EventTypedata class UserCreatedDeclarativeAll(val name: String, val email: String)
@EventTypedata class UserEmailChangedDeclarativeAll(val email: String)
data class UserProfileDeclarativeAll( val name: String = "", val email: String = "", val lastUpdated: String = "")
class UserProfileDeclarativeAllProjection : IProjectionFor<UserProfileDeclarativeAll> { override fun define(builder: IProjectionBuilderFor<UserProfileDeclarativeAll>) { builder .from(UserCreatedDeclarativeAll::class) .from(UserEmailChangedDeclarativeAll::class) .fromAll { it.set(UserProfileDeclarativeAll::lastUpdated).toEventContextProperty("occurred") } }}import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.projections.IProjectionBuilderFor;import io.cratis.chronicle.projections.IProjectionFor;
@EventTyperecord UserCreatedDeclarativeAll(String name, String email) {}
@EventTyperecord UserEmailChangedDeclarativeAll(String email) {}
class UserProfileDeclarativeAll { public String name = ""; public String email = ""; public String lastUpdated = "";}
class UserProfileDeclarativeAllProjection implements IProjectionFor<UserProfileDeclarativeAll> { @Override public void define(IProjectionBuilderFor<UserProfileDeclarativeAll> builder) { builder .from(UserCreatedDeclarativeAll.class) .from(UserEmailChangedDeclarativeAll.class) .fromAll(feb -> { feb.set("lastUpdated").toEventContextProperty("occurred"); }); }}defmodule MyApp.Events.UserCreatedDeclarativeAll do use Chronicle.Events.EventType, id: "user-created-declarative-all-v1"
defstruct [:name, :email]end
defmodule MyApp.Events.UserEmailChangedDeclarativeAll do use Chronicle.Events.EventType, id: "user-email-changed-declarative-all-v1"
defstruct [:email]end
defmodule MyApp.ReadModels.UserProfileDeclarativeAll do use Chronicle.ReadModels.ReadModel
defstruct [:name, :email, :last_updated]end
defmodule MyApp.Projections.UserProfileDeclarativeAllProjection do use Chronicle.Projections.Projection, model: MyApp.ReadModels.UserProfileDeclarativeAll
alias MyApp.Events.{UserCreatedDeclarativeAll, UserEmailChangedDeclarativeAll}
from UserCreatedDeclarativeAll from UserEmailChangedDeclarativeAll
from_every set: [last_updated: :occurred]endUse fluent fromAll(...) to update a projection for every event type, including
those not declared with from(...). It creates a read model keyed by event source
ID even for an otherwise unrelated event. Mappings also apply to child projections.
Use fromEvery(...) instead when only subscribed events should update the model.
import { eventType, IProjectionBuilderFor, IProjectionFor, projection } from '@cratis/chronicle';import { field } from '@cratis/fundamentals';
@eventType()export class UserCreatedDeclarativeAll { @field(String) readonly name: string; @field(String) readonly email: string;
constructor(name: string, email: string) { this.name = name; this.email = email; }}
@eventType()export class UserEmailChangedDeclarativeAll { @field(String) readonly email: string;
constructor(email: string) { this.email = email; }}
export class UserProfileDeclarativeAll { name = ''; email = ''; lastUpdated = new Date();}
@projection('', UserProfileDeclarativeAll)export class UserProfileDeclarativeAllProjection implements IProjectionFor<UserProfileDeclarativeAll> { define(builder: IProjectionBuilderFor<UserProfileDeclarativeAll>): void { builder .from(UserCreatedDeclarativeAll) .from(UserEmailChangedDeclarativeAll) .fromAll(all => all .set(model => model.lastUpdated) .toEventContextProperty('occurred')); }}Event Context Fields
Section titled “Event Context Fields”using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record AccountTouchedDeclarativeAll(string Reason);
public record AccountAuditDeclarativeAll( DateTimeOffset LastUpdated, EventSequenceNumber LastEventSequence, string LastCorrelationId);
public class AccountAuditDeclarativeAllProjection : IProjectionFor<AccountAuditDeclarativeAll>{ public void Define(IProjectionBuilderFor<AccountAuditDeclarativeAll> builder) => builder .From<AccountTouchedDeclarativeAll>() .FromAll(_ => _ .Set(m => m.LastUpdated).ToEventContextProperty(c => c.Occurred) .Set(m => m.LastEventSequence).ToEventContextProperty(c => c.SequenceNumber) .Set(m => m.LastCorrelationId).ToEventContextProperty(c => c.CorrelationId));}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.projections.IProjectionBuilderForimport io.cratis.chronicle.projections.IProjectionFor
@EventTypedata class AccountTouchedDeclarativeAll(val reason: String)
data class AccountAuditDeclarativeAll( val lastUpdated: String = "", val lastEventSequence: String = "", val lastCorrelationId: String = "")
class AccountAuditDeclarativeAllProjection : IProjectionFor<AccountAuditDeclarativeAll> { override fun define(builder: IProjectionBuilderFor<AccountAuditDeclarativeAll>) { builder .from(AccountTouchedDeclarativeAll::class) .fromAll { it.set(AccountAuditDeclarativeAll::lastUpdated).toEventContextProperty("occurred") it.set(AccountAuditDeclarativeAll::lastEventSequence).toEventContextProperty("sequenceNumber") it.set(AccountAuditDeclarativeAll::lastCorrelationId).toEventContextProperty("correlationId") } }}import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.projections.IProjectionBuilderFor;import io.cratis.chronicle.projections.IProjectionFor;
@EventTyperecord AccountTouchedDeclarativeAll(String reason) {}
class AccountAuditDeclarativeAll { public String lastUpdated = ""; public String lastEventSequence = ""; public String lastCorrelationId = "";}
class AccountAuditDeclarativeAllProjection implements IProjectionFor<AccountAuditDeclarativeAll> { @Override public void define(IProjectionBuilderFor<AccountAuditDeclarativeAll> builder) { builder .from(AccountTouchedDeclarativeAll.class) .fromAll(feb -> { feb.set("lastUpdated").toEventContextProperty("occurred"); feb.set("lastEventSequence").toEventContextProperty("sequenceNumber"); feb.set("lastCorrelationId").toEventContextProperty("correlationId"); }); }}defmodule MyApp.Events.AccountTouchedDeclarativeAll do use Chronicle.Events.EventType, id: "account-touched-declarative-all-v1"
defstruct [:reason]end
defmodule MyApp.ReadModels.AccountAuditDeclarativeAll do use Chronicle.ReadModels.ReadModel
defstruct [:last_updated, :last_event_sequence, :last_correlation_id]end
defmodule MyApp.Projections.AccountAuditDeclarativeAllProjection do use Chronicle.Projections.Projection, model: MyApp.ReadModels.AccountAuditDeclarativeAll
alias MyApp.Events.AccountTouchedDeclarativeAll
from AccountTouchedDeclarativeAll
from_every set: [ last_updated: :occurred, last_event_sequence: "$context.sequenceNumber", last_correlation_id: "$context.correlationId" ]endimport { eventType, IProjectionBuilderFor, IProjectionFor, projection } from '@cratis/chronicle';import { field } from '@cratis/fundamentals';
@eventType()export class AccountTouchedDeclarativeAll { @field(String) readonly reason: string;
constructor(reason: string) { this.reason = reason; }}
export class AccountAuditDeclarativeAll { lastUpdated = new Date(); lastEventSequence = 0n; lastCorrelationId = '';}
@projection('', AccountAuditDeclarativeAll)export class AccountAuditDeclarativeAllProjection implements IProjectionFor<AccountAuditDeclarativeAll> { define(builder: IProjectionBuilderFor<AccountAuditDeclarativeAll>): void { builder .from(AccountTouchedDeclarativeAll) .fromAll(_ => _ .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”using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record AccountOpenedDeclarativeAll(string OwnerName);
public record AccountSummaryDeclarativeAll( string AccountId, string OwnerName);
public class AccountSummaryDeclarativeAllProjection : IProjectionFor<AccountSummaryDeclarativeAll>{ public void Define(IProjectionBuilderFor<AccountSummaryDeclarativeAll> builder) => builder .From<AccountOpenedDeclarativeAll>() .FromAll(_ => _ .Set(m => m.AccountId) .ToEventSourceId());}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.projections.IProjectionBuilderForimport io.cratis.chronicle.projections.IProjectionFor
@EventTypedata class AccountOpenedDeclarativeAll(val ownerName: String)
data class AccountSummaryDeclarativeAll( val accountId: String = "", val ownerName: String = "")
class AccountSummaryDeclarativeAllProjection : IProjectionFor<AccountSummaryDeclarativeAll> { override fun define(builder: IProjectionBuilderFor<AccountSummaryDeclarativeAll>) { builder .from(AccountOpenedDeclarativeAll::class) .fromAll { it.set(AccountSummaryDeclarativeAll::accountId).toEventSourceId() } }}import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.projections.IProjectionBuilderFor;import io.cratis.chronicle.projections.IProjectionFor;
@EventTyperecord AccountOpenedDeclarativeAll(String ownerName) {}
class AccountSummaryDeclarativeAll { public String accountId = ""; public String ownerName = "";}
class AccountSummaryDeclarativeAllProjection implements IProjectionFor<AccountSummaryDeclarativeAll> { @Override public void define(IProjectionBuilderFor<AccountSummaryDeclarativeAll> builder) { builder .from(AccountOpenedDeclarativeAll.class) .fromAll(feb -> { feb.set("accountId").toEventSourceId(); }); }}defmodule MyApp.Events.AccountOpenedDeclarativeAll do use Chronicle.Events.EventType, id: "account-opened-declarative-all-v1"
defstruct [:owner_name]end
defmodule MyApp.ReadModels.AccountSummaryDeclarativeAll do use Chronicle.ReadModels.ReadModel
defstruct [:account_id, :owner_name]end
defmodule MyApp.Projections.AccountSummaryDeclarativeAllProjection do use Chronicle.Projections.Projection, model: MyApp.ReadModels.AccountSummaryDeclarativeAll
alias MyApp.Events.AccountOpenedDeclarativeAll
from AccountOpenedDeclarativeAll
from_every set: [account_id: :event_source_id]endimport { eventType, IProjectionBuilderFor, IProjectionFor, projection } from '@cratis/chronicle';import { field } from '@cratis/fundamentals';
@eventType()export class AccountOpenedDeclarativeAll { @field(String) readonly ownerName: string;
constructor(ownerName: string) { this.ownerName = ownerName; }}
export class AccountSummaryDeclarativeAll { accountId = ''; ownerName = '';}
@projection('', AccountSummaryDeclarativeAll)export class AccountSummaryDeclarativeAllProjection implements IProjectionFor<AccountSummaryDeclarativeAll> { define(builder: IProjectionBuilderFor<AccountSummaryDeclarativeAll>): void { builder .from(AccountOpenedDeclarativeAll) .fromAll(_ => _ .set(m => m.accountId) .toEventSourceId()); }}With Event-Specific Mappings
Section titled “With Event-Specific Mappings”FromAll can sit beside event-specific From mappings, but the FromAll mapping also processes event types not shown in this example. Those events can create instances without the event-specific business fields. If metadata should update only for the events listed in From, use FromEvery instead.
using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record OrderCreatedDeclarativeAll(string OrderNumber);
[EventType]public record OrderShippedDeclarativeAll(string TrackingNumber);
public record OrderDeclarativeAll( string OrderNumber, string Status, DateTimeOffset LastModified);
public class OrderDeclarativeAllProjection : IProjectionFor<OrderDeclarativeAll>{ public void Define(IProjectionBuilderFor<OrderDeclarativeAll> builder) => builder .FromAll(_ => _ .Set(m => m.LastModified) .ToEventContextProperty(c => c.Occurred)) .From<OrderCreatedDeclarativeAll>(_ => _ .Set(m => m.OrderNumber).To(e => e.OrderNumber) .Set(m => m.Status) .ToValue("Placed")) .From<OrderShippedDeclarativeAll>(_ => _ .Set(m => m.Status) .ToValue("Shipped"));}// Requires io.cratis:chronicle 6.5.0 or later.import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.projections.IProjectionBuilderForimport io.cratis.chronicle.projections.IProjectionFor
@EventTypedata class OrderCreatedDeclarativeAll(val orderNumber: String)
@EventTypedata class OrderShippedDeclarativeAll(val trackingNumber: String)
data class OrderDeclarativeAll( val orderNumber: String = "", val status: String = "", val lastModified: String = "")
class OrderDeclarativeAllProjection : IProjectionFor<OrderDeclarativeAll> { override fun define(builder: IProjectionBuilderFor<OrderDeclarativeAll>) { builder .fromAll { it.set(OrderDeclarativeAll::lastModified).toEventContextProperty("occurred") } .from(OrderCreatedDeclarativeAll::class) { it.set(OrderDeclarativeAll::status).toValue("Placed") } .from(OrderShippedDeclarativeAll::class) { it.set(OrderDeclarativeAll::status).toValue("Shipped") } }}// Requires io.cratis:chronicle 6.5.0 or later.import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.projections.IProjectionBuilderFor;import io.cratis.chronicle.projections.IProjectionFor;
@EventTyperecord OrderCreatedDeclarativeAll(String orderNumber) {}
@EventTyperecord OrderShippedDeclarativeAll(String trackingNumber) {}
class OrderDeclarativeAll { public String orderNumber = ""; public String status = ""; public String lastModified = "";}
class OrderDeclarativeAllProjection implements IProjectionFor<OrderDeclarativeAll> { @Override public void define(IProjectionBuilderFor<OrderDeclarativeAll> builder) { builder .fromAll(feb -> { feb.set("lastModified").toEventContextProperty("occurred"); }) .from(OrderCreatedDeclarativeAll.class, fb -> { fb.<String>set("status").toValue("Placed"); }) .from(OrderShippedDeclarativeAll.class, fb -> { fb.<String>set("status").toValue("Shipped"); }); }}defmodule MyApp.Events.OrderCreatedDeclarativeAll do use Chronicle.Events.EventType, id: "order-created-declarative-all"
defstruct [:order_number]end
defmodule MyApp.Events.OrderShippedDeclarativeAll do use Chronicle.Events.EventType, id: "order-shipped-declarative-all"
defstruct [:tracking_number]end
defmodule MyApp.ReadModels.OrderDeclarativeAll do use Chronicle.ReadModels.ReadModel
defstruct [:order_number, :status, :last_modified]end
defmodule MyApp.Projections.OrderDeclarativeAllProjection do use Chronicle.Projections.Projection, model: MyApp.ReadModels.OrderDeclarativeAll
alias MyApp.Events.{OrderCreatedDeclarativeAll, OrderShippedDeclarativeAll}
# Elixir's from_every excludes child-projection events by default — the # same default FromAll uses in .NET. from_every set: [last_modified: :occurred]
from OrderCreatedDeclarativeAll, set: [ order_number: :order_number, status: "$value(Placed)" ]
from OrderShippedDeclarativeAll, set: [status: "$value(Shipped)"]endimport { eventType, IProjectionBuilderFor, IProjectionFor, projection } from '@cratis/chronicle';import { field } from '@cratis/fundamentals';
@eventType()export class OrderCreatedDeclarativeAll { @field(String) readonly orderNumber: string;
constructor(orderNumber: string) { this.orderNumber = orderNumber; }}
@eventType()export class OrderShippedDeclarativeAll { @field(String) readonly trackingNumber: string;
constructor(trackingNumber: string) { this.trackingNumber = trackingNumber; }}
export class OrderDeclarativeAll { orderNumber = ''; status = ''; lastModified = new Date();}
@projection('', OrderDeclarativeAll)export class OrderDeclarativeAllProjection implements IProjectionFor<OrderDeclarativeAll> { define(builder: IProjectionBuilderFor<OrderDeclarativeAll>): void { builder .fromAll(_ => _ .set(m => m.lastModified) .toEventContextProperty('occurred')) .from(OrderCreatedDeclarativeAll, _ => _ .set(m => m.status) .toValue('Placed')) .from(OrderShippedDeclarativeAll, _ => _ .set(m => m.status) .toValue('Shipped')); }}Counting Into A Dictionary With A Dynamic Key
Section titled “Counting Into A Dictionary With A Dynamic Key”FromAll also supports Count, Increment, and Decrement against a dictionary-typed property, where the key is resolved per event from a value on the EventContext — for example, one counter per event type, keyed by the event type identifier. The dictionary’s value type is always int64 for these operations; the key is always string.
using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record UserRegisteredForEventCounts(string Name);
[EventType]public record OrderPlacedForEventCounts(string OrderId);
public record EventTypeCountsReadModel( Guid Id, Dictionary<string, int> EventCountByType, DateTimeOffset LastEventOccurred);
public class EventTypeCountsProjection : IProjectionFor<EventTypeCountsReadModel>{ public void Define(IProjectionBuilderFor<EventTypeCountsReadModel> builder) => builder .FromAll(_ => _ .Count(m => m.EventCountByType, c => c.EventType.Id) .Set(m => m.LastEventOccurred).ToEventContextProperty(c => c.Occurred));}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.projections.IProjectionBuilderForimport io.cratis.chronicle.projections.IProjectionFor
@EventTypedata class UserRegisteredForEventCounts(val name: String)
@EventTypedata class OrderPlacedForEventCounts(val orderId: String)
data class EventTypeCountsReadModel( val id: String = "", val eventCountByType: MutableMap<String, Long> = mutableMapOf())
class EventTypeCountsProjection : IProjectionFor<EventTypeCountsReadModel> { override fun define(builder: IProjectionBuilderFor<EventTypeCountsReadModel>) { builder .fromAll { feb -> feb.count(EventTypeCountsReadModel::eventCountByType, "eventType.id") } }}import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.projections.IProjectionBuilderFor;import io.cratis.chronicle.projections.IProjectionFor;
import java.util.HashMap;import java.util.Map;
@EventTyperecord UserRegisteredForEventCounts(String name) {}
@EventTyperecord OrderPlacedForEventCounts(String orderId) {}
class EventTypeCountsReadModel { public String id = ""; public Map<String, Long> eventCountByType = new HashMap<>();}
class EventTypeCountsProjection implements IProjectionFor<EventTypeCountsReadModel> { @Override public void define(IProjectionBuilderFor<EventTypeCountsReadModel> builder) { builder .fromAll(feb -> { feb.count("eventCountByType", "eventType.id"); }); }}defmodule MyApp.Events.UserRegisteredForEventCounts do use Chronicle.Events.EventType, id: "user-registered-for-event-counts-v1"
defstruct [:name]end
defmodule MyApp.Events.OrderPlacedForEventCounts do use Chronicle.Events.EventType, id: "order-placed-for-event-counts-v1"
defstruct [:order_id]end
defmodule MyApp.ReadModels.EventTypeCountsReadModel do use Chronicle.ReadModels.ReadModel
defstruct [:event_count_by_type]end
defmodule MyApp.Projections.EventTypeCountsProjection do use Chronicle.Projections.Projection, model: MyApp.ReadModels.EventTypeCountsReadModel
from_every increment: [event_count_by_type: {:event_context, :type}]endimport { eventType, IProjectionBuilderFor, IProjectionFor, projection } from '@cratis/chronicle';import { field } from '@cratis/fundamentals';
@eventType()export class UserRegisteredForEventCounts { @field(String) readonly name: string;
constructor(name: string) { this.name = name; }}
@eventType()export class OrderPlacedForEventCounts { @field(String) readonly orderId: string;
constructor(orderId: string) { this.orderId = orderId; }}
export class EventTypeCountsReadModel { eventCountByType: Record<string, number> = {}; lastEventOccurred = new Date();}
@projection('', EventTypeCountsReadModel)export class EventTypeCountsProjection implements IProjectionFor<EventTypeCountsReadModel> { define(builder: IProjectionBuilderFor<EventTypeCountsReadModel>): void { builder .fromAll(_ => _ .count(m => m.eventCountByType, 'eventType.id') .set(m => m.lastEventOccurred).toEventContextProperty('occurred')); }}The model-bound [FromAll] attribute does not yet support this dictionary form — use the fluent API above until it does.
FromAll And FromEvery
Section titled “FromAll And FromEvery”| API | Use it when |
|---|---|
FromAll | You are using the .NET declarative projection API and want to express an all-events mapping. |
FromEvery | You want mappings applied to the projection’s own handled event types, without subscribing to unrelated event types. |
Prefer event context sources for audit fields because every event has the same context shape. Use event payload properties only when the event contracts intentionally share the same property.