public When_multiple_conditions_are_registered_on_a_projection() { When(() => { action = () => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder.HandleProjectionModificationsAs((key, context, projector, options) => { throw new InvalidOperationException("Modification should not be called."); }); mapBuilder.HandleProjectionDeletionsAs((key, context, options) => { throw new InvalidOperationException("Deletion should not be called."); }); mapBuilder.HandleCustomActionsAs((context, projector) => { throw new InvalidOperationException("Custom action should not be called."); }); mapBuilder.Map <ProductAddedToCatalogEvent>() .When(e => e.Category == "Hybrids") .AsUpdateOf(e => e.ProductKey).Using((p, e, ctx) => p.Category = e.Category); mapBuilder.Map <ProductAddedToCatalogEvent>() .When(e => e.Category == "Electrics") .AsDeleteOf(e => e.ProductKey); var map = mapBuilder.Build(); }; }); }
private EventMapBuilder <Dictionary <Guid, PaymentModel> > CreatePaymentEventMap() { var mapBuilder = new EventMapBuilder <Dictionary <Guid, PaymentModel> >(); mapBuilder.Map <OrderPaymentCreated>().As((OrderPayment, events) => { CreatePayment(OrderPayment); }); mapBuilder.Map <OrderPaymentPaid>().As((OrderPayment, events) => { UpdateStatus(OrderPayment); }); return(mapBuilder); }
public When_an_updating_event_should_ignore_missing_projections() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder .Map <ProductAddedToCatalogEvent>() .AsUpdateOf(e => e.ProductKey) .IgnoringMisses() .Using((p, e, ctx) => { p.Category = e.Category; return(Task.FromResult(0)); }); map = mapBuilder.Build(new ProjectorMap <ProductCatalogEntry, string, ProjectionContext> { Update = (key, context, projector, createIfMissing) => Task.FromResult(false) }); }); WhenLater(async() => { await map.Handle( new ProductAddedToCatalogEvent { Category = "Hybrids", ProductKey = "c350E" }, new ProjectionContext()); }); }
public When_an_event_is_mapped_as_a_delete() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder .Map <ProductDiscontinuedEvent>() .AsDeleteOf(e => e.ProductKey) .ThrowingIfMissing(); map = mapBuilder.Build(new ProjectorMap <ProductCatalogEntry, string, ProjectionContext> { Delete = (key, context) => { isDeleted = true; return(Task.FromResult(true)); } }); }); When(async() => { await map.Handle( new ProductDiscontinuedEvent { ProductKey = "c350E" }, new ProjectionContext()); }); }
public When_a_condition_is_not_met() { Given(() => { var mapBuilder = new EventMapBuilder <object>(); mapBuilder.Map <ProductAddedToCatalogEvent>() .When(e => e.Category == "Electric") .As((e, ctx) => { projection.Category = e.Category; return(Task.FromResult(0)); }); mapBuilder.HandleCustomActionsAs((context, projector) => { throw new InvalidOperationException("Custom action should not be called."); }); map = mapBuilder.Build(); }); When(async() => { await map.Handle( new ProductAddedToCatalogEvent { Category = "Hybrids", ProductKey = "c350E" }, new object()); }); }
public When_deleting_a_non_existing_event_should_be_handled_manually() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder .Map <ProductDiscontinuedEvent>() .AsDeleteOf(e => e.ProductKey) .HandlingMissesUsing((key, context) => { missedKey = key; }); map = mapBuilder.Build(new ProjectorMap <ProductCatalogEntry, string, ProjectionContext> { Delete = (key, context) => Task.FromResult(false) }); }); WhenLater(async() => { await map.Handle( new ProductDiscontinuedEvent { ProductKey = "c350E" }, new ProjectionContext()); }); }
public When_deleting_a_non_existing_event_should_be_handled_manually_from_context() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder .Map <ProductDiscontinuedEvent>() .AsDeleteOf((e, context) => context.EventHeaders["ProductId"] as string) .HandlingMissesUsing((key, context) => { missedKey = key; }); map = mapBuilder.Build(new ProjectorMap <ProductCatalogEntry, string, ProjectionContext> { Delete = (key, context) => Task.FromResult(false) }); }); WhenLater(async() => { await map.Handle( new ProductDiscontinuedEvent { ProductKey = "c350E" }, new ProjectionContext() { EventHeaders = new Dictionary <string, object>(1) { { "ProductId", "1234" } } }); }); }
public When_an_event_is_mapped_as_a_custom_action() { Given(() => { var mapBuilder = new EventMapBuilder <object>(); mapBuilder.Map <ProductDiscontinuedEvent>().As((@event, context) => { involvedKey = @event.ProductKey; return(Task.FromResult(0)); }); map = mapBuilder.Build(new ProjectorMap <object> { Custom = (context, projector) => projector() }); }); When(async() => { await map.Handle( new ProductDiscontinuedEvent { ProductKey = "c350E" }, new object()); }); }
public When_a_condition_is_met() { Given(() => { var mapBuilder = new EventMapBuilder <object>(); mapBuilder .Map <ProductAddedToCatalogEvent>() .When(e => e.Category == "Hybrids") .As((e, ctx) => { involvedKey = e.ProductKey; return(Task.FromResult(0)); }); map = mapBuilder.Build(new ProjectorMap <object> { Custom = (context, projector) => projector() }); }); When(async() => { await map.Handle( new ProductAddedToCatalogEvent { Category = "Hybrids", ProductKey = "c350E" }, new object()); }); }
public static async Task PlayThing() { var mapBuilder = new EventMapBuilder <GiftCardProjectionContext>(); mapBuilder .Map <RedeemedEvent>() .When((evt, context) => { Console.WriteLine("in conditional"); return(Task.FromResult(evt.Credits > 0)); }) .As((evt, context) => { Console.WriteLine("in as"); return(Task.CompletedTask); }); var projectorMap = new ProjectorMap <GiftCardProjectionContext> { Custom = (context, projector) => { Console.WriteLine("in projector"); return(projector()); } }; var map = mapBuilder.Build(projectorMap); var a = await map.Handle(new RedeemedEvent(5), new GiftCardProjectionContext()); Console.ReadLine(); }
private EventMapBuilder <Balance> CreateBalanceEventMap() { var mapBuilder = new EventMapBuilder <Balance>(); mapBuilder.Map <OrderPaymentPaid>().As((OrderPayment, balance) => { AddBalance(OrderPayment, balance); }); return(mapBuilder); }
private void BuildCountryProjector() { var countryMapBuilder = new EventMapBuilder <CountryLookup, string, ProjectionContext>(); countryMapBuilder .Map <CountryRegisteredEvent>() .AsCreateOf(anEvent => anEvent.Code) .Using((country, anEvent) => country.Name = anEvent.Name); countryLookupProjector = new ExampleProjector <CountryLookup>(countryMapBuilder, store); }
public BalanceProjection(IStreamStore streamStore, StreamId streamId) { var mapBuilder = new EventMapBuilder <Balance>(); mapBuilder.Map <Deposited>().As((deposited, balance) => { balance.Add(deposited.Amount); }); mapBuilder.Map <Withdrawn>().As((withdrawn, balance) => { balance.Subtract(withdrawn.Amount); }); _map = mapBuilder.Build(new ProjectorMap <Balance>() { Custom = (context, projector) => projector() }); streamStore.SubscribeToStream(streamId, null, StreamMessageReceived); }
private void BuildCountryProjector() { var countryMapBuilder = new EventMapBuilder <CountryLookup, string, RavenProjectionContext>(); countryMapBuilder .Map <CountryRegisteredEvent>() .AsCreateOf(anEvent => anEvent.Code) .Using((country, anEvent) => country.Name = anEvent.Name); countryProjector = new RavenChildProjector <CountryLookup>(countryMapBuilder, (lookup, key) => lookup.Id = key) { Cache = new LruProjectionCache <CountryLookup>(20000, TimeSpan.FromSeconds(30), TimeSpan.FromMinutes(2), p => p.Id, () => DateTime.UtcNow) }; }
private void BuildCountryProjector() { var countryMapBuilder = new EventMapBuilder <CountryLookup, string, RavenProjectionContext>(); countryMapBuilder .Map <CountryRegisteredEvent>() .AsCreateOf(anEvent => anEvent.Code) .Using((country, anEvent) => country.Name = anEvent.Name); countryProjector = new RavenChildProjector <CountryLookup>(countryMapBuilder) { Cache = cache }; }
public When_a_condition_is_not_met_on_a_projection() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder.HandleProjectionModificationsAs(async(key, context, projector, options) => { projection = new ProductCatalogEntry { Id = key, }; await projector(projection); }); mapBuilder .Map <ProductAddedToCatalogEvent>() .When(e => e.Category == "Electric") .AsUpdateOf(e => e.ProductKey) .Using((p, e, ctx) => { p.Category = e.Category; return(Task.FromResult(0)); }); mapBuilder.HandleProjectionDeletionsAs((key, context, options) => { throw new InvalidOperationException("Deletion should not be called."); }); mapBuilder.HandleCustomActionsAs((context, projector) => { throw new InvalidOperationException("Custom action should not be called."); }); map = mapBuilder.Build(); }); When(async() => { await map.Handle( new ProductAddedToCatalogEvent { Category = "Hybrids", ProductKey = "c350E" }, new ProjectionContext()); }); }
public When_an_event_is_mapped_as_a_create_if_does_not_exist() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder .Map <ProductAddedToCatalogEvent>() .AsCreateIfDoesNotExistOf(e => e.ProductKey) .Using((p, e, ctx) => { p.Category = e.Category; return(Task.FromResult(0)); }); mapBuilder.HandleProjectionModificationsAs(async(key, context, projector, options) => { projection = new ProductCatalogEntry { Id = key, }; this.options = options; await projector(projection); }); mapBuilder.HandleProjectionDeletionsAs((key, context, options) => { throw new InvalidOperationException("Deletion should not be called."); }); mapBuilder.HandleCustomActionsAs((context, projector) => { throw new InvalidOperationException("Custom action should not be called."); }); map = mapBuilder.Build(); }); When(async() => { await map.Handle( new ProductAddedToCatalogEvent { Category = "Hybrids", ProductKey = "c350E" }, new ProjectionContext()); }); }
public When_a_creating_event_should_allow_manual_handling_of_duplicates() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder .Map <ProductAddedToCatalogEvent>() .AsCreateOf(e => e.ProductKey) .HandlingDuplicatesUsing((duplicate, @event, context) => { duplicateProjection = existingProjection; return(true); }) .Using((p, e, ctx) => { p.Category = e.Category; return(Task.FromResult(0)); }); existingProjection = new ProductCatalogEntry { Id = "c350E", Category = "OldCategory", }; map = mapBuilder.Build(new ProjectorMap <ProductCatalogEntry, string, ProjectionContext> { Create = async(key, context, projector, shouldOverwrite) => { if (shouldOverwrite(existingProjection)) { await projector(existingProjection); } } }); }); When(async() => { await map.Handle(new ProductAddedToCatalogEvent { Category = "NewCategory", ProductKey = "c350E" }, new ProjectionContext()); }); }
private void BuildCountryProjector() { var countryMapBuilder = new EventMapBuilder <CountryLookup, string, NHibernateProjectionContext>(); countryMapBuilder .Map <CountryRegisteredEvent>() .AsCreateOf(anEvent => anEvent.Code) .Using((country, anEvent) => country.Name = anEvent.Name); countryProjector = new NHibernateChildProjector <CountryLookup, string>(countryMapBuilder, (lookup, identity) => lookup.Id = identity) { // We use a local LRU cache for the countries to avoid unnecessary database lookups. Cache = new LruProjectionCache <CountryLookup, string>( 20000, TimeSpan.FromSeconds(30), TimeSpan.FromMinutes(2), p => p.Id, () => DateTime.UtcNow) }; }
private EntityFrameworkProjector <Transaction, Guid, ProjectorState> BuildTransactionProjector(Func <DbContext> dbContextProvider) { var transactionMapBuilder = new EventMapBuilder <Transaction, Guid, EntityFrameworkProjectionContext>(); transactionMapBuilder .Map <AmountDeposited>() .AsCreateOf(@event => @event.TransactionId) .Using((entity, @event) => { entity.Type = TransactionType.Deposit; entity.Amount = @event.Amount; entity.AccountId = @event.AccountId; entity.CreatedOn = DateTime.UtcNow; }); return(new EntityFrameworkProjector <Transaction, Guid, ProjectorState>(dbContextProvider, transactionMapBuilder, (entity, key) => entity.Id = key)); }
public When_an_updating_event_should_create_a_missing_projection_from_context() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder .Map <ProductAddedToCatalogEvent>() .AsUpdateOf((e, context) => context.EventHeaders["ProductId"] as string) .CreatingIfMissing() .Using((p, e, ctx) => { p.Category = e.Category; return(Task.FromResult(0)); }); map = mapBuilder.Build(new ProjectorMap <ProductCatalogEntry, string, ProjectionContext> { Update = (key, context, projector, createIfMissing) => { shouldCreate = true; return(Task.FromResult(0)); } }); }); When(async() => { await map.Handle( new ProductAddedToCatalogEvent { Category = "Hybrids", ProductKey = "c350E" }, new ProjectionContext() { EventHeaders = new Dictionary <string, object>(1) { { "ProductId", "1234" } } }); }); }
public When_a_creating_event_must_ignore_an_existing_projection() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder .Map <ProductAddedToCatalogEvent>() .AsCreateOf(e => e.ProductKey).IgnoringDuplicates() .Using((p, e, ctx) => { p.Category = e.Category; return(Task.FromResult(0)); }); existingProjection = new ProductCatalogEntry { Id = "c350E", Category = "Fosile", }; map = mapBuilder.Build(new ProjectorMap <ProductCatalogEntry, string, ProjectionContext> { Create = async(key, context, projector, shouldOverwrite) => { if (shouldOverwrite(existingProjection)) { await projector(existingProjection); } } }); }); When(async() => { await map.Handle( new ProductAddedToCatalogEvent { Category = "Hybrids", ProductKey = "c350E" }, new ProjectionContext()); }); }
public When_an_event_is_mapped_as_a_delete_if_exists() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder.Map <ProductDiscontinuedEvent>().AsDeleteIfExistsOf(e => e.ProductKey); mapBuilder.HandleProjectionDeletionsAs((key, context, options) => { projection = new ProductCatalogEntry { Id = key, Deleted = true }; this.options = options; return(Task.FromResult(0)); }); mapBuilder.HandleProjectionModificationsAs((key, context, projector, options) => { throw new InvalidOperationException("Modification should not be called."); }); mapBuilder.HandleCustomActionsAs((context, projector) => { throw new InvalidOperationException("Custom action should not be called."); }); map = mapBuilder.Build(); }); When(async() => { await map.Handle( new ProductDiscontinuedEvent { ProductKey = "c350E" }, new ProjectionContext()); }); }
public When_an_event_is_mapped_as_a_custom_action_on_a_projection() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder.HandleCustomActionsAs((context, projector) => { customActionDecoratorExecuted = true; return(projector()); }); mapBuilder.HandleProjectionModificationsAs((key, context, projector, options) => { throw new InvalidOperationException("Modification should not be called."); }); mapBuilder.HandleProjectionDeletionsAs((key, context, options) => { throw new InvalidOperationException("Deletion should not be called."); }); mapBuilder.Map <ProductDiscontinuedEvent>().As((@event, context) => { involvedKey = @event.ProductKey; return(Task.FromResult(0)); }); map = mapBuilder.Build(); }); When(async() => { await map.Handle( new ProductDiscontinuedEvent { ProductKey = "c350E" }, new ProjectionContext()); }); }
public When_a_global_filter_is_not_met() { Given(() => { var mapBuilder = new EventMapBuilder <object>() .Where((@event, context) => { if (@event is ProductAddedToCatalogEvent addedEvent) { return(Task.FromResult(addedEvent.Category == "Electric")); } return(Task.FromResult(true)); }); mapBuilder .Map <ProductAddedToCatalogEvent>() .As((e, ctx) => { involvedKey = e.ProductKey; return(Task.FromResult(0)); }); map = mapBuilder.Build(new ProjectorMap <object> { Custom = (context, projector) => projector() }); }); When(async() => { await map.Handle( new ProductAddedToCatalogEvent { Category = "Hybrids", ProductKey = "c350E" }, new object()); }); }
public When_event_should_create_a_new_projection_from_context() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder.Map <ProductAddedToCatalogEvent>().AsCreateOf((e, context) => context.EventHeaders["ProductId"] as string).Using((p, e, ctx) => { p.Category = e.Category; return(Task.FromResult(0)); }); map = mapBuilder.Build(new ProjectorMap <ProductCatalogEntry, string, ProjectionContext> { Create = async(key, context, projector, shouldOverwrite) => { projection = new ProductCatalogEntry { Id = key, }; await projector(projection); } }); }); When(async() => { await map.Handle(new ProductAddedToCatalogEvent { Category = "Hybrids" }, new ProjectionContext() { EventHeaders = new Dictionary <string, object>(1) { { "ProductId", "1234" } } }); }); }
public When_an_updating_event_should_throw_on_misses() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder.Map <ProductAddedToCatalogEvent>().AsUpdateOf(e => e.ProductKey).Using((p, e, ctx) => { p.Category = e.Category; return(Task.FromResult(0)); }); existingProjection = new ProductCatalogEntry { Id = "c350E", Category = "OldCategory", }; map = mapBuilder.Build(new ProjectorMap <ProductCatalogEntry, string, ProjectionContext> { Update = async(key, context, projector, createIfMissing) => { if (createIfMissing()) { await projector(existingProjection); } } }); }); WhenLater(async() => { await map.Handle( new ProductAddedToCatalogEvent { ProductKey = "c350E", Category = "NewCategory" }, new ProjectionContext()); }); }
public When_multiple_conditions_are_registered() { When(() => { action = () => { var mapBuilder = new EventMapBuilder <object>(); mapBuilder.Map <ProductAddedToCatalogEvent>() .When(e => e.Category != "Hybrids") .When(e => e.Category != "Electrics") .As((e, ctx) => { }); var map = mapBuilder.Build(new ProjectorMap <object> { Custom = (context, projector) => throw new InvalidOperationException("Custom action should not be called.") }); }; });
public When_event_should_create_a_new_projection() { Given(() => { var mapBuilder = new EventMapBuilder <ProductCatalogEntry, string, ProjectionContext>(); mapBuilder.Map <ProductAddedToCatalogEvent>().AsCreateOf(e => e.ProductKey).Using((p, e, ctx) => { p.Category = e.Category; return(Task.FromResult(0)); }); map = mapBuilder.Build(new ProjectorMap <ProductCatalogEntry, string, ProjectionContext> { Create = async(key, context, projector, shouldOverwrite) => { projection = new ProductCatalogEntry { Id = key, }; await projector(projection); } }); }); When(async() => { await map.Handle(new ProductAddedToCatalogEvent { Category = "Hybrids", ProductKey = "c350E" }, new ProjectionContext()); }); }
private void BuildDocumentProjector() { var documentMapBuilder = new EventMapBuilder <DocumentCountProjection, string, RavenProjectionContext>(); documentMapBuilder .Map <WarrantAssignedEvent>() .AsCreateOf(anEvent => anEvent.Number) .Using((document, anEvent) => { document.Type = "Warrant"; document.Kind = anEvent.Kind; document.Country = anEvent.Country; document.State = anEvent.InitialState; }); documentMapBuilder .Map <CertificateIssuedEvent>() .AsCreateOf(anEvent => anEvent.Number) .Using((document, anEvent) => { document.Type = "Certificate"; document.Kind = anEvent.Kind; document.Country = anEvent.Country; document.State = anEvent.InitialState; }); documentMapBuilder .Map <ConstitutionEstablishedEvent>() .AsUpdateOf(anEvent => anEvent.Number) .Using((document, anEvent) => { document.Type = "Constitution"; document.Kind = anEvent.Kind; document.Country = anEvent.Country; document.State = anEvent.InitialState; }); documentMapBuilder .Map <LicenseGrantedEvent>() .AsCreateOf(anEvent => anEvent.Number) .Using((document, anEvent) => { document.Type = "Audit"; document.Kind = anEvent.Kind; document.Country = anEvent.Country; document.State = anEvent.InitialState; }); documentMapBuilder .Map <ContractNegotiatedEvent>() .AsCreateOf(anEvent => anEvent.Number) .Using((document, anEvent) => { document.Type = "Task"; document.Kind = anEvent.Kind; document.Country = anEvent.Country; document.State = anEvent.InitialState; }); documentMapBuilder .Map <BondIssuedEvent>() .AsCreateOf(anEvent => anEvent.Number) .Using((document, anEvent) => { document.Type = "IsolationCertificate"; document.Kind = anEvent.Kind; document.Country = anEvent.Country; document.State = anEvent.InitialState; }); documentMapBuilder .Map <AreaRestrictedEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => document.RestrictedArea = anEvent.Area); documentMapBuilder .Map <AreaRestrictionCancelledEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => document.RestrictedArea = null); documentMapBuilder .Map <StateTransitionedEvent>() .When(anEvent => anEvent.State != "Closed") .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => document.State = anEvent.State); documentMapBuilder .Map <StateRevertedEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => document.State = anEvent.State); documentMapBuilder .Map <DocumentArchivedEvent>() .AsDeleteOf(anEvent => anEvent.DocumentNumber); documentMapBuilder .Map <CountryCorrectedEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => document.Country = anEvent.Country); documentMapBuilder .Map <NextReviewScheduledEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => document.NextReviewAt = anEvent.NextReviewAt); documentMapBuilder .Map <LifetimeRestrictedEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => document.LifetimePeriodEnd = anEvent.PeriodEnd); documentMapBuilder .Map <LifetimeRestrictionRemovedEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => document.LifetimePeriodEnd = null); documentMapBuilder .Map <ValidityPeriodPlannedEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => { ValidityPeriod period = document.GetOrAddPeriod(anEvent.Sequence); period.From = anEvent.From; period.To = anEvent.To; }); documentMapBuilder .Map <ValidityPeriodResetEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => { ValidityPeriod period = document.GetOrAddPeriod(anEvent.Sequence); period.From = null; period.To = null; }); documentMapBuilder .Map <ValidityPeriodApprovedEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => { ValidityPeriod period = document.GetOrAddPeriod(anEvent.Sequence); period.Status = "Valid"; ValidityPeriod lastValidPeriod = document.Periods.LastOrDefault(aPeriod => aPeriod.Status == "Valid"); ValidityPeriod[] contiguousPeriods = GetPreviousContiguousValidPeriods(document.Periods, lastValidPeriod) .OrderBy(x => x.Sequence).ToArray(); document.StartDateTime = contiguousPeriods.Any() ? contiguousPeriods.First().From : DateTime.MinValue; document.EndDateTime = contiguousPeriods.Any() ? contiguousPeriods.Last().To : DateTime.MaxValue; }); documentMapBuilder .Map <ValidityPeriodClosedEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => { ValidityPeriod period = document.GetOrAddPeriod(anEvent.Sequence); period.Status = "Closed"; period.To = anEvent.ClosedAt; }); documentMapBuilder .Map <ValidityPeriodCanceledEvent>() .AsUpdateOf(anEvent => anEvent.DocumentNumber) .Using((document, anEvent) => { ValidityPeriod period = document.GetOrAddPeriod(anEvent.Sequence); period.Status = "Canceled"; }); documentProjector = new RavenProjector <DocumentCountProjection>( sessionFactory, documentMapBuilder, (projection, identity) => projection.Id = identity, new[] { countryProjector }) { BatchSize = 20, Cache = cache }; }