diff --git a/src/Squidex.Infrastructure.MongoDb/EventStore/MongoEventStore.cs b/src/Squidex.Infrastructure.MongoDb/EventStore/MongoEventStore.cs index d51cfc9c7..b7d3ff079 100644 --- a/src/Squidex.Infrastructure.MongoDb/EventStore/MongoEventStore.cs +++ b/src/Squidex.Infrastructure.MongoDb/EventStore/MongoEventStore.cs @@ -69,15 +69,17 @@ namespace Squidex.Infrastructure.MongoDb.EventStore { await Collection.Find(x => x.EventStream == streamName).ForEachAsync(commit => { - var position = commit.EventStreamOffset; + var eventNumber = commit.EventsOffset; + var eventStreamNumber = commit.EventStreamOffset; foreach (var @event in commit.Events) { - var eventData = SimpleMapper.Map(@event, new EventData()); + eventNumber++; + eventStreamNumber++; - observer.OnNext(new StoredEvent(position, eventData)); + var eventData = SimpleMapper.Map(@event, new EventData()); - position++; + observer.OnNext(new StoredEvent(eventNumber, eventStreamNumber, eventData)); } }, ct); }); @@ -92,16 +94,18 @@ namespace Squidex.Infrastructure.MongoDb.EventStore await Collection.Find(x => x.EventsOffset >= commitOffset).SortBy(x => x.EventsOffset).ForEachAsync(commit => { var eventNumber = commit.EventsOffset; + var eventStreamNumber = commit.EventStreamOffset; foreach (var @event in commit.Events) { eventNumber++; + eventStreamNumber++; if (eventNumber > lastReceivedEventNumber) { var eventData = SimpleMapper.Map(@event, new EventData()); - observer.OnNext(new StoredEvent(eventNumber, eventData)); + observer.OnNext(new StoredEvent(eventNumber, eventStreamNumber, eventData)); } } }, ct); diff --git a/src/Squidex.Infrastructure/CQRS/CommonHeaders.cs b/src/Squidex.Infrastructure/CQRS/CommonHeaders.cs index 9274e62e2..c48283347 100644 --- a/src/Squidex.Infrastructure/CQRS/CommonHeaders.cs +++ b/src/Squidex.Infrastructure/CQRS/CommonHeaders.cs @@ -18,6 +18,8 @@ namespace Squidex.Infrastructure.CQRS public static readonly string EventNumber = "EventNumber"; + public static readonly string EventStreamNumber = "EventStreamNumber"; + public static readonly string Timestamp = "Timestamp"; public static readonly string Actor = "Actor"; diff --git a/src/Squidex.Infrastructure/CQRS/EnvelopeExtensions.cs b/src/Squidex.Infrastructure/CQRS/EnvelopeExtensions.cs index 27a757517..322369def 100644 --- a/src/Squidex.Infrastructure/CQRS/EnvelopeExtensions.cs +++ b/src/Squidex.Infrastructure/CQRS/EnvelopeExtensions.cs @@ -26,6 +26,18 @@ namespace Squidex.Infrastructure.CQRS return envelope; } + public static long EventStreamNumber(this EnvelopeHeaders headers) + { + return headers[CommonHeaders.EventStreamNumber].ToInt32(CultureInfo.InvariantCulture); + } + + public static Envelope SetEventStreamNumber(this Envelope envelope, long value) where T : class + { + envelope.Headers.Set(CommonHeaders.EventStreamNumber, value); + + return envelope; + } + public static Guid CommitId(this EnvelopeHeaders headers) { return headers[CommonHeaders.CommitId].ToGuid(CultureInfo.InvariantCulture); diff --git a/src/Squidex.Infrastructure/CQRS/Events/EventReceiver.cs b/src/Squidex.Infrastructure/CQRS/Events/EventReceiver.cs index d693f040f..80c5ff3ba 100644 --- a/src/Squidex.Infrastructure/CQRS/Events/EventReceiver.cs +++ b/src/Squidex.Infrastructure/CQRS/Events/EventReceiver.cs @@ -176,6 +176,7 @@ namespace Squidex.Infrastructure.CQRS.Events var @event = formatter.Parse(storedEvent.Data); @event.SetEventNumber(storedEvent.EventNumber); + @event.SetEventStreamNumber(storedEvent.EventStreamNumber); return @event; } diff --git a/src/Squidex.Infrastructure/CQRS/Events/StoredEvent.cs b/src/Squidex.Infrastructure/CQRS/Events/StoredEvent.cs index 4f8f04d6e..547956c13 100644 --- a/src/Squidex.Infrastructure/CQRS/Events/StoredEvent.cs +++ b/src/Squidex.Infrastructure/CQRS/Events/StoredEvent.cs @@ -11,6 +11,7 @@ namespace Squidex.Infrastructure.CQRS.Events public sealed class StoredEvent { private readonly long eventNumber; + private readonly long eventStreamNumber; private readonly EventData data; public long EventNumber @@ -18,18 +19,23 @@ namespace Squidex.Infrastructure.CQRS.Events get { return eventNumber; } } + public long EventStreamNumber + { + get { return eventStreamNumber; } + } + public EventData Data { get { return data; } } - public StoredEvent(long eventNumber, EventData data) + public StoredEvent(long eventNumber, long eventStreamNumber, EventData data) { Guard.NotNull(data, nameof(data)); this.data = data; - this.eventNumber = eventNumber; + this.eventStreamNumber = eventStreamNumber; } } } diff --git a/src/Squidex.Read.MongoDb/Utils/EntityMapper.cs b/src/Squidex.Read.MongoDb/Utils/EntityMapper.cs index bff43a0be..c9830576a 100644 --- a/src/Squidex.Read.MongoDb/Utils/EntityMapper.cs +++ b/src/Squidex.Read.MongoDb/Utils/EntityMapper.cs @@ -62,7 +62,7 @@ namespace Squidex.Read.MongoDb.Utils if (withVersion != null) { - withVersion.Version = headers.EventNumber(); + withVersion.Version = headers.EventStreamNumber(); } } diff --git a/src/Squidex/app/features/content/pages/content/content-page.component.ts b/src/Squidex/app/features/content/pages/content/content-page.component.ts index be9fb02cd..91b147f95 100644 --- a/src/Squidex/app/features/content/pages/content/content-page.component.ts +++ b/src/Squidex/app/features/content/pages/content/content-page.component.ts @@ -39,7 +39,7 @@ import { }) export class ContentPageComponent extends AppComponentBase implements OnDestroy, OnInit { private messageSubscription: Subscription; - private version: Version; + private version: Version = new Version(''); public schema: SchemaDetailsDto; diff --git a/tests/Squidex.Infrastructure.Tests/CQRS/Commands/DefaultDomainObjectRepositoryTests.cs b/tests/Squidex.Infrastructure.Tests/CQRS/Commands/DefaultDomainObjectRepositoryTests.cs index 850366649..ffe4340e4 100644 --- a/tests/Squidex.Infrastructure.Tests/CQRS/Commands/DefaultDomainObjectRepositoryTests.cs +++ b/tests/Squidex.Infrastructure.Tests/CQRS/Commands/DefaultDomainObjectRepositoryTests.cs @@ -90,8 +90,8 @@ namespace Squidex.Infrastructure.CQRS.Commands var events = new[] { - new StoredEvent(0, eventData1), - new StoredEvent(1, eventData2) + new StoredEvent(0, 0, eventData1), + new StoredEvent(1, 1, eventData2) }; eventStore.Setup(x => x.GetEventsAsync(streamName)).Returns(events.ToObservable()); @@ -115,8 +115,8 @@ namespace Squidex.Infrastructure.CQRS.Commands var events = new[] { - new StoredEvent(0, eventData1), - new StoredEvent(1, eventData2) + new StoredEvent(0, 0, eventData1), + new StoredEvent(1, 1, eventData2) }; eventStore.Setup(x => x.GetEventsAsync(streamName)).Returns(events.ToObservable()); diff --git a/tests/Squidex.Infrastructure.Tests/CQRS/EnvelopeExtensionsTests.cs b/tests/Squidex.Infrastructure.Tests/CQRS/EnvelopeExtensionsTests.cs index 1e20276fa..eb0bc8436 100644 --- a/tests/Squidex.Infrastructure.Tests/CQRS/EnvelopeExtensionsTests.cs +++ b/tests/Squidex.Infrastructure.Tests/CQRS/EnvelopeExtensionsTests.cs @@ -72,5 +72,16 @@ namespace Squidex.Infrastructure.CQRS Assert.Equal(eventNumber, sut.Headers.EventNumber()); Assert.Equal(eventNumber, sut.Headers["EventNumber"].ToInt32(culture)); } + + [Fact] + public void Should_set_and_get_event_stream_number() + { + const int eventStreamNumber = 123; + + sut.SetEventStreamNumber(eventStreamNumber); + + Assert.Equal(eventStreamNumber, sut.Headers.EventStreamNumber()); + Assert.Equal(eventStreamNumber, sut.Headers["EventStreamNumber"].ToInt32(culture)); + } } } diff --git a/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventDataFormatterTests.cs b/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventDataFormatterTests.cs index a96515f52..e76e34877 100644 --- a/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventDataFormatterTests.cs +++ b/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventDataFormatterTests.cs @@ -42,6 +42,7 @@ namespace Squidex.Infrastructure.CQRS.Events inputEvent.SetCommitId(commitId); inputEvent.SetEventId(Guid.NewGuid()); inputEvent.SetEventNumber(1); + inputEvent.SetEventStreamNumber(1); inputEvent.SetTimestamp(SystemClock.Instance.GetCurrentInstant()); var sut = new EventDataFormatter(typeNameRegistry, serializerSettings); diff --git a/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventReceiverTests.cs b/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventReceiverTests.cs index e05616428..08d8aa308 100644 --- a/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventReceiverTests.cs +++ b/tests/Squidex.Infrastructure.Tests/CQRS/Events/EventReceiverTests.cs @@ -81,9 +81,9 @@ namespace Squidex.Infrastructure.CQRS.Events { events = new[] { - new StoredEvent(3, eventData1), - new StoredEvent(4, eventData2), - new StoredEvent(4, eventData3) + new StoredEvent(3, 3, eventData1), + new StoredEvent(4, 4, eventData2), + new StoredEvent(4, 4, eventData3) }; consumerName = eventConsumer.Object.GetType().Name;