public async Task A_stream_can_be_derived_from_an_index_projection_in_order_to_perform_a_reduce_operation()
        {
            store.WriteEvents(i => new AccountOpened
            {
                AccountType = i % 2 == 0
                    ? BankAccountType.Checking
                    : BankAccountType.Savings
            }, howMany: 100);

            var eventsByAggregate = streamSource.StreamPerAggregate()
                                    .Trace()
                                    .Map(ss => ss.Select(s => s.Trace()));

            var indexCatchup = StreamCatchup.All(eventsByAggregate, batchSize: 1);
            var index        = new Projection <ConcurrentBag <AccountOpened>, string>
            {
                Value = new ConcurrentBag <AccountOpened>()
            };

            // subscribe a catchup to the updates stream to build up an index
            indexCatchup.Subscribe(
                Aggregator.Create <Projection <ConcurrentBag <AccountOpened> >, IDomainEvent>(async(p, events) =>
            {
                foreach (var e in events.OfType <AccountOpened>()
                         .Where(e => e.AccountType == BankAccountType.Savings))
                {
                    p.Value.Add(e);
                }

                return(p);
            }).Trace(),
                async(streamId, aggregate) => await aggregate(index));

            // create a catchup over the index
            var savingsAccounts = Stream.Create <IDomainEvent, string>(
                "Savings accounts",
                async q => index.Value.SkipWhile(v => q.Cursor.HasReached(v.CheckpointToken))
                .Take(q.BatchSize ?? 1000));
            var savingsAccountsCatchup = StreamCatchup.Create(savingsAccounts);

            var numberOfSavingsAccounts = new Projection <int, int>();

            savingsAccountsCatchup.Subscribe <Projection <int, int>, IDomainEvent, string>(
                manageProjection: async(streamId, aggregate) =>
            {
                numberOfSavingsAccounts = await aggregate(numberOfSavingsAccounts);
            },
                aggregate: async(c, es) =>
            {
                c.Value += es.Count;
                return(c);
            });

            using (indexCatchup.Poll(TimeSpan.FromMilliseconds(100)))
                using (savingsAccountsCatchup.Poll(TimeSpan.FromMilliseconds(50)))
                {
                    await Wait.Until(() => numberOfSavingsAccounts.Value >= 50);
                }
        }
Ejemplo n.º 2
0
        public async Task When_an_aggregation_fails_then_the_projection_is_not_updated()
        {
            var projections = new InMemoryProjectionStore <BalanceProjection>();
            var catchup     = StreamCatchup.All(streamSource.StreamPerAggregate().Trace());

            // subscribe a flaky projector
            catchup.Subscribe(new BalanceProjector()
                              .Pipeline(async(projection, batch, next) =>
            {
                bool shouldThrow = true;                       // declared outside to nudge the compiler into inferring the correct .Pipeline overload
                if (shouldThrow)
                {
                    throw new Exception("oops");
                }
                await next(projection, batch);
            }),
                              projections.AsHandler(),
                              e => e.Continue());

            await catchup.RunSingleBatch();

            projections.Count().Should().Be(0);
        }
Ejemplo n.º 3
0
        public async Task Catchup_can_use_a_sequence_of_keys_to_traverse_all_aggregates()
        {
            var projectionStore = new InMemoryProjectionStore <BalanceProjection>();

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

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

            projectionStore.Sum(b => b.Balance)
            .Should()
            .Be(100);
            projectionStore.Count()
            .Should()
            .Be(100);
        }