public static async Task <PagedResult <TEntity> > GetPagedQueryResultsAsync <TEntity>(
            this IDynamoDBContext dynamoDbContext, QueryOperationConfig queryConfig) where TEntity : class
        {
            var dbResults = new List <TEntity>();
            var table     = dynamoDbContext.GetTargetTable <TEntity>();

            var search     = table.Query(queryConfig);
            var resultsSet = await search.GetNextSetAsync().ConfigureAwait(false);

            var paginationToken = search.PaginationToken;

            if (resultsSet.Any())
            {
                dbResults.AddRange(dynamoDbContext.FromDocuments <TEntity>(resultsSet));

                // Look ahead for any more, but only if we have a token
                if (!string.IsNullOrEmpty(PaginationDetails.EncodeToken(paginationToken)))
                {
                    queryConfig.PaginationToken = paginationToken;
                    queryConfig.Limit           = 1;
                    search     = table.Query(queryConfig);
                    resultsSet = await search.GetNextSetAsync().ConfigureAwait(false);

                    if (!resultsSet.Any())
                    {
                        paginationToken = null;
                    }
                }
            }

            return(new PagedResult <TEntity>(dbResults, new PaginationDetails(paginationToken)));
        }
        public async Task <IEnumerable <CelebrityEventBase> > ReadEventsAsync(string aggregateId, long?version = null, bool consistentRead = false, CancellationToken cancellationToken = default)
        {
            if (aggregateId is null)
            {
                throw new ArgumentNullException(nameof(aggregateId));
            }

            var table = _dbContext.GetTargetTable <DynamoDbEventModel>(_configuration);

            var search = table.Query(new QueryOperationConfig
            {
                KeyExpression = new Expression
                {
                    ExpressionStatement      = "#aggregate_id = :v_aggregate_id and #aggregate_version >= :v_aggregate_version",
                    ExpressionAttributeNames = new Dictionary <string, string>
                    {
                        { "#aggregate_id", "AggregateId" },
                        { "#aggregate_version", "AggregateVersion" }
                    },
                    ExpressionAttributeValues = new Dictionary <string, DynamoDBEntry>
                    {
                        { ":v_aggregate_id", aggregateId },
                        { ":v_aggregate_version", version ?? 1 }
                    },
                },
                IndexName      = _options.IndexName,
                ConsistentRead = consistentRead
            });

            var events = new List <DynamoDbEventModel>();

            do
            {
                var items = await search.GetNextSetAsync(cancellationToken);

                if (items.Any())
                {
                    events.AddRange(_dbContext.FromDocuments <DynamoDbEventModel>(items));
                }
            }while(search.IsDone is false);

            return(ParseToCelebrityEvents(events));
        }
        public async Task <PagedResult <Note> > GetByTargetIdAsync(GetNotesByTargetIdQuery query)
        {
            int pageSize = query.PageSize.HasValue ? query.PageSize.Value : MAX_RESULTS;
            var dbNotes  = new List <NoteDb>();
            var table    = _dynamoDbContext.GetTargetTable <NoteDb>();

            var queryConfig = new QueryOperationConfig
            {
                IndexName       = GETNOTESBYTARGETIDINDEX,
                BackwardSearch  = true,
                ConsistentRead  = true,
                Limit           = pageSize,
                PaginationToken = PaginationDetails.DecodeToken(query.PaginationToken),
                Filter          = new QueryFilter(TARGETID, QueryOperator.Equal, query.TargetId)
            };
            var search = table.Query(queryConfig);

            _logger.LogDebug($"Querying {queryConfig.IndexName} index for targetId {query.TargetId}");
            var resultsSet = await search.GetNextSetAsync().ConfigureAwait(false);

            var paginationToken = search.PaginationToken;

            if (resultsSet.Any())
            {
                dbNotes.AddRange(_dynamoDbContext.FromDocuments <NoteDb>(resultsSet));

                // Look ahead for any more, but only if we have a token
                if (!string.IsNullOrEmpty(PaginationDetails.EncodeToken(paginationToken)))
                {
                    queryConfig.PaginationToken = paginationToken;
                    queryConfig.Limit           = 1;
                    search     = table.Query(queryConfig);
                    resultsSet = await search.GetNextSetAsync().ConfigureAwait(false);

                    if (!resultsSet.Any())
                    {
                        paginationToken = null;
                    }
                }
            }

            return(new PagedResult <Note>(dbNotes.Select(x => x.ToDomain()), new PaginationDetails(paginationToken)));
        }