Skip to content

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.

Map event context metadata when the read model needs to know when it was last touched.

Declarative FromEvery
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));
}

View C# snippet source on GitHub

Every-event mappings can map more than one context field.

Map multiple context fields
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));
}

View C# snippet source on GitHub

Map the event source id when the read model’s primary identifier is not otherwise populated from each event payload.

Map the event source id
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());
}

View C# snippet source on GitHub

In .NET, FromEvery and FromAll both support .Set(m => m.Status).ToValue("active") to assign a constant whenever a matching event is processed. Concept values are unwrapped. Enums with an int underlying type use their numeric value; other enums use their name. Use .ToValue<string?>(null) to clear a nullable property.

The value is not type-checked against the read model property. The every-event builder does not know the property’s type, so ToValue infers it from the value you pass, and a value of the wrong type compiles and is not reported when the projection is defined. Pass a value of the property’s own type.

The kernel now honors the child-inclusion flag. In .NET, FromEvery includes events handled only by child projections by default, including nested child collections. These mappings update the containing parent using the child’s resolved parent key, not a new root keyed by the child identifier. Existing fluent projections therefore start updating parent audit fields on child-only events.

Call ExcludeChildProjections() to keep every-event mappings local to the level where they are declared. That level’s own from and join events still apply the mappings. In the declaration language, every also includes child events by default; add exclude children to opt out.

Exclude child projection events
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());
}

View C# snippet source on GitHub

Use a root FromAll mapping only when the parent must also observe unrelated event types in the sequence. Its child-inclusion flag is true, so child-only events update their containing parent too. Use FromEvery for audit metadata that should follow just the projection’s handled events.

Include child projection events
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)));
}

View C# snippet source on GitHub

Clients that support multiple every-event declarations merge the property mappings into one projection definition.

Multiple FromEvery declarations
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));
}

View C# snippet source on GitHub

Use caseTypical source
Audit timestampEvent context occurrence time
Event sequencingEvent context sequence number
Correlation trackingEvent context correlation id
Event source identificationEvent source id

Use event-specific mappings when the property should update only for selected event types.