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); }
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; }
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); }
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)); }
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")); }
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); }
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); }
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); }
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); }
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); }
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(); }); }