예제 #1
0
    /// <summary>
    /// Applies the pagination algorithm to the provided data.
    /// </summary>
    /// <param name="query">The query builder.</param>
    /// <param name="arguments">The paging arguments.</param>
    /// <param name="totalCount">Specify the total amount of elements</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns></returns>
    public async ValueTask <CollectionSegment <TEntity> > ApplyPaginationAsync(
        TQuery query,
        OffsetPagingArguments arguments,
        int?totalCount,
        CancellationToken cancellationToken)
    {
        Func <CancellationToken, ValueTask <int> > getTotalCount = totalCount is null
            ? async ct => await CountAsync(query, ct)
            : _ => new ValueTask <int>(totalCount.Value);

        TQuery sliced = query;

        if (arguments.Skip is { } skip)
        {
            sliced = ApplySkip(sliced, skip);
        }

        if (arguments.Take is { } take)
        {
            sliced = ApplyTake(sliced, take + 1);
        }

        IReadOnlyList <TEntity> items =
            await ExecuteAsync(sliced, cancellationToken).ConfigureAwait(false);

        bool hasNextPage     = items.Count == arguments.Take + 1;
        bool hasPreviousPage = (arguments.Skip ?? 0) > 0;

        CollectionSegmentInfo pageInfo = new(hasNextPage, hasPreviousPage);

        items = new SkipLastCollection <TEntity>(items, skipLast: hasNextPage);

        return(new CollectionSegment <TEntity>(
                   items,
                   pageInfo,
                   getTotalCount));
    }
    /// <summary>
    /// Applies the pagination algorithm to the provided query.
    /// </summary>
    /// <param name="query">The query builder.</param>
    /// <param name="arguments">The paging arguments.</param>
    /// <param name="totalCount">Specify the total amount of elements</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>
    /// Returns the connection.
    /// </returns>
    public async ValueTask <Connection <TEntity> > ApplyPaginationAsync(
        TQuery query,
        CursorPagingArguments arguments,
        int?totalCount,
        CancellationToken cancellationToken)
    {
        if (query is null)
        {
            throw new ArgumentNullException(nameof(query));
        }

        var maxElementCount = int.MaxValue;
        Func <CancellationToken, ValueTask <int> > executeCount = totalCount is null ?
                                                                  ct => CountAsync(query, ct)
            : _ => new ValueTask <int>(totalCount.Value);

        // We only need the maximal element count if no `before` counter is set and no `first`
        // argument is provided.
        if (arguments.Before is null && arguments.First is null)
        {
            var count = await executeCount(cancellationToken);

            maxElementCount = count;

            // in case we already know the total count, we override the countAsync parameter
            // so that we do not have to fetch the count twice
            executeCount = _ => new ValueTask <int>(count);
        }

        CursorPagingRange range = SliceRange(arguments, maxElementCount);

        var skip = range.Start;
        var take = range.Count();

        // we fetch one element more than we requested
        if (take != maxElementCount)
        {
            take++;
        }

        TQuery slicedSource = query;

        if (skip != 0)
        {
            slicedSource = ApplySkip(query, skip);
        }

        if (take != maxElementCount)
        {
            slicedSource = ApplyTake(slicedSource, take);
        }

        IReadOnlyList <Edge <TEntity> > selectedEdges =
            await ExecuteAsync(slicedSource, skip, cancellationToken);

        var moreItemsReturnedThanRequested = selectedEdges.Count > range.Count();
        var isSequenceFromStart            = range.Start == 0;

        selectedEdges = new SkipLastCollection <Edge <TEntity> >(
            selectedEdges,
            moreItemsReturnedThanRequested);

        ConnectionPageInfo pageInfo =
            CreatePageInfo(isSequenceFromStart, moreItemsReturnedThanRequested, selectedEdges);

        return(new Connection <TEntity>(selectedEdges, pageInfo, executeCount));
    }