Browse Source

Version fix.

pull/680/head
Sebastian Stehle 5 years ago
parent
commit
3ce3560475
  1. 2
      backend/src/Squidex.Domain.Apps.Entities/DomainObjectState.cs
  2. 32
      backend/src/Squidex.Infrastructure/Commands/DomainObject.cs
  3. 2
      backend/src/Squidex.Infrastructure/Commands/IDomainState.cs
  4. 4
      backend/src/Squidex.Infrastructure/Commands/SnapshotList.cs
  5. 2
      backend/src/Squidex.Infrastructure/Orleans/GrainState.cs
  6. 2
      backend/src/Squidex.Infrastructure/States/IPersistenceFactory.cs
  7. 14
      backend/src/Squidex.Infrastructure/States/Persistence.cs
  8. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs
  9. 38
      backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs
  10. 2
      backend/tests/Squidex.Infrastructure.Tests/States/Save.cs
  11. 2
      backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainState.cs

2
backend/src/Squidex.Domain.Apps.Entities/DomainObjectState.cs

@ -73,6 +73,8 @@ namespace Squidex.Domain.Apps.Entities
clone.LastModified = timestamp; clone.LastModified = timestamp;
clone.LastModifiedBy = payload.Actor; clone.LastModifiedBy = payload.Actor;
clone.Version++;
return (clone as T)!; return (clone as T)!;
} }
} }

32
backend/src/Squidex.Infrastructure/Commands/DomainObject.cs

@ -61,23 +61,19 @@ namespace Squidex.Infrastructure.Commands
if (result == null && valid) if (result == null && valid)
{ {
var snapshot = new T var snapshotCurrent = new T();
{ var snapshotVersion = EtagVersion.Empty;
Version = EtagVersion.Empty
};
snapshots.Add(snapshot, snapshot.Version, false); snapshots.Add(snapshotCurrent, snapshotVersion, false);
var allEvents = factory.WithEventSourcing(GetType(), UniqueId, @event => var allEvents = factory.WithEventSourcing(GetType(), UniqueId, @event =>
{ {
var newVersion = snapshot.Version + 1; snapshotVersion++;
if (!snapshots.Contains(newVersion)) if (!snapshots.Contains(snapshotVersion))
{ {
snapshot = Apply(snapshot, @event); snapshotCurrent = Apply(snapshotCurrent, @event);
snapshot.Version = newVersion; snapshots.Add(snapshotCurrent, snapshotVersion, false);
snapshots.Add(snapshot, snapshot.Version, false);
return true; return true;
} }
@ -90,7 +86,7 @@ namespace Squidex.Infrastructure.Commands
(result, valid) = snapshots.Get(version); (result, valid) = snapshots.Get(version);
} }
return result ?? new T { Version = EtagVersion.Empty }; return result ?? new T();
} }
public virtual void Setup(DomainId uniqueId) public virtual void Setup(DomainId uniqueId)
@ -98,10 +94,9 @@ namespace Squidex.Infrastructure.Commands
this.uniqueId = uniqueId; this.uniqueId = uniqueId;
persistence = factory.WithSnapshotsAndEventSourcing(GetType(), UniqueId, persistence = factory.WithSnapshotsAndEventSourcing(GetType(), UniqueId,
new HandleSnapshot<T>(snapshot => new HandleSnapshot<T>((snapshot, version) =>
{ {
snapshot.Version = Version + 1; snapshots.Add(snapshot, version, true);
snapshots.Add(snapshot, snapshot.Version, true);
}), }),
@event => ApplyEvent(@event, true)); @event => ApplyEvent(@event, true));
} }
@ -292,14 +287,11 @@ namespace Squidex.Infrastructure.Commands
private bool ApplyEvent(Envelope<IEvent> @event, bool isLoading) private bool ApplyEvent(Envelope<IEvent> @event, bool isLoading)
{ {
var newVersion = Version + 1;
var snapshotNew = Apply(Snapshot, @event); var snapshotNew = Apply(Snapshot, @event);
if (!ReferenceEquals(Snapshot, snapshotNew) || isLoading) if (!ReferenceEquals(Snapshot, snapshotNew) || isLoading)
{ {
snapshotNew.Version = newVersion; snapshots.Add(snapshotNew, Version + 1, true);
snapshots.Add(snapshotNew, snapshotNew.Version, true);
return true; return true;
} }
@ -328,7 +320,7 @@ namespace Squidex.Infrastructure.Commands
{ {
await EnsureLoadedAsync(true); await EnsureLoadedAsync(true);
if (Snapshot.Version <= EtagVersion.Empty) if (Version <= EtagVersion.Empty)
{ {
throw new DomainObjectNotFoundException(UniqueId.ToString()); throw new DomainObjectNotFoundException(UniqueId.ToString());
} }

2
backend/src/Squidex.Infrastructure/Commands/IDomainState.cs

@ -11,8 +11,6 @@ namespace Squidex.Infrastructure.Commands
{ {
public interface IDomainState<out T> public interface IDomainState<out T>
{ {
long Version { get; set; }
T Apply(Envelope<IEvent> @event); T Apply(Envelope<IEvent> @event);
} }
} }

4
backend/src/Squidex.Infrastructure/Commands/SnapshotList.cs

@ -50,7 +50,7 @@ namespace Squidex.Infrastructure.Commands
public void Clear() public void Clear()
{ {
items.Clear(); items.Clear();
items.Add(new T { Version = EtagVersion.Empty }); items.Add(new T());
} }
public (T?, bool Valid) Get(long version) public (T?, bool Valid) Get(long version)
@ -110,7 +110,7 @@ namespace Squidex.Infrastructure.Commands
{ {
var lastIndex = items.Count - 1; var lastIndex = items.Count - 1;
for (var i = lastIndex - capacity; i >= 0; i--) for (var i = lastIndex - capacity; i > 0; i--)
{ {
items[i] = null; items[i] = null;
} }

2
backend/src/Squidex.Infrastructure/Orleans/GrainState.cs

@ -62,7 +62,7 @@ namespace Squidex.Infrastructure.Orleans
return persistence.ReadAsync(); return persistence.ReadAsync();
} }
private void ApplyState(T value) private void ApplyState(T value, long version)
{ {
Value = value; Value = value;
} }

2
backend/src/Squidex.Infrastructure/States/IPersistenceFactory.cs

@ -12,7 +12,7 @@ namespace Squidex.Infrastructure.States
{ {
public delegate bool HandleEvent(Envelope<IEvent> @event); public delegate bool HandleEvent(Envelope<IEvent> @event);
public delegate void HandleSnapshot<in T>(T state); public delegate void HandleSnapshot<in T>(T state, long version);
public interface IPersistenceFactory<T> public interface IPersistenceFactory<T>
{ {

14
backend/src/Squidex.Infrastructure/States/Persistence.cs

@ -109,17 +109,16 @@ namespace Squidex.Infrastructure.States
private async Task ReadSnapshotAsync() private async Task ReadSnapshotAsync()
{ {
var (state, position) = await snapshotStore.ReadAsync(ownerKey); var (state, version) = await snapshotStore.ReadAsync(ownerKey);
// Treat all negative values as not-found (empty). version = Math.Max(version, EtagVersion.Empty);
position = Math.Max(position, EtagVersion.Empty);
versionSnapshot = position; versionSnapshot = version;
versionEvents = position; versionEvents = version;
if (applyState != null && position >= 0) if (applyState != null && version >= 0)
{ {
applyState(state); applyState(state, version);
} }
} }
@ -138,7 +137,6 @@ namespace Squidex.Infrastructure.States
throw new InvalidOperationException("Events must follow the snapshot version in consecutive order with no gaps."); throw new InvalidOperationException("Events must follow the snapshot version in consecutive order with no gaps.");
} }
// Skip the parsing for performance reasons if we are not interested, but continue reading to get the version
if (!isStopped) if (!isStopped)
{ {
var parsedEvent = eventDataFormatter.ParseIfKnown(@event); var parsedEvent = eventDataFormatter.ParseIfKnown(@event);

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs

@ -88,7 +88,7 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers
return context; return context;
} }
protected async Task<object> PublishIdempotentAsync<T>(DomainObject<T> domainObject, IAggregateCommand command) where T : class, IDomainState<T>, new() protected async Task<object> PublishIdempotentAsync<T>(DomainObject<T> domainObject, IAggregateCommand command) where T : class, IDomainState<T>, IEntityWithVersion, new()
{ {
var result = await domainObject.ExecuteAsync(command); var result = await domainObject.ExecuteAsync(command);

38
backend/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectTests.cs

@ -32,7 +32,7 @@ namespace Squidex.Infrastructure.Commands
public void Should_instantiate() public void Should_instantiate()
{ {
Assert.Equal(EtagVersion.Empty, sut.Version); Assert.Equal(EtagVersion.Empty, sut.Version);
AssertSnapshot(sut.Snapshot, 0, -1); AssertSnapshot(sut.Snapshot, 0);
} }
[Fact] [Fact]
@ -52,7 +52,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 0, EtagVersion.Empty), result); Assert.Equal(CommandResult.Empty(id, 0, EtagVersion.Empty), result);
Assert.Empty(sut.GetUncomittedEvents()); Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 4, 0); AssertSnapshot(sut.Snapshot, 4);
} }
[Fact] [Fact]
@ -76,7 +76,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 2, 1), result); Assert.Equal(CommandResult.Empty(id, 2, 1), result);
Assert.Empty(sut.GetUncomittedEvents()); Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 4, 2); AssertSnapshot(sut.Snapshot, 4);
} }
[Fact] [Fact]
@ -114,7 +114,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 2, 1), result); Assert.Equal(CommandResult.Empty(id, 2, 1), result);
Assert.Empty(sut.GetUncomittedEvents()); Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 4, 2); AssertSnapshot(sut.Snapshot, 4);
} }
[Fact] [Fact]
@ -150,7 +150,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 1, 0), result); Assert.Equal(CommandResult.Empty(id, 1, 0), result);
Assert.Empty(sut.GetUncomittedEvents()); Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 8, 1); AssertSnapshot(sut.Snapshot, 8);
} }
[Fact] [Fact]
@ -170,7 +170,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 1, 0), result); Assert.Equal(CommandResult.Empty(id, 1, 0), result);
Assert.Empty(sut.GetUncomittedEvents()); Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 8, 1); AssertSnapshot(sut.Snapshot, 8);
} }
[Fact] [Fact]
@ -196,7 +196,7 @@ namespace Squidex.Infrastructure.Commands
.MustHaveHappenedOnceExactly(); .MustHaveHappenedOnceExactly();
Assert.Empty(sut.GetUncomittedEvents()); Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 9, 2); AssertSnapshot(sut.Snapshot, 9);
} }
[Fact] [Fact]
@ -301,7 +301,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 0, 0), result); Assert.Equal(CommandResult.Empty(id, 0, 0), result);
Assert.Empty(sut.GetUncomittedEvents()); Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 4, 0); AssertSnapshot(sut.Snapshot, 4);
} }
[Fact] [Fact]
@ -315,7 +315,7 @@ namespace Squidex.Infrastructure.Commands
await Assert.ThrowsAsync<InvalidOperationException>(() => sut.ExecuteAsync(new CreateAuto())); await Assert.ThrowsAsync<InvalidOperationException>(() => sut.ExecuteAsync(new CreateAuto()));
Assert.Empty(sut.GetUncomittedEvents()); Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 0, -1); AssertSnapshot(sut.Snapshot, 0);
} }
[Fact] [Fact]
@ -329,7 +329,7 @@ namespace Squidex.Infrastructure.Commands
await Assert.ThrowsAsync<InvalidOperationException>(() => sut.ExecuteAsync(new UpdateAuto())); await Assert.ThrowsAsync<InvalidOperationException>(() => sut.ExecuteAsync(new UpdateAuto()));
Assert.Empty(sut.GetUncomittedEvents()); Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 4, 0); AssertSnapshot(sut.Snapshot, 4);
} }
[Fact] [Fact]
@ -345,7 +345,7 @@ namespace Squidex.Infrastructure.Commands
await sut.ExecuteAsync(new DeletePermanent()); await sut.ExecuteAsync(new DeletePermanent());
AssertSnapshot(sut.Snapshot, 0, EtagVersion.Empty, false); AssertSnapshot(sut.Snapshot, 0, false);
A.CallTo(() => persistence.DeleteAsync()) A.CallTo(() => persistence.DeleteAsync())
.MustHaveHappened(); .MustHaveHappened();
@ -372,9 +372,9 @@ namespace Squidex.Infrastructure.Commands
var version_1 = await sut.GetSnapshotAsync(1); var version_1 = await sut.GetSnapshotAsync(1);
Assert.Empty(sut.GetUncomittedEvents()); Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(version_Empty, 0, -1); AssertSnapshot(version_Empty, 0);
AssertSnapshot(version_0, 3, 0); AssertSnapshot(version_0, 3);
AssertSnapshot(version_1, 4, 1); AssertSnapshot(version_1, 4);
A.CallTo(() => persistenceFactory.WithEventSourcing(typeof(MyDomainObject), id, A<HandleEvent>._)) A.CallTo(() => persistenceFactory.WithEventSourcing(typeof(MyDomainObject), id, A<HandleEvent>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
@ -396,17 +396,17 @@ namespace Squidex.Infrastructure.Commands
var version_1 = await sut.GetSnapshotAsync(1); var version_1 = await sut.GetSnapshotAsync(1);
Assert.Empty(sut.GetUncomittedEvents()); Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(version_Empty, 0, -1); AssertSnapshot(version_Empty, 0);
AssertSnapshot(version_0, 3, 0); AssertSnapshot(version_0, 3);
AssertSnapshot(version_1, 4, 1); AssertSnapshot(version_1, 4);
A.CallTo(() => persistenceFactory.WithEventSourcing(typeof(MyDomainObject), id, A<HandleEvent>._)) A.CallTo(() => persistenceFactory.WithEventSourcing(typeof(MyDomainObject), id, A<HandleEvent>._))
.MustHaveHappened(); .MustHaveHappened();
} }
private static void AssertSnapshot(MyDomainState state, int value, long version, bool isDeleted = false) private static void AssertSnapshot(MyDomainState state, int value, bool isDeleted = false)
{ {
Assert.Equal(new MyDomainState { Value = value, Version = version, IsDeleted = isDeleted }, state); Assert.Equal(new MyDomainState { Value = value, IsDeleted = isDeleted }, state);
} }
private void SetupDeleted() private void SetupDeleted()

2
backend/tests/Squidex.Infrastructure.Tests/States/Save.cs

@ -32,7 +32,7 @@ namespace Squidex.Infrastructure.States
{ {
Value = initial; Value = initial;
Write = state => Write = (state, _) =>
{ {
Value = state; Value = state;
}; };

2
backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainState.cs

@ -16,8 +16,6 @@ namespace Squidex.Infrastructure.TestHelpers
public bool IsDeleted { get; set; } public bool IsDeleted { get; set; }
public long Version { get; set; }
public long Value { get; set; } public long Value { get; set; }
public MyDomainState Apply(Envelope<IEvent> @event) public MyDomainState Apply(Envelope<IEvent> @event)

Loading…
Cancel
Save