diff --git a/backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs b/backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs index 405786898..9143d59d5 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs @@ -104,7 +104,7 @@ namespace Squidex.Infrastructure.EventSourcing } } - public async IAsyncEnumerable QueryAllReverseAsync(string? streamFilter = null, Instant timestamp = default, long take = long.MaxValue, + public async IAsyncEnumerable QueryAllReverseAsync(string? streamFilter = null, Instant timestamp = default, int take = int.MaxValue, [EnumeratorCancellation] CancellationToken ct = default) { if (take <= 0) @@ -118,7 +118,7 @@ namespace Squidex.Infrastructure.EventSourcing var find = Collection.Find(filterDefinition, options: Batching.Options) - .Limit((int)take).Sort(Sort.Descending(TimestampField).Ascending(EventStreamField)); + .Limit(take).Sort(Sort.Descending(TimestampField).Ascending(EventStreamField)); var taken = 0; @@ -149,7 +149,7 @@ namespace Squidex.Infrastructure.EventSourcing } } - public async IAsyncEnumerable QueryAllAsync(string? streamFilter = null, string? position = null, long take = long.MaxValue, + public async IAsyncEnumerable QueryAllAsync(string? streamFilter = null, string? position = null, int take = int.MaxValue, [EnumeratorCancellation] CancellationToken ct = default) { StreamPosition lastPosition = position; @@ -158,7 +158,7 @@ namespace Squidex.Infrastructure.EventSourcing var find = Collection.Find(filterDefinition) - .Limit((int)take).Sort(Sort.Ascending(TimestampField).Ascending(EventStreamField)); + .Limit(take).Sort(Sort.Ascending(TimestampField).Ascending(EventStreamField)); var taken = 0; diff --git a/backend/src/Squidex.Infrastructure/EventSourcing/IEventStore.cs b/backend/src/Squidex.Infrastructure/EventSourcing/IEventStore.cs index 97b147613..4524e12ba 100644 --- a/backend/src/Squidex.Infrastructure/EventSourcing/IEventStore.cs +++ b/backend/src/Squidex.Infrastructure/EventSourcing/IEventStore.cs @@ -19,9 +19,9 @@ namespace Squidex.Infrastructure.EventSourcing Task> QueryAsync(string streamName, long streamPosition = 0); - IAsyncEnumerable QueryAllReverseAsync(string? streamFilter = null, Instant timestamp = default, long take = long.MaxValue, CancellationToken ct = default); + IAsyncEnumerable QueryAllReverseAsync(string? streamFilter = null, Instant timestamp = default, int take = int.MaxValue, CancellationToken ct = default); - IAsyncEnumerable QueryAllAsync(string? streamFilter = null, string? position = null, long take = long.MaxValue, CancellationToken ct = default); + IAsyncEnumerable QueryAllAsync(string? streamFilter = null, string? position = null, int take = int.MaxValue, CancellationToken ct = default); Task AppendAsync(Guid commitId, string streamName, ICollection events); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RepairFilesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RepairFilesTests.cs index f4e9e1f14..89c636fe6 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RepairFilesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RepairFilesTests.cs @@ -128,7 +128,7 @@ namespace Squidex.Domain.Apps.Entities.Assets .Returns(null); } - A.CallTo(() => eventStore.QueryAllAsync("^asset\\-", null, long.MaxValue, default)) + A.CallTo(() => eventStore.QueryAllAsync("^asset\\-", null, int.MaxValue, default)) .Returns(storedEvents.ToAsyncEnumerable()); } } diff --git a/backend/tests/Squidex.Infrastructure.Tests/Collections/ImmutableListTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Collections/ImmutableListTests.cs index 7fa2a8401..0f8075806 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Collections/ImmutableListTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Collections/ImmutableListTests.cs @@ -5,8 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure.TestHelpers; using System.Linq; +using Squidex.Infrastructure.TestHelpers; using Xunit; namespace Squidex.Infrastructure.Collections diff --git a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EventStoreTests.cs b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EventStoreTests.cs index d7648992a..88468d4be 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EventStoreTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/EventStoreTests.cs @@ -60,13 +60,13 @@ namespace Squidex.Infrastructure.EventSourcing { var streamName = $"test-{Guid.NewGuid()}"; - var events = new[] + var commit = new[] { CreateEventData(1), CreateEventData(2) }; - await Assert.ThrowsAsync(() => Sut.AppendAsync(Guid.NewGuid(), streamName, 0, events)); + await Assert.ThrowsAsync(() => Sut.AppendAsync(Guid.NewGuid(), streamName, 0, commit)); } [Fact] @@ -74,15 +74,15 @@ namespace Squidex.Infrastructure.EventSourcing { var streamName = $"test-{Guid.NewGuid()}"; - var events = new[] + var commit = new[] { CreateEventData(1), CreateEventData(2) }; - await Sut.AppendAsync(Guid.NewGuid(), streamName, events); + await Sut.AppendAsync(Guid.NewGuid(), streamName, commit); - await Assert.ThrowsAsync(() => Sut.AppendAsync(Guid.NewGuid(), streamName, 0, events)); + await Assert.ThrowsAsync(() => Sut.AppendAsync(Guid.NewGuid(), streamName, 0, commit)); } [Fact] @@ -90,21 +90,30 @@ namespace Squidex.Infrastructure.EventSourcing { var streamName = $"test-{Guid.NewGuid()}"; - var events = new[] + var commit1 = new[] { CreateEventData(1), CreateEventData(2) }; - await Sut.AppendAsync(Guid.NewGuid(), streamName, events); + var commit2 = new[] + { + CreateEventData(1), + CreateEventData(2) + }; + + await Sut.AppendAsync(Guid.NewGuid(), streamName, commit1); + await Sut.AppendAsync(Guid.NewGuid(), streamName, commit2); var readEvents1 = await QueryAsync(streamName); var readEvents2 = await QueryAllAsync(streamName); var expected = new[] { - new StoredEvent(streamName, "Position", 0, events[0]), - new StoredEvent(streamName, "Position", 1, events[1]) + new StoredEvent(streamName, "Position", 0, commit1[0]), + new StoredEvent(streamName, "Position", 1, commit1[1]), + new StoredEvent(streamName, "Position", 2, commit2[2]), + new StoredEvent(streamName, "Position", 3, commit2[3]) }; ShouldBeEquivalentTo(readEvents1, expected); @@ -116,7 +125,7 @@ namespace Squidex.Infrastructure.EventSourcing { var streamName = $"test-{Guid.NewGuid()}"; - var events = new[] + var commit1 = new[] { CreateEventData(1), CreateEventData(2) @@ -124,7 +133,7 @@ namespace Squidex.Infrastructure.EventSourcing await Sut.AppendUnsafeAsync(new List { - new EventCommit(Guid.NewGuid(), streamName, -1, events) + new EventCommit(Guid.NewGuid(), streamName, -1, commit1) }); var readEvents1 = await QueryAsync(streamName); @@ -132,8 +141,8 @@ namespace Squidex.Infrastructure.EventSourcing var expected = new[] { - new StoredEvent(streamName, "Position", 0, events[0]), - new StoredEvent(streamName, "Position", 1, events[1]) + new StoredEvent(streamName, "Position", 0, commit1[0]), + new StoredEvent(streamName, "Position", 1, commit1[1]) }; ShouldBeEquivalentTo(readEvents1, expected); @@ -145,7 +154,7 @@ namespace Squidex.Infrastructure.EventSourcing { var streamName = $"test-{Guid.NewGuid()}"; - var events = new[] + var commit1 = new[] { CreateEventData(1), CreateEventData(2) @@ -153,13 +162,13 @@ namespace Squidex.Infrastructure.EventSourcing var readEvents = await QueryWithSubscriptionAsync(streamName, async () => { - await Sut.AppendAsync(Guid.NewGuid(), streamName, events); + await Sut.AppendAsync(Guid.NewGuid(), streamName, commit1); }); var expected = new[] { - new StoredEvent(streamName, "Position", 0, events[0]), - new StoredEvent(streamName, "Position", 1, events[1]) + new StoredEvent(streamName, "Position", 0, commit1[0]), + new StoredEvent(streamName, "Position", 1, commit1[1]) }; ShouldBeEquivalentTo(readEvents, expected); @@ -170,7 +179,7 @@ namespace Squidex.Infrastructure.EventSourcing { var streamName = $"test-{Guid.NewGuid()}"; - var events1 = new[] + var commit1 = new[] { CreateEventData(1), CreateEventData(2) @@ -179,10 +188,10 @@ namespace Squidex.Infrastructure.EventSourcing // Append and read in parallel. await QueryWithSubscriptionAsync(streamName, async () => { - await Sut.AppendAsync(Guid.NewGuid(), streamName, events1); + await Sut.AppendAsync(Guid.NewGuid(), streamName, commit1); }); - var events2 = new[] + var commit2 = new[] { CreateEventData(1), CreateEventData(2) @@ -191,23 +200,23 @@ namespace Squidex.Infrastructure.EventSourcing // Append and read in parallel. var readEventsFromPosition = await QueryWithSubscriptionAsync(streamName, async () => { - await Sut.AppendAsync(Guid.NewGuid(), streamName, events2); + await Sut.AppendAsync(Guid.NewGuid(), streamName, commit2); }); var expectedFromPosition = new[] { - new StoredEvent(streamName, "Position", 2, events2[0]), - new StoredEvent(streamName, "Position", 3, events2[1]) + new StoredEvent(streamName, "Position", 2, commit2[0]), + new StoredEvent(streamName, "Position", 3, commit2[1]) }; var readEventsFromBeginning = await QueryWithSubscriptionAsync(streamName, fromBeginning: true); var expectedFromBeginning = new[] { - new StoredEvent(streamName, "Position", 0, events1[0]), - new StoredEvent(streamName, "Position", 1, events1[1]), - new StoredEvent(streamName, "Position", 2, events2[0]), - new StoredEvent(streamName, "Position", 3, events2[1]) + new StoredEvent(streamName, "Position", 0, commit1[0]), + new StoredEvent(streamName, "Position", 1, commit1[1]), + new StoredEvent(streamName, "Position", 2, commit2[0]), + new StoredEvent(streamName, "Position", 3, commit2[1]) }; ShouldBeEquivalentTo(readEventsFromPosition?.TakeLast(2), expectedFromPosition); @@ -219,13 +228,13 @@ namespace Squidex.Infrastructure.EventSourcing { var streamName = $"test-{Guid.NewGuid()}"; - var events = new[] + var commit = new[] { CreateEventData(1), CreateEventData(2) }; - await Sut.AppendAsync(Guid.NewGuid(), streamName, events); + await Sut.AppendAsync(Guid.NewGuid(), streamName, commit); var firstRead = await QueryAsync(streamName); @@ -234,7 +243,7 @@ namespace Squidex.Infrastructure.EventSourcing var expected = new[] { - new StoredEvent(streamName, "Position", 1, events[1]) + new StoredEvent(streamName, "Position", 1, commit[1]) }; ShouldBeEquivalentTo(readEvents1, expected); @@ -247,33 +256,33 @@ namespace Squidex.Infrastructure.EventSourcing var streamName1 = $"test-{Guid.NewGuid()}"; var streamName2 = $"test-{Guid.NewGuid()}"; - var events1 = new[] + var stream1Commit = new[] { CreateEventData(1), CreateEventData(2) }; - var events2 = new[] + var stream2Commit = new[] { CreateEventData(3), CreateEventData(4) }; - await Sut.AppendAsync(Guid.NewGuid(), streamName1, events1); - await Sut.AppendAsync(Guid.NewGuid(), streamName2, events2); + await Sut.AppendAsync(Guid.NewGuid(), streamName1, stream1Commit); + await Sut.AppendAsync(Guid.NewGuid(), streamName2, stream2Commit); var readEvents = await Sut.QueryManyAsync(new[] { streamName1, streamName2 }); var expected1 = new[] { - new StoredEvent(streamName1, "Position", 0, events1[0]), - new StoredEvent(streamName1, "Position", 1, events1[1]) + new StoredEvent(streamName1, "Position", 0, stream1Commit[0]), + new StoredEvent(streamName1, "Position", 1, stream1Commit[1]) }; var expected2 = new[] { - new StoredEvent(streamName2, "Position", 0, events2[0]), - new StoredEvent(streamName2, "Position", 1, events2[1]) + new StoredEvent(streamName2, "Position", 0, stream2Commit[0]), + new StoredEvent(streamName2, "Position", 1, stream2Commit[1]) }; ShouldBeEquivalentTo(readEvents[streamName1], expected1); diff --git a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/PollingSubscriptionTests.cs b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/PollingSubscriptionTests.cs index e8effa498..29cd82e00 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/PollingSubscriptionTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/PollingSubscriptionTests.cs @@ -26,7 +26,7 @@ namespace Squidex.Infrastructure.EventSourcing await WaitAndStopAsync(sut); - A.CallTo(() => eventStore.QueryAllAsync("^my-stream", position, A._, A._)) + A.CallTo(() => eventStore.QueryAllAsync("^my-stream", position, A._, A._)) .MustHaveHappenedOnceExactly(); } @@ -35,7 +35,7 @@ namespace Squidex.Infrastructure.EventSourcing { var ex = new InvalidOperationException(); - A.CallTo(() => eventStore.QueryAllAsync("^my-stream", position, A._, A._)) + A.CallTo(() => eventStore.QueryAllAsync("^my-stream", position, A._, A._)) .Throws(ex); var sut = new PollingSubscription(eventStore, eventSubscriber, "^my-stream", position); @@ -51,7 +51,7 @@ namespace Squidex.Infrastructure.EventSourcing { var ex = new OperationCanceledException(); - A.CallTo(() => eventStore.QueryAllAsync("^my-stream", position, A._, A._)) + A.CallTo(() => eventStore.QueryAllAsync("^my-stream", position, A._, A._)) .Throws(ex); var sut = new PollingSubscription(eventStore, eventSubscriber, "^my-stream", position); @@ -67,7 +67,7 @@ namespace Squidex.Infrastructure.EventSourcing { var ex = new AggregateException(new OperationCanceledException()); - A.CallTo(() => eventStore.QueryAllAsync("^my-stream", position, A._, A._)) + A.CallTo(() => eventStore.QueryAllAsync("^my-stream", position, A._, A._)) .Throws(ex); var sut = new PollingSubscription(eventStore, eventSubscriber, "^my-stream", position); @@ -87,7 +87,7 @@ namespace Squidex.Infrastructure.EventSourcing await WaitAndStopAsync(sut); - A.CallTo(() => eventStore.QueryAllAsync("^my-stream", position, A._, A._)) + A.CallTo(() => eventStore.QueryAllAsync("^my-stream", position, A._, A._)) .MustHaveHappened(2, Times.Exactly); } diff --git a/frontend/app/framework/utils/duration.spec.ts b/frontend/app/framework/utils/duration.spec.ts index 2085fbfbc..ed373d372 100644 --- a/frontend/app/framework/utils/duration.spec.ts +++ b/frontend/app/framework/utils/duration.spec.ts @@ -16,38 +16,46 @@ describe('Duration', () => { }); it('should calculate timestamp from first and second time', () => { - const s = DateTime.today(); - const d = s.addSeconds(100); + const time1 = DateTime.today(); + const time2 = time1.addSeconds(100); - const duration = Duration.create(s, d); + const duration = Duration.create(time1, time2); const actual = duration.timestamp; - const expected = 100000; - expect(actual).toBe(expected); + expect(actual).toBe(100000); }); it('should print to string correctly', () => { - const s = DateTime.today(); - const d = s.addHours(12).addMinutes(30).addSeconds(60); + const time1 = DateTime.today(); + const time2 = time1.addHours(12).addMinutes(30).addSeconds(60); - const duration = Duration.create(s, d); + const duration = Duration.create(time1, time2); const actual = duration.toString(); - const expected = '12:31:00'; - expect(actual).toBe(expected); + expect(actual).toBe('12:31:00'); }); it('should print to string correctly for one digit minutes', () => { - const s = DateTime.today(); - const d = s.addHours(1).addMinutes(2).addSeconds(5); + const time1 = DateTime.today(); + const time2 = time1.addHours(1).addMinutes(2).addSeconds(5); - const duration = Duration.create(s, d); + const duration = Duration.create(time1, time2); const actual = duration.toString(); - const expected = '01:02:05'; - expect(actual).toBe(expected); + expect(actual).toBe('01:02:05'); + }); + + it('should print to string correctly for one partial seconds', () => { + const time1 = DateTime.today(); + const time2 = time1.addHours(1).addMinutes(2).addSeconds(4.555334); + + const duration = Duration.create(time1, time2); + + const actual = duration.toString(); + + expect(actual).toBe('01:02:04'); }); }); diff --git a/frontend/app/framework/utils/duration.ts b/frontend/app/framework/utils/duration.ts index ae5a66c0d..c25581b29 100644 --- a/frontend/app/framework/utils/duration.ts +++ b/frontend/app/framework/utils/duration.ts @@ -43,7 +43,7 @@ export class Duration { seconds %= 60; - let secondsString = seconds.toString(); + let secondsString = Math.ceil(seconds).toString(); if (secondsString.length === 1) { secondsString = `0${secondsString}`;