public async Task A_DuckTypeProjector_can_access_the_metadata_of_unknown_event_types_dynamically() { StorableEvent storableEvent = null; using (var db = EventStoreDbContext()) { storableEvent = new StorableEvent { AggregateId = Guid.NewGuid(), StreamName = Any.CamelCaseName(), Type = Any.CamelCaseName(), Body = new { }.ToJson() }; db.Events.Add(storableEvent); await db.SaveChangesAsync(); } IEvent receivedEvent = null; var projector = Projector.CreateFor <dynamic>(e => receivedEvent = e); using (var catchup = CreateReadModelCatchup(projector)) { await catchup.Run(); } long absoluteSequenceNumber = ((IHaveExtensibleMetada)receivedEvent).Metadata.AbsoluteSequenceNumber; absoluteSequenceNumber.Should().Be(storableEvent.Id); }
public async Task Report_projections_can_be_created_using_anonymous_projectors_over_multiple_event_types() { var projector = Projector.Combine( Projector.CreateFor <Placed>(e => { using (var db1 = ReadModelDbContext()) { db1.OrderTallyByStatus(OrderTally.OrderStatus.Pending).Count++; db1.SaveChanges(); } }), Projector.CreateFor <Cancelled>(e => { using (var db2 = ReadModelDbContext()) { db2.OrderTallyByStatus(OrderTally.OrderStatus.Canceled).Count++; db2.OrderTallyByStatus(OrderTally.OrderStatus.Pending).Count--; db2.SaveChanges(); } }), Projector.CreateFor <Delivered>(e => { using (var db3 = ReadModelDbContext()) { db3.OrderTallyByStatus(OrderTally.OrderStatus.Delivered).Count++; db3.OrderTallyByStatus(OrderTally.OrderStatus.Pending).Count--; db3.SaveChanges(); } })).Named("Order status report"); Events.Write(20, _ => new Order.Cancelled()); Events.Write(20, _ => new Order.Delivered()); Events.Write(50, _ => new Order.Placed()); using (var catchup = CreateReadModelCatchup(projector)) { await catchup.Run(); } using (var db = ReadModelDbContext()) { db.Set <OrderTally>() .Single(t => t.Status == "Canceled") .Count .Should() .Be(20); db.Set <OrderTally>() .Single(t => t.Status == "Delivered") .Count .Should() .Be(20); db.Set <OrderTally>() .Single(t => t.Status == "Pending") .Count .Should() .Be(10); } }
public async Task When_classes_not_implementing_IEvent_are_used_to_query_the_event_store_then_only_the_corresponding_events_are_queried() { var eventsQueried = 0; var expectedEventsQueried = 0; Events.Write(20, _ => { Event e = null; switch (Any.Int(1, 3)) { case 1: e = (Event)Events.Any(); break; case 2: e = new Order.ItemAdded(); break; case 3: e = new Order.ItemRemoved(); break; } if (e is Order.ItemAdded || e is Order.ItemRemoved) { expectedEventsQueried++; } e.AggregateId = Guid.NewGuid(); return(e); }); var projector1 = Projector.CreateFor <ItemAdded>(e => { eventsQueried++; }); var projector2 = Projector.CreateFor <ItemRemoved>(e => { eventsQueried++; }); using (var catchup = CreateReadModelCatchup(projector1, projector2)) { await catchup.Run(); } eventsQueried.Should().Be(expectedEventsQueried); }
public async Task When_classes_not_implementing_IEvent_are_used_to_query_the_event_store_then_non_nested_classes_have_their_EventStreamName_set_correctly() { Events.Write(1, _ => new Order.Cancelled()); Cancelled cancelled = null; var projector = Projector.CreateFor <Cancelled>(e => { cancelled = e; }); using (var catchup = CreateReadModelCatchup(projector)) { await catchup.Run(); } cancelled.EventStreamName.Should().Be("Order"); }
public async Task A_DuckTypeProjector_can_access_the_metadata_of_known_event_types_dynamically() { var lastEventId = Events.Write(1, _ => new Order.CustomerInfoChanged()); Order.CustomerInfoChanged receivedEvent = null; var projector = Projector.CreateFor <Order.CustomerInfoChanged>(e => receivedEvent = e); using (var catchup = CreateReadModelCatchup(projector)) { await catchup.Run(); } long absoluteSequenceNumber = receivedEvent.Metadata.AbsoluteSequenceNumber; absoluteSequenceNumber.Should().Be(lastEventId); }
public async Task Duck_projectors_can_access_the_event_properties_of_received_events() { var expectedTimestamp = DateTimeOffset.Parse("2014-07-03"); var expectedAggregateId = Any.Guid(); var receivedAggregateId = new Guid(); var expectedSequenceNumber = Any.PositiveInt(); int receivedSequenceNumber = 0; var receivedTimestamp = new DateTimeOffset(); var receivedEventStreamName = ""; var receivedEventTypeName = ""; using (var db = EventStoreDbContext()) { db.Events.Add(new StorableEvent { AggregateId = expectedAggregateId, SequenceNumber = expectedSequenceNumber, Timestamp = expectedTimestamp, StreamName = "Reporting", Type = "DuckEvent", Body = new { Quacks = 9000 }.ToJson() }); await db.SaveChangesAsync(); } var projector = Projector.CreateFor <Reporting.DuckEvent>(e => { receivedAggregateId = e.AggregateId; receivedSequenceNumber = e.SequenceNumber; receivedTimestamp = e.Timestamp; receivedEventStreamName = e.EventStreamName; receivedEventTypeName = e.EventTypeName; }); using (var catchup = CreateReadModelCatchup(projector)) { await catchup.Run(); } receivedAggregateId.Should().Be(expectedAggregateId); receivedSequenceNumber.Should().Be(expectedSequenceNumber); receivedTimestamp.Should().Be(expectedTimestamp); receivedEventStreamName.Should().Be("Reporting"); receivedEventTypeName.Should().Be("DuckEvent"); }
public async Task When_classes_not_implementing_IEvent_are_used_to_query_the_event_store_then_nested_classes_can_be_used_to_specify_stream_names() { using (var db = EventStoreDbContext()) { Enumerable.Range(1, 5).ForEach(i => db.Events.Add(new StorableEvent { AggregateId = Guid.NewGuid(), StreamName = "Reporting", Type = "DuckEvent", Body = new { Quacks = i }.ToJson() })); Enumerable.Range(1, 5).ForEach(i => db.Events.Add(new StorableEvent { AggregateId = Guid.NewGuid(), StreamName = Any.CamelCaseName(), Type = "DuckEvent", Body = new { Quacks = i }.ToJson() })); await db.SaveChangesAsync(); } var unNestedDucks = 0; var nestedDucks = 0; var projector1 = Projector.CreateFor <DuckEvent>(e => { unNestedDucks++; }); var projector2 = Projector.CreateFor <Reporting.DuckEvent>(e => { nestedDucks++; }); using (var catchup = CreateReadModelCatchup(projector1, projector2)) { await catchup.Run(); } nestedDucks.Should().Be(5); unNestedDucks.Should().Be(10); }
public void When_classes_not_implementing_IEvent_are_used_to_query_the_event_store_then_properties_are_duck_deserialized() { using (var db = new EventStoreDbContext()) { Enumerable.Range(1, 5).ForEach(i => db.Events.Add(new StorableEvent { AggregateId = Guid.NewGuid(), StreamName = "Reporting", Type = "DuckEvent", Body = new { Quacks = i }.ToJson() })); Enumerable.Range(1, 5).ForEach(i => db.Events.Add(new StorableEvent { AggregateId = Guid.NewGuid(), StreamName = Any.CamelCaseName(), Type = "DuckEvent", Body = new { Quacks = i }.ToJson() })); db.SaveChanges(); } var unNestedDuckQuacks = 0; var nestedDuckQuacks = 0; var projector1 = Projector.CreateFor <DuckEvent>(e => { unNestedDuckQuacks += e.Quacks; }); var projector2 = Projector.CreateFor <Reporting.DuckEvent>(e => { nestedDuckQuacks += e.Quacks; }); using (var catchup = CreateReadModelCatchup(projector1, projector2)) { catchup.Run(); } nestedDuckQuacks.Should().Be(15); unNestedDuckQuacks.Should().Be(30); }
public async Task Catchup_continues_when_DuckTypeProjector_throws() { Events.Write(20); int counter = 0; int eventsHandled = 0; var handler = Projector.CreateFor <ItemAdded>(e => { counter++; if (counter == 10) { throw new Exception("oops!"); } eventsHandled++; }); await new ReadModelCatchup(handler) { StartAtEventId = HighestEventId + 1 }.SingleBatchAsync(); eventsHandled.Should().Be(19); }
public async Task Catchup_continues_when_DuckTypeProjector_throws() { Events.Write(20); var counter = 0; var eventsHandled = 0; var handler = Projector.CreateFor <ItemAdded>(e => { counter++; if (counter == 10) { throw new Exception("oops!"); } eventsHandled++; }); await new ReadModelCatchup( eventStoreDbContext: () => EventStoreDbContext(), readModelDbContext: () => ReadModelDbContext(), startAtEventId: HighestEventId + 1, projectors: handler).SingleBatchAsync(); eventsHandled.Should().Be(19); }