diff --git a/backend/src/Squidex.Domain.Apps.Entities/DomainObjectState.cs b/backend/src/Squidex.Domain.Apps.Entities/DomainObjectState.cs index d5ad126ca..b0560434a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/DomainObjectState.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/DomainObjectState.cs @@ -73,8 +73,6 @@ namespace Squidex.Domain.Apps.Entities clone.LastModified = timestamp; clone.LastModifiedBy = payload.Actor; - clone.Version++; - return (clone as T)!; } } diff --git a/backend/src/Squidex.Infrastructure/Commands/DomainObject.cs b/backend/src/Squidex.Infrastructure/Commands/DomainObject.cs index 3e99df63e..eb109b48f 100644 --- a/backend/src/Squidex.Infrastructure/Commands/DomainObject.cs +++ b/backend/src/Squidex.Infrastructure/Commands/DomainObject.cs @@ -61,19 +61,23 @@ namespace Squidex.Infrastructure.Commands if (result == null && valid) { - var snapshotCurrent = new T(); - var snapshotVersion = EtagVersion.Empty; + var snapshot = new T + { + Version = EtagVersion.Empty + }; - snapshots.Add(snapshotCurrent, snapshotVersion, false); + snapshots.Add(snapshot, snapshot.Version, false); var allEvents = factory.WithEventSourcing(GetType(), UniqueId, @event => { - snapshotVersion++; + var newVersion = snapshot.Version + 1; - if (!snapshots.Contains(snapshotVersion)) + if (!snapshots.Contains(newVersion)) { - snapshotCurrent = Apply(snapshotCurrent, @event); - snapshots.Add(snapshotCurrent, snapshotVersion, false); + snapshot = Apply(snapshot, @event); + snapshot.Version = newVersion; + + snapshots.Add(snapshot, newVersion, false); return true; } @@ -86,7 +90,7 @@ namespace Squidex.Infrastructure.Commands (result, valid) = snapshots.Get(version); } - return result ?? new T(); + return result ?? new T { Version = EtagVersion.Empty }; } public virtual void Setup(DomainId uniqueId) @@ -96,6 +100,7 @@ namespace Squidex.Infrastructure.Commands persistence = factory.WithSnapshotsAndEventSourcing(GetType(), UniqueId, new HandleSnapshot((snapshot, version) => { + snapshot.Version = version; snapshots.Add(snapshot, version, true); }), @event => ApplyEvent(@event, true)); @@ -287,11 +292,14 @@ namespace Squidex.Infrastructure.Commands private bool ApplyEvent(Envelope @event, bool isLoading) { + var newVersion = Version + 1; + var snapshotNew = Apply(Snapshot, @event); if (!ReferenceEquals(Snapshot, snapshotNew) || isLoading) { - snapshots.Add(snapshotNew, Version + 1, true); + snapshotNew.Version = newVersion; + snapshots.Add(snapshotNew, newVersion, true); return true; } diff --git a/backend/src/Squidex.Infrastructure/Commands/IDomainState.cs b/backend/src/Squidex.Infrastructure/Commands/IDomainState.cs index a23f47079..9d4412f7c 100644 --- a/backend/src/Squidex.Infrastructure/Commands/IDomainState.cs +++ b/backend/src/Squidex.Infrastructure/Commands/IDomainState.cs @@ -11,6 +11,8 @@ namespace Squidex.Infrastructure.Commands { public interface IDomainState { + long Version { get; set; } + T Apply(Envelope @event); } } diff --git a/backend/src/Squidex.Infrastructure/Commands/SnapshotList.cs b/backend/src/Squidex.Infrastructure/Commands/SnapshotList.cs index 36c5e72d9..6cbbe73ca 100644 --- a/backend/src/Squidex.Infrastructure/Commands/SnapshotList.cs +++ b/backend/src/Squidex.Infrastructure/Commands/SnapshotList.cs @@ -50,7 +50,10 @@ namespace Squidex.Infrastructure.Commands public void Clear() { items.Clear(); - items.Add(new T()); + items.Add(new T + { + Version = EtagVersion.Empty + }); } public (T?, bool Valid) Get(long version) diff --git a/backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs index b74e80271..7e8102ee0 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs @@ -32,7 +32,7 @@ namespace Squidex.Infrastructure.Commands public void Should_instantiate() { Assert.Equal(EtagVersion.Empty, sut.Version); - AssertSnapshot(sut.Snapshot, 0); + AssertSnapshot(sut.Snapshot, 0, EtagVersion.Empty); } [Fact] @@ -53,7 +53,7 @@ namespace Squidex.Infrastructure.Commands Assert.Equal(0, sut.Version); Assert.Empty(sut.GetUncomittedEvents()); - AssertSnapshot(sut.Snapshot, 4); + AssertSnapshot(sut.Snapshot, 4, 0); } [Fact] @@ -78,7 +78,7 @@ namespace Squidex.Infrastructure.Commands Assert.Equal(2, sut.Version); Assert.Empty(sut.GetUncomittedEvents()); - AssertSnapshot(sut.Snapshot, 4); + AssertSnapshot(sut.Snapshot, 4, 2); } [Fact] @@ -117,7 +117,7 @@ namespace Squidex.Infrastructure.Commands Assert.Equal(2, sut.Version); Assert.Empty(sut.GetUncomittedEvents()); - AssertSnapshot(sut.Snapshot, 4); + AssertSnapshot(sut.Snapshot, 4, 2); } [Fact] @@ -154,7 +154,7 @@ namespace Squidex.Infrastructure.Commands Assert.Equal(1, sut.Version); Assert.Empty(sut.GetUncomittedEvents()); - AssertSnapshot(sut.Snapshot, 8); + AssertSnapshot(sut.Snapshot, 8, 1); } [Fact] @@ -175,7 +175,7 @@ namespace Squidex.Infrastructure.Commands Assert.Equal(1, sut.Version); Assert.Empty(sut.GetUncomittedEvents()); - AssertSnapshot(sut.Snapshot, 8); + AssertSnapshot(sut.Snapshot, 8, 1); } [Fact] @@ -201,7 +201,7 @@ namespace Squidex.Infrastructure.Commands .MustHaveHappenedOnceExactly(); Assert.Empty(sut.GetUncomittedEvents()); - AssertSnapshot(sut.Snapshot, 9); + AssertSnapshot(sut.Snapshot, 9, 2); } [Fact] @@ -307,7 +307,7 @@ namespace Squidex.Infrastructure.Commands Assert.Equal(0, sut.Version); Assert.Empty(sut.GetUncomittedEvents()); - AssertSnapshot(sut.Snapshot, 4); + AssertSnapshot(sut.Snapshot, 4, 0); } [Fact] @@ -321,7 +321,7 @@ namespace Squidex.Infrastructure.Commands await Assert.ThrowsAsync(() => sut.ExecuteAsync(new CreateAuto())); Assert.Empty(sut.GetUncomittedEvents()); - AssertSnapshot(sut.Snapshot, 0); + AssertSnapshot(sut.Snapshot, 0, EtagVersion.Empty); } [Fact] @@ -335,7 +335,7 @@ namespace Squidex.Infrastructure.Commands await Assert.ThrowsAsync(() => sut.ExecuteAsync(new UpdateAuto())); Assert.Empty(sut.GetUncomittedEvents()); - AssertSnapshot(sut.Snapshot, 4); + AssertSnapshot(sut.Snapshot, 4, 0); } [Fact] @@ -351,7 +351,7 @@ namespace Squidex.Infrastructure.Commands await sut.ExecuteAsync(new DeletePermanent()); - AssertSnapshot(sut.Snapshot, 0, false); + AssertSnapshot(sut.Snapshot, 0, EtagVersion.Empty, false); A.CallTo(() => persistence.DeleteAsync()) .MustHaveHappened(); @@ -378,9 +378,9 @@ namespace Squidex.Infrastructure.Commands var version_1 = await sut.GetSnapshotAsync(1); Assert.Empty(sut.GetUncomittedEvents()); - AssertSnapshot(version_Empty, 0); - AssertSnapshot(version_0, 3); - AssertSnapshot(version_1, 4); + AssertSnapshot(version_Empty, 0, EtagVersion.Empty); + AssertSnapshot(version_0, 3, 0); + AssertSnapshot(version_1, 4, 1); A.CallTo(() => persistenceFactory.WithEventSourcing(typeof(MyDomainObject), id, A._)) .MustNotHaveHappened(); @@ -402,17 +402,17 @@ namespace Squidex.Infrastructure.Commands var version_1 = await sut.GetSnapshotAsync(1); Assert.Empty(sut.GetUncomittedEvents()); - AssertSnapshot(version_Empty, 0); - AssertSnapshot(version_0, 3); - AssertSnapshot(version_1, 4); + AssertSnapshot(version_Empty, 0, EtagVersion.Empty); + AssertSnapshot(version_0, 3, 0); + AssertSnapshot(version_1, 4, 1); A.CallTo(() => persistenceFactory.WithEventSourcing(typeof(MyDomainObject), id, A._)) .MustHaveHappened(); } - private static void AssertSnapshot(MyDomainState state, int value, bool isDeleted = false) + private static void AssertSnapshot(MyDomainState state, int value, long version, bool isDeleted = false) { - Assert.Equal(new MyDomainState { Value = value, IsDeleted = isDeleted }, state); + Assert.Equal(new MyDomainState { Value = value, Version = version, IsDeleted = isDeleted }, state); } private void SetupDeleted() diff --git a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainState.cs b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainState.cs index 964ac2b12..5a51eff9b 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainState.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainState.cs @@ -16,6 +16,8 @@ namespace Squidex.Infrastructure.TestHelpers public bool IsDeleted { get; set; } + public long Version { get; set; } + public long Value { get; set; } public MyDomainState Apply(Envelope @event)