コード例 #1
0
        public async Task <long> SaveAsync(AggregateRoot aggregate)
        {
            if (aggregate == null)
            {
                return(0);
            }

            //Save the uncomitted changes to the eventstore
            var events = aggregate.GetUncommitedChanges();

            if (!events.Any())
            {
                return(0);
            }

            var streamId =
                StreamIdBuilder.Create()
                .FromAggregateRoot(aggregate)
                .Build();

            var eventCount = events.Count();
            await _streamWriter.AppendEventsToStream(streamId, events, aggregate.Version);

            aggregate.MarkChangesAsCommitted();
            return(eventCount);
        }
コード例 #2
0
        private async IAsyncEnumerable <Event> GetAllEventsForAggregate(Guid id)
        {
            var streamId = StreamIdBuilder.Create()
                           .WithAggregateType <T>()
                           .WithAggregateId(id)
                           .Build();

            var enumerator = _streamReader.ReadAllEventsFromStreamAsync(streamId).GetAsyncEnumerator();

            try
            {
                if (enumerator == null)
                {
                    yield break;
                }

                while (await enumerator.MoveNextAsync())
                {
                    yield return(enumerator.Current);
                }
            }
            finally
            {
                if (enumerator != null)
                {
                    await enumerator.DisposeAsync();
                }
            }

            yield break;
        }
コード例 #3
0
        public async Task write_events_to_stream_when_expected_version_matches()
        {
            var connectionProvider = new EventStoreConnectionProvider(Options.Create(_fixture.EventStoreConnectionOptions));

            var aggregateId = Guid.NewGuid();
            var streamId    =
                StreamIdBuilder.Create()
                .WithAggregateId(aggregateId)
                .WithAggregateType <DummyAggregate>()
                .Build();

            var writeEvents = new List <Event> {
                new DummyCreatedEvent(aggregateId, "The name", "https://url.example.com"),
                new DummyNameChangedEvent(aggregateId, "The new name"),
                new DummyUrlChangedEvent(aggregateId, "https://newurl.example.com")
            };

            var sut = new EventStoreStreamWriter(connectionProvider, _serializer);
            await sut.AppendEventsToStream(streamId, writeEvents);

            var changeEvent = new DummyUrlChangedEvent(aggregateId, "https://newnewurl.example.com");
            await sut.AppendEventsToStream(streamId, new List <Event> {
                changeEvent
            }, 2);
        }
コード例 #4
0
        public async Task throw_on_write_when_expected_version_does_not_match()
        {
            var connectionProvider = new EventStoreConnectionProvider(Options.Create(_fixture.EventStoreConnectionOptions));

            var aggregateId = Guid.NewGuid();
            var streamId    =
                StreamIdBuilder.Create()
                .WithAggregateId(aggregateId)
                .WithAggregateType <DummyAggregate>()
                .Build();

            var writeEvents = new List <Event> {
                new DummyCreatedEvent(aggregateId, "The name", "https://url.example.com"),
                new DummyNameChangedEvent(aggregateId, "The new name"),
                new DummyUrlChangedEvent(aggregateId, "https://newurl.example.com")
            };

            //Write 3 events to the stream, this sets the version to 2
            var sut = new EventStoreStreamWriter(connectionProvider, _serializer);
            await sut.AppendEventsToStream(streamId, writeEvents);

            //Write should fail
            var changeEvent = new DummyUrlChangedEvent(aggregateId, "https://newnewurl.example.com");
            await Assert.ThrowsAsync <WrongExpectedVersionException>(
                async() => await sut.AppendEventsToStream(streamId, new List <Event> {
                changeEvent
            }, 1));
        }
コード例 #5
0
        public void throw_when_aggregate_root_name_not_provided()
        {
            var builder = new StreamIdBuilder();

            Assert.Throws <ArgumentNullException>(() => builder.Build("region", "context", null, "1"));
            Assert.Throws <ArgumentNullException>(() => builder.Build("region", "context", "", "1"));
        }
コード例 #6
0
        public async Task write_events_to_stream()
        {
            var connectionProvider = new EventStoreConnectionProvider(Options.Create(_fixture.EventStoreConnectionOptions));

            var aggregateId = Guid.NewGuid();
            var streamId    =
                StreamIdBuilder.Create()
                .WithAggregateId(aggregateId)
                .WithAggregateType <DummyAggregate>()
                .Build();

            var writeEvents = new List <Event> {
                new DummyCreatedEvent(aggregateId, "The name", "https://url.example.com"),
                new DummyNameChangedEvent(aggregateId, "The new name"),
                new DummyUrlChangedEvent(aggregateId, "https://newurl.example.com")
            };

            var sut = new EventStoreStreamWriter(connectionProvider, _serializer);
            await sut.AppendEventsToStream(streamId, writeEvents);

            var reader = new EventStoreStreamReader(connectionProvider, _serializer);

            var count      = 0;
            var enumerator = reader.ReadAllEventsFromStreamAsync(streamId).GetAsyncEnumerator();

            while (await enumerator.MoveNextAsync())
            {
                count++;
            }
            await enumerator.DisposeAsync();

            count.Should().Be(3);
        }
コード例 #7
0
        public async Task Writes_aggregate_to_stream()
        {
            var sut = await CreateRepository <DummyAggregate>();

            var fakeAggregate = await CreateDummyAggregate(sut);

            var reader   = CreateStreamReader();
            var streamId = StreamIdBuilder.Create()
                           .WithAggregateType <DummyAggregate>()
                           .WithAggregateId(fakeAggregate.Id)
                           .Build();

            fakeAggregate.Version.Should().Be(0);

            var count      = 0;
            var enumerator = reader.ReadAllEventsFromStreamAsync(streamId).GetAsyncEnumerator();

            while (await enumerator.MoveNextAsync())
            {
                count++;
            }
            await enumerator.DisposeAsync();

            count.Should().Be(1);
        }
コード例 #8
0
        public void build_stream_id_from_only_aggregate_root_name()
        {
            var builder           = new StreamIdBuilder();
            var aggregateRootName = "testAr";
            var streamId          = builder.Build(null, null, aggregateRootName, null);

            Assert.Equal(streamId, aggregateRootName, StringComparer.OrdinalIgnoreCase);
        }
コード例 #9
0
        public void build_stream_id_from_all_fragments()
        {
            var builder           = new StreamIdBuilder();
            var regionId          = "region";
            var context           = "context";
            var aggregateRootName = "testAr";
            var aggregateRootId   = "1";
            var expectedStreamId  = string.Join(StreamIdBuilder.SEPARATOR, regionId, context, aggregateRootName, aggregateRootId);
            var actualStreamId    = builder.Build(regionId, context, aggregateRootName, aggregateRootId);

            Assert.Equal(expectedStreamId, actualStreamId, StringComparer.OrdinalIgnoreCase);
        }
コード例 #10
0
        public async Task <T> Execute(Guid partitionId)
        {
            //Fetch the latest state stored in the repository.
            var projection = await _stateRepository.GetProjectionState(partitionId);

            if (projection == null || projection == default)
            {
                projection = new T();
            }

            var streamId = StreamIdBuilder.Create()
                           .WithAggregateType(_projectionProfile.Filter.AggregateType)
                           .WithAggregateId(partitionId)
                           .Build();

            //Read backwards and update read-model if stale
            var eventStack = new Stack <Event>();
            var stream     = _streamReader.ReadStreamBackwards(streamId);

            await foreach (var ev in stream)
            {
                if (ev.EventId == projection.LastEventId)
                {
                    break;
                }

                if (_projectionProfile.Filter != null & !_projectionProfile.Filter.DoesEventPassFilter(ev, streamId))
                {
                    continue;
                }

                //add this event to our stack
                eventStack.Push(ev);
            }

            //Pop events off the stack and apply them to the projection
            while (eventStack.Count > 0)
            {
                var @event = eventStack.Pop();
                projection = await ProjectEventOntoModel(projection, @event);
            }

            return(projection);
        }
コード例 #11
0
        public async Task Throw_stream_not_found_exception_if_stream_does_not_exist()
        {
            var aggregateId = Guid.NewGuid();
            var streamId    =
                StreamIdBuilder.Create()
                .WithAggregateId(aggregateId)
                .WithAggregateType <DummyAggregate>()
                .Build();

            var reader = new SqlStreamStoreStreamReader(_storeProvider, _serializer);
            await Assert.ThrowsAsync <StreamNotFoundException>(async() =>
            {
                var enumerator = reader.ReadAllEventsFromStreamAsync(streamId).GetAsyncEnumerator();
                while (await enumerator.MoveNextAsync())
                {
                    ;
                }
                await enumerator.DisposeAsync();
            });
        }