Beispiel #1
0
        public async Task <IReadOnlyList <StoredEvent> > QueryAsync(string streamName, long streamPosition = 0)
        {
            var commits =
                await Collection.Find(
                    Filter.And(
                        Filter.Eq(EventStreamField, streamName),
                        Filter.Gte(EventStreamOffsetField, streamPosition - 1)))
                .Sort(Sort.Ascending(TimestampField)).ToListAsync();

            var result = new List <StoredEvent>();

            foreach (var commit in commits)
            {
                var eventStreamOffset = (int)commit.EventStreamOffset;

                var commitTimestamp = commit.Timestamp;
                var commitOffset    = 0;

                foreach (var e in commit.Events)
                {
                    eventStreamOffset++;

                    if (eventStreamOffset >= streamPosition)
                    {
                        var eventData  = e.ToEventData();
                        var eventToken = new StreamPosition(commitTimestamp, commitOffset, commit.Events.Length);

                        result.Add(new StoredEvent(eventToken, eventStreamOffset, eventData));
                    }
                }
            }

            return(result);
        }
Beispiel #2
0
        public async IAsyncEnumerable <StoredEvent> QueryAllAsync(string?streamFilter = null, string?position = null, int take = int.MaxValue,
                                                                  [EnumeratorCancellation] CancellationToken ct = default)
        {
            StreamPosition lastPosition = position;

            var filterDefinition = CreateFilter(streamFilter, lastPosition);

            var find =
                Collection.Find(filterDefinition)
                .Limit(take).Sort(Sort.Ascending(TimestampField).Ascending(EventStreamField));

            var taken = 0;

            await foreach (var current in find.ToAsyncEnumerable(ct))
            {
                foreach (var @event in current.Filtered(lastPosition))
                {
                    yield return(@event);

                    taken++;

                    if (taken == take)
                    {
                        break;
                    }
                }
            }
        }
Beispiel #3
0
        private async Task QueryAsync(Func <StoredEvent, Task> callback, StreamPosition lastPosition, SqlQuerySpec query, EventPredicate filterExpression, CancellationToken ct = default)
        {
            using (Profiler.TraceMethod <CosmosDbEventStore>())
            {
                await documentClient.QueryAsync(collectionUri, query, async commit =>
                {
                    var eventStreamOffset = (int)commit.EventStreamOffset;

                    var commitTimestamp = commit.Timestamp;
                    var commitOffset    = 0;

                    foreach (var @event in commit.Events)
                    {
                        eventStreamOffset++;

                        if (commitOffset > lastPosition.CommitOffset || commitTimestamp > lastPosition.Timestamp)
                        {
                            var eventData = @event.ToEventData();

                            if (filterExpression(eventData))
                            {
                                var eventToken = new StreamPosition(commitTimestamp, commitOffset, commit.Events.Length);

                                await callback(new StoredEvent(commit.EventStream, eventToken, eventStreamOffset, eventData));
                            }
                        }

                        commitOffset++;
                    }
                }, ct);
            }
        }
Beispiel #4
0
        private async Task QueryAsync(Func <StoredEvent, Task> callback, StreamPosition lastPosition, EventFilter filterDefinition, EventPredicate filterExpression, CancellationToken ct = default)
        {
            using (Profiler.TraceMethod <MongoEventStore>())
            {
                await Collection.Find(filterDefinition, options : Batching.Options).Sort(Sort.Ascending(TimestampField)).ForEachPipelineAsync(async commit =>
                {
                    var eventStreamOffset = (int)commit.EventStreamOffset;

                    var commitTimestamp = commit.Timestamp;
                    var commitOffset    = 0;

                    foreach (var @event in commit.Events)
                    {
                        eventStreamOffset++;

                        if (commitOffset > lastPosition.CommitOffset || commitTimestamp > lastPosition.Timestamp)
                        {
                            var eventData = @event.ToEventData();

                            if (filterExpression(eventData))
                            {
                                var eventToken = new StreamPosition(commitTimestamp, commitOffset, commit.Events.Length);

                                await callback(new StoredEvent(commit.EventStream, eventToken, eventStreamOffset, eventData));
                            }
                        }

                        commitOffset++;
                    }
                }, ct);
            }
        }
Beispiel #5
0
        private Task QueryAsync(Func <StoredEvent, Task> callback, StreamPosition lastPosition, FilterDefinition <MongoEventCommit> filter, CancellationToken ct)
        {
            return(Collection.Find(filter).Sort(Sort.Ascending(TimestampField)).ForEachPipelineAsync(async commit =>
            {
                var eventStreamOffset = (int)commit.EventStreamOffset;

                var commitTimestamp = commit.Timestamp;
                var commitOffset = 0;

                foreach (var e in commit.Events)
                {
                    eventStreamOffset++;

                    if (commitOffset > lastPosition.CommitOffset || commitTimestamp > lastPosition.Timestamp)
                    {
                        var eventData = e.ToEventData();
                        var eventToken = new StreamPosition(commitTimestamp, commitOffset, commit.Events.Length);

                        await callback(new StoredEvent(eventToken, eventStreamOffset, eventData));

                        commitOffset++;
                    }
                }
            }, ct));
        }
Beispiel #6
0
        public async Task GetEventsAsync(Func <StoredEvent, Task> callback, string streamFilter = null, string position = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            Guard.NotNull(callback, nameof(callback));

            StreamPosition lastPosition = position;

            var filter = CreateFilter(streamFilter, lastPosition);

            await Collection.Find(filter).Sort(Sort.Ascending(TimestampField)).ForEachAsync(async commit =>
            {
                var eventStreamOffset = (int)commit.EventStreamOffset;

                var commitTimestamp = commit.Timestamp;
                var commitOffset    = 0;

                foreach (var e in commit.Events)
                {
                    eventStreamOffset++;

                    if (commitOffset > lastPosition.CommitOffset || commitTimestamp > lastPosition.Timestamp)
                    {
                        var eventData  = e.ToEventData();
                        var eventToken = new StreamPosition(commitTimestamp, commitOffset, commit.Events.Length);

                        await callback(new StoredEvent(eventToken, eventStreamOffset, eventData));

                        commitOffset++;
                    }
                }
            }, cancellationToken);
        }
Beispiel #7
0
        private static EventFilter CreateFilter(string?streamFilter, StreamPosition streamPosition)
        {
            var filters = new List <EventFilter>();

            AppendByPosition(streamPosition, filters);
            AppendByStream(streamFilter, filters);

            return(Filter.And(filters));
        }
Beispiel #8
0
        public static StreamPosition ToPosition(this long version)
        {
            if (version <= 0)
            {
                return(StreamPosition.Start);
            }

            return(StreamPosition.FromInt64(version));
        }
Beispiel #9
0
        private static EventFilter CreateFilter(string property, object value, StreamPosition streamPosition)
        {
            var filters = new List <EventFilter>();

            AppendByPosition(streamPosition, filters);
            AppendByProperty(property, value, filters);

            return(Filter.And(filters));
        }
Beispiel #10
0
        public Task QueryAsync(Func <StoredEvent, Task> callback, string streamFilter = null, string position = null, CancellationToken ct = default(CancellationToken))
        {
            Guard.NotNull(callback, nameof(callback));

            StreamPosition lastPosition = position;

            var filter = CreateFilter(streamFilter, lastPosition);

            return(QueryAsync(callback, lastPosition, filter, ct));
        }
Beispiel #11
0
        public static SqlQuerySpec CreateByProperty(string property, object value, StreamPosition streamPosition)
        {
            var filters = new List <string>();

            var parameters = new SqlParameterCollection();

            filters.ForPosition(parameters, streamPosition);
            filters.ForProperty(parameters, property, value);

            return(BuildQuery(filters, parameters));
        }
Beispiel #12
0
 private static void AddPositionFilter(StreamPosition streamPosition, List <FilterDefinition <MongoEventCommit> > filters)
 {
     if (streamPosition.IsEndOfCommit)
     {
         filters.Add(Filter.Gt(TimestampField, streamPosition.Timestamp));
     }
     else
     {
         filters.Add(Filter.Gte(TimestampField, streamPosition.Timestamp));
     }
 }
Beispiel #13
0
        public static SqlQuerySpec CreateByFilter(string?streamFilter, StreamPosition streamPosition, string sortOrder, long take)
        {
            var filters = new List <string>();

            var parameters = new SqlParameterCollection();

            filters.ForPosition(parameters, streamPosition);
            filters.ForRegex(parameters, streamFilter);

            return(BuildQuery(filters, parameters, sortOrder, take));
        }
Beispiel #14
0
        public Task QueryAsync(Func <StoredEvent, Task> callback, string?streamFilter = null, string?position = null, CancellationToken ct = default)
        {
            Guard.NotNull(callback);

            StreamPosition lastPosition = position;

            var filterDefinition = CreateFilter(streamFilter, lastPosition);
            var filterExpression = CreateFilterExpression(null, null);

            return(QueryAsync(callback, lastPosition, filterDefinition, filterExpression, ct));
        }
Beispiel #15
0
 private static void AppendByPosition(StreamPosition streamPosition, List <EventFilter> filters)
 {
     if (streamPosition.IsEndOfCommit)
     {
         filters.Add(Filter.Gt(TimestampField, streamPosition.Timestamp));
     }
     else
     {
         filters.Add(Filter.Gte(TimestampField, streamPosition.Timestamp));
     }
 }
Beispiel #16
0
 public static FilterDefinition <MongoEventCommit> ByPosition(StreamPosition streamPosition)
 {
     if (streamPosition.IsEndOfCommit)
     {
         return(Builders <MongoEventCommit> .Filter.Gt(x => x.Timestamp, streamPosition.Timestamp));
     }
     else
     {
         return(Builders <MongoEventCommit> .Filter.Gte(x => x.Timestamp, streamPosition.Timestamp));
     }
 }
        private static EventFilter CreateFilter(string?streamFilter, StreamPosition streamPosition)
        {
            var byPosition = FilterExtensions.ByPosition(streamPosition);
            var byStream   = FilterExtensions.ByStream(streamFilter);

            if (byStream != null)
            {
                return(Filter.And(byPosition, byStream));
            }

            return(byPosition);
        }
Beispiel #18
0
        public Task QueryAsync(Func <StoredEvent, Task> callback, string streamFilter = null, string position = null, CancellationToken ct = default)
        {
            Guard.NotNull(callback, nameof(callback));

            ThrowIfDisposed();

            StreamPosition lastPosition = position;

            var filterDefinition = FilterBuilder.CreateByFilter(streamFilter, lastPosition);
            var filterExpression = FilterBuilder.CreateExpression(null, null);

            return(QueryAsync(callback, lastPosition, filterDefinition, filterExpression, ct));
        }
Beispiel #19
0
        public Task QueryAsync(Func <StoredEvent, Task> callback, string property, object value, string?position = null, CancellationToken ct = default)
        {
            Guard.NotNull(callback);
            Guard.NotNullOrEmpty(property);
            Guard.NotNull(value);

            StreamPosition lastPosition = position;

            var filterDefinition = CreateFilter(property, value, lastPosition);
            var filterExpression = CreateFilterExpression(property, value);

            return(QueryAsync(callback, lastPosition, filterDefinition, filterExpression, ct));
        }
Beispiel #20
0
 private async Task QueryAsync(Func <StoredEvent, Task> callback, StreamPosition position, EventFilter filter, CancellationToken ct = default)
 {
     using (Profiler.TraceMethod <MongoEventStore>())
     {
         await Collection.Find(filter, options : Batching.Options).Sort(Sort.Ascending(TimestampField)).ForEachPipedAsync(async commit =>
         {
             foreach (var @event in commit.Filtered(position))
             {
                 await callback(@event);
             }
         }, ct);
     }
 }
Beispiel #21
0
        private IAsyncEnumerable <StoredEvent> QueryReverseAsync(string streamName, StreamPosition start, long count,
                                                                 CancellationToken ct = default)
        {
            var result = client.ReadStreamAsync(
                Direction.Backwards,
                streamName,
                start,
                count,
                resolveLinkTos: true,
                cancellationToken: ct);

            return(result.Select(x => Formatter.Read(x, StreamPrefix, serializer)));
        }
Beispiel #22
0
        private async Task QueryCurrentAsync(string?streamFilter, StreamPosition lastPosition)
        {
            BsonDocument?resumeToken = null;

            var start =
                lastPosition.Timestamp.Timestamp > 0 ?
                lastPosition.Timestamp.Timestamp - 30 :
                SystemClock.Instance.GetCurrentInstant().Minus(Duration.FromSeconds(30)).ToUnixTimeSeconds();

            var changePipeline = Match(streamFilter);
            var changeStart    = new BsonTimestamp((int)start, 0);

            while (!stopToken.IsCancellationRequested)
            {
                var changeOptions = new ChangeStreamOptions();

                if (resumeToken != null)
                {
                    changeOptions.StartAfter = resumeToken;
                }
                else
                {
                    changeOptions.StartAtOperationTime = changeStart;
                }

                using (var cursor = eventStore.TypedCollection.Watch(changePipeline, changeOptions, stopToken.Token))
                {
                    var isRead = false;

                    await cursor.ForEachAsync(async change =>
                    {
                        if (change.OperationType == ChangeStreamOperationType.Insert)
                        {
                            foreach (var storedEvent in change.FullDocument.Filtered(lastPosition))
                            {
                                await eventSubscriber.OnEventAsync(this, storedEvent);
                            }
                        }

                        isRead = true;
                    }, stopToken.Token);

                    resumeToken = cursor.GetResumeToken();

                    if (!isRead)
                    {
                        await Task.Delay(1000);
                    }
                }
            }
        }
Beispiel #23
0
        public Task QueryAsync(Func <StoredEvent, Task> callback, string property, object value, string position = null, CancellationToken ct = default)
        {
            Guard.NotNull(callback, nameof(callback));
            Guard.NotNullOrEmpty(property, nameof(property));
            Guard.NotNull(value, nameof(value));

            ThrowIfDisposed();

            StreamPosition lastPosition = position;

            var filterDefinition = FilterBuilder.CreateByProperty(property, value, lastPosition);
            var filterExpression = FilterBuilder.CreateExpression(property, value);

            return(QueryAsync(callback, lastPosition, filterDefinition, filterExpression, ct));
        }
Beispiel #24
0
        public async Task <IReadOnlyList <StoredEvent> > QueryLatestAsync(string streamName, int count)
        {
            Guard.NotNullOrEmpty(streamName, nameof(streamName));

            ThrowIfDisposed();

            if (count <= 0)
            {
                return(EmptyEvents);
            }

            using (Profiler.TraceMethod <CosmosDbEventStore>())
            {
                var query = FilterBuilder.ByStreamNameDesc(streamName, count);

                var result = new List <StoredEvent>();

                await documentClient.QueryAsync(collectionUri, query, commit =>
                {
                    var eventStreamOffset = (int)commit.EventStreamOffset;

                    var commitTimestamp = commit.Timestamp;
                    var commitOffset    = 0;

                    foreach (var @event in commit.Events)
                    {
                        eventStreamOffset++;

                        var eventData  = @event.ToEventData();
                        var eventToken = new StreamPosition(commitTimestamp, commitOffset, commit.Events.Length);

                        result.Add(new StoredEvent(streamName, eventToken, eventStreamOffset, eventData));
                    }

                    return(Task.CompletedTask);
                });

                IEnumerable <StoredEvent> ordered = result.OrderBy(x => x.EventStreamNumber);

                if (result.Count > count)
                {
                    ordered = ordered.Skip(result.Count - count);
                }

                return(ordered.ToList());
            }
        }
Beispiel #25
0
        public async Task <IReadOnlyList <StoredEvent> > QueryLatestAsync(string streamName, int count)
        {
            Guard.NotNullOrEmpty(streamName);

            if (count <= 0)
            {
                return(EmptyEvents);
            }

            using (Profiler.TraceMethod <MongoEventStore>())
            {
                var commits =
                    await Collection.Find(
                        Filter.Eq(EventStreamField, streamName))
                    .Sort(Sort.Descending(TimestampField)).Limit(count).ToListAsync();

                var result = new List <StoredEvent>();

                foreach (var commit in commits)
                {
                    var eventStreamOffset = (int)commit.EventStreamOffset;

                    var commitTimestamp = commit.Timestamp;
                    var commitOffset    = 0;

                    foreach (var @event in commit.Events)
                    {
                        eventStreamOffset++;

                        var eventData  = @event.ToEventData();
                        var eventToken = new StreamPosition(commitTimestamp, commitOffset, commit.Events.Length);

                        result.Add(new StoredEvent(streamName, eventToken, eventStreamOffset, eventData));
                    }
                }

                IEnumerable <StoredEvent> ordered = result.OrderBy(x => x.EventStreamNumber);

                if (result.Count > count)
                {
                    ordered = ordered.Skip(result.Count - count);
                }

                return(ordered.ToList());
            }
        }
        public async IAsyncEnumerable <StoredEvent> QueryAllReverseAsync(string?streamFilter = null, Instant timestamp = default, long take = long.MaxValue,
                                                                         [EnumeratorCancellation] CancellationToken ct = default)
        {
            if (take <= 0)
            {
                yield break;
            }

            StreamPosition lastPosition = timestamp;

            var filterDefinition = CreateFilter(streamFilter, lastPosition);

            var find =
                Collection.Find(filterDefinition, options: Batching.Options)
                .Limit((int)take).Sort(Sort.Descending(TimestampField).Ascending(EventStreamField));

            var taken = 0;

            using (var cursor = await find.ToCursorAsync(ct))
            {
                while (taken < take && await cursor.MoveNextAsync(ct))
                {
                    foreach (var current in cursor.Current)
                    {
                        foreach (var @event in current.Filtered(lastPosition).Reverse())
                        {
                            yield return(@event);

                            taken++;

                            if (taken == take)
                            {
                                break;
                            }
                        }

                        if (taken == take)
                        {
                            break;
                        }
                    }
                }
            }
        }
Beispiel #27
0
        public static StreamPosition ToPosition(this string?position, bool inclusive)
        {
            if (string.IsNullOrWhiteSpace(position))
            {
                return(StreamPosition.Start);
            }

            if (long.TryParse(position, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedPosition))
            {
                if (!inclusive)
                {
                    parsedPosition++;
                }

                return(StreamPosition.FromInt64(parsedPosition));
            }

            return(StreamPosition.Start);
        }
Beispiel #28
0
        public async Task QueryAsync(Func <StoredEvent, Task> callback, string?streamFilter = null, string?position = null, CancellationToken ct = default)
        {
            Guard.NotNull(callback, nameof(callback));

            ThrowIfDisposed();

            StreamPosition lastPosition = position;

            var filterDefinition = FilterBuilder.CreateByFilter(streamFilter, lastPosition);
            var filterExpression = FilterBuilder.CreateExpression(null, null);

            using (Profiler.TraceMethod <CosmosDbEventStore>())
            {
                await documentClient.QueryAsync(collectionUri, filterDefinition, async commit =>
                {
                    var eventStreamOffset = (int)commit.EventStreamOffset;

                    var commitTimestamp = commit.Timestamp;
                    var commitOffset    = 0;

                    foreach (var @event in commit.Events)
                    {
                        eventStreamOffset++;

                        if (commitOffset > lastPosition.CommitOffset || commitTimestamp > lastPosition.Timestamp)
                        {
                            var eventData = @event.ToEventData();

                            if (filterExpression(eventData))
                            {
                                var eventToken = new StreamPosition(commitTimestamp, commitOffset, commit.Events.Length);

                                await callback(new StoredEvent(commit.EventStream, eventToken, eventStreamOffset, eventData));
                            }
                        }

                        commitOffset++;
                    }
                }, ct);
            }
        }
Beispiel #29
0
        public async Task <IReadOnlyList <StoredEvent> > QueryAsync(string streamName, long streamPosition = 0)
        {
            Guard.NotNullOrEmpty(streamName);

            using (Profiler.TraceMethod <MongoEventStore>())
            {
                var commits =
                    await Collection.Find(
                        Filter.And(
                            Filter.Eq(EventStreamField, streamName),
                            Filter.Gte(EventStreamOffsetField, streamPosition - MaxCommitSize)))
                    .Sort(Sort.Ascending(TimestampField)).ToListAsync();

                var result = new List <StoredEvent>();

                foreach (var commit in commits)
                {
                    var eventStreamOffset = (int)commit.EventStreamOffset;

                    var commitTimestamp = commit.Timestamp;
                    var commitOffset    = 0;

                    foreach (var @event in commit.Events)
                    {
                        eventStreamOffset++;

                        if (eventStreamOffset >= streamPosition)
                        {
                            var eventData  = @event.ToEventData();
                            var eventToken = new StreamPosition(commitTimestamp, commitOffset, commit.Events.Length);

                            result.Add(new StoredEvent(streamName, eventToken, eventStreamOffset, eventData));
                        }
                    }
                }

                return(result);
            }
        }
Beispiel #30
0
        public static IEnumerable <StoredEvent> Filtered(this MongoEventCommit commit, long streamPosition)
        {
            var eventStreamOffset = commit.EventStreamOffset;

            var commitTimestamp = commit.Timestamp;
            var commitOffset    = 0;

            foreach (var @event in commit.Events)
            {
                eventStreamOffset++;

                if (eventStreamOffset >= streamPosition)
                {
                    var eventData     = @event.ToEventData();
                    var eventPosition = new StreamPosition(commitTimestamp, commitOffset, commit.Events.Length);

                    yield return(new StoredEvent(commit.EventStream, eventPosition, eventStreamOffset, eventData));
                }

                commitOffset++;
            }
        }