public async Task Getting_and_storing_projections_and_cursors_can_operate_transactionally_via_a_closure()
        {
            BalanceProjection finalProjection = null;

            var catchup = StreamCatchup.Create(stream);
            FetchAndSaveProjection <BalanceProjection> fetchAndSaveProjection = (async(id, callAggregatorPipeline) =>
            {
                using (var transaction = new TransactionScope())
                {
                    // e.g. get the projection / cursor from the store
                    var proj = new BalanceProjection
                    {
                        CursorPosition = 5
                    };

                    proj = await callAggregatorPipeline(proj);

                    finalProjection = proj;

                    // save the projection / cursor back to the store
                    transaction.Complete();
                }
            });

            catchup.Subscribe(new BalanceProjector(), fetchAndSaveProjection);

            store.WriteEvents(streamId, amount: 100m, howMany: 5);

            await catchup.RunSingleBatch();

            finalProjection.Balance.Should().Be(100m);
        }
Пример #2
0
        public async Task A_pipeline_can_be_used_to_continue_on_exceptions()
        {
            var aggregator = Aggregator
                             .Create <BalanceProjection, IDomainEvent>((projection, events) =>
            {
                Task.Run(() =>
                {
                    throw new Exception("DRAT!");
                });
            })
                             .Pipeline(async(projection, events, next) =>
            {
                try
                {
                    return(await next(projection, events));
                }
                catch (Exception)
                {
                    return(projection);
                }
            });

            var balanceProjection  = new BalanceProjection();
            var returnedProjection = await aggregator.Aggregate(balanceProjection, null);

            balanceProjection.Should().BeSameAs(returnedProjection);
        }
Пример #3
0
        public async Task An_aggregator_can_be_short_circuited_using_Pipeline_and_returning_rather_than_calling_next()
        {
            var wasCalled = false;

            var aggregator = Aggregator.Create <BalanceProjection, IDomainEvent>((projection, events) => wasCalled = true)
                             .Pipeline(async(projection, events, next) => projection);

            var balanceProjection  = new BalanceProjection();
            var returnedProjection = await aggregator.Aggregate(balanceProjection, null);

            wasCalled.Should().BeFalse();
            balanceProjection.Should().BeSameAs(returnedProjection);
        }
Пример #4
0
        public async Task When_a_stream_has_no_events_after_the_projection_cursor_then_no_data_is_fetched()
        {
            var initialProjection = new BalanceProjection
            {
                Balance        = 321m,
                CursorPosition = 5
            };

            var finalProjection = await stream.Aggregate(AccountBalanceProjector(),
                                                         initialProjection);

            finalProjection.ShouldBeEquivalentTo(initialProjection,
                                                 "the projection cursor is past the end of the event stream so no events should be applied");
        }
Пример #5
0
        public async Task Projections_can_be_updated_from_a_previously_stored_state()
        {
            var projection = new BalanceProjection
            {
                Balance        = 100m,
                CursorPosition = 2
            };

            var balanceProjection = await stream.Aggregate(AccountBalanceProjector(),
                                                           projection);

            balanceProjection.Balance
            .Should()
            .Be(111m,
                "the first two items in the sequence should not have been applied, and the prior projection state should have been used");
        }
Пример #6
0
        public async Task The_same_projection_is_not_queried_more_than_once_during_a_batch()
        {
            var streamId   = "hello";
            var projection = new BalanceProjection
            {
                CursorPosition = 1
            };

            var getCount        = 0;
            var projectionStore = ProjectionStore.Create <string, BalanceProjection>(
                get: async key =>
            {
                if (key.Contains(streamId))
                {
                    Console.WriteLine("Get");
                    Interlocked.Increment(ref getCount);
                }
                return(projection);
            },
                put: async(key, p) =>
            {
                if (streamId == key)
                {
                    Console.WriteLine("Put");
                }
                projection = p;
            });

            var catchup = StreamCatchup.All(streamSource.StreamPerAggregate());

            catchup.Subscribe(new BalanceProjector(), projectionStore);

            store.WriteEvents(streamId);
            store.WriteEvents(streamId);
            store.WriteEvents(streamId);

            await catchup.RunSingleBatch();

            getCount.Should().Be(1);
        }