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.LastModifiedBy = payload.Actor;
clone.Version++;
return (clone as T)!;
}
}

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

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

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

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

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

@ -62,7 +62,7 @@ namespace Squidex.Infrastructure.Orleans
return persistence.ReadAsync();
}
private void ApplyState(T value)
private void ApplyState(T value, long version)
{
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 void HandleSnapshot<in T>(T state);
public delegate void HandleSnapshot<in T>(T state, long version);
public interface IPersistenceFactory<T>
{

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

@ -109,17 +109,16 @@ namespace Squidex.Infrastructure.States
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).
position = Math.Max(position, EtagVersion.Empty);
version = Math.Max(version, EtagVersion.Empty);
versionSnapshot = position;
versionEvents = position;
versionSnapshot = version;
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.");
}
// Skip the parsing for performance reasons if we are not interested, but continue reading to get the version
if (!isStopped)
{
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;
}
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);

38
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, -1);
AssertSnapshot(sut.Snapshot, 0);
}
[Fact]
@ -52,7 +52,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 0, EtagVersion.Empty), result);
Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 4, 0);
AssertSnapshot(sut.Snapshot, 4);
}
[Fact]
@ -76,7 +76,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 2, 1), result);
Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 4, 2);
AssertSnapshot(sut.Snapshot, 4);
}
[Fact]
@ -114,7 +114,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 2, 1), result);
Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 4, 2);
AssertSnapshot(sut.Snapshot, 4);
}
[Fact]
@ -150,7 +150,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 1, 0), result);
Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 8, 1);
AssertSnapshot(sut.Snapshot, 8);
}
[Fact]
@ -170,7 +170,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 1, 0), result);
Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 8, 1);
AssertSnapshot(sut.Snapshot, 8);
}
[Fact]
@ -196,7 +196,7 @@ namespace Squidex.Infrastructure.Commands
.MustHaveHappenedOnceExactly();
Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 9, 2);
AssertSnapshot(sut.Snapshot, 9);
}
[Fact]
@ -301,7 +301,7 @@ namespace Squidex.Infrastructure.Commands
Assert.Equal(CommandResult.Empty(id, 0, 0), result);
Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 4, 0);
AssertSnapshot(sut.Snapshot, 4);
}
[Fact]
@ -315,7 +315,7 @@ namespace Squidex.Infrastructure.Commands
await Assert.ThrowsAsync<InvalidOperationException>(() => sut.ExecuteAsync(new CreateAuto()));
Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 0, -1);
AssertSnapshot(sut.Snapshot, 0);
}
[Fact]
@ -329,7 +329,7 @@ namespace Squidex.Infrastructure.Commands
await Assert.ThrowsAsync<InvalidOperationException>(() => sut.ExecuteAsync(new UpdateAuto()));
Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(sut.Snapshot, 4, 0);
AssertSnapshot(sut.Snapshot, 4);
}
[Fact]
@ -345,7 +345,7 @@ namespace Squidex.Infrastructure.Commands
await sut.ExecuteAsync(new DeletePermanent());
AssertSnapshot(sut.Snapshot, 0, EtagVersion.Empty, false);
AssertSnapshot(sut.Snapshot, 0, false);
A.CallTo(() => persistence.DeleteAsync())
.MustHaveHappened();
@ -372,9 +372,9 @@ namespace Squidex.Infrastructure.Commands
var version_1 = await sut.GetSnapshotAsync(1);
Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(version_Empty, 0, -1);
AssertSnapshot(version_0, 3, 0);
AssertSnapshot(version_1, 4, 1);
AssertSnapshot(version_Empty, 0);
AssertSnapshot(version_0, 3);
AssertSnapshot(version_1, 4);
A.CallTo(() => persistenceFactory.WithEventSourcing(typeof(MyDomainObject), id, A<HandleEvent>._))
.MustNotHaveHappened();
@ -396,17 +396,17 @@ namespace Squidex.Infrastructure.Commands
var version_1 = await sut.GetSnapshotAsync(1);
Assert.Empty(sut.GetUncomittedEvents());
AssertSnapshot(version_Empty, 0, -1);
AssertSnapshot(version_0, 3, 0);
AssertSnapshot(version_1, 4, 1);
AssertSnapshot(version_Empty, 0);
AssertSnapshot(version_0, 3);
AssertSnapshot(version_1, 4);
A.CallTo(() => persistenceFactory.WithEventSourcing(typeof(MyDomainObject), id, A<HandleEvent>._))
.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()

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

@ -32,7 +32,7 @@ namespace Squidex.Infrastructure.States
{
Value = initial;
Write = state =>
Write = (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 long Version { get; set; }
public long Value { get; set; }
public MyDomainState Apply(Envelope<IEvent> @event)

Loading…
Cancel
Save