コード例 #1
0
ファイル: Connection~1.cs プロジェクト: anadale/hotchocolate
 public Connection(
     IReadOnlyCollection <Edge <T> > edges,
     ConnectionPageInfo info,
     Func <CancellationToken, ValueTask <int> > getTotalCount)
     : base(edges, info, getTotalCount)
 {
     Edges = edges;
 }
コード例 #2
0
 public Connection(
     IReadOnlyCollection <IEdge> edges,
     ConnectionPageInfo info,
     Func <CancellationToken, ValueTask <int> > getTotalCount)
 {
     _getTotalCount = getTotalCount ??
                      throw new ArgumentNullException(nameof(getTotalCount));
     Edges = edges ??
             throw new ArgumentNullException(nameof(edges));
     Info = info ??
            throw new ArgumentNullException(nameof(info));
 }
コード例 #3
0
        protected override ValueTask <Connection> SliceAsync(IResolverContext context, object source, CursorPagingArguments arguments)
        {
            //If Appropriate we handle the values here to ensure that no post-processing is done other than
            //  correctly mapping the results into a GraphQL Connection as Edges with Cursors...
            if (source is IPreProcessedCursorSlice <TEntity> pagedResults)
            {
                bool includeTotalCountEnabled = this.PagingOptions.IncludeTotalCount ?? PagingDefaults.IncludeTotalCount;
                var  graphQLParamsContext     = new GraphQLParamsContext(context);

                //Optimized to only require TotalCount value if the query actually requested it!
                if (includeTotalCountEnabled && graphQLParamsContext.IsTotalCountRequested && pagedResults.TotalCount == null)
                {
                    throw new InvalidOperationException($"Total Count is requested in the query, but was not provided with the results [{this.GetType().GetTypeName()}] from the resolvers pre-processing logic; TotalCount is null.");
                }

                int?totalCount = pagedResults.TotalCount;

                //Ensure we are null safe and return a valid empty list by default.
                IReadOnlyList <IndexEdge <TEntity> > selectedEdges =
                    pagedResults?.ToEdgeResults().ToList() ?? new List <IndexEdge <TEntity> >();;

                IndexEdge <TEntity>?firstEdge = selectedEdges.FirstOrDefault();
                IndexEdge <TEntity>?lastEdge  = selectedEdges.LastOrDefault();

                var connectionPageInfo = new ConnectionPageInfo(
                    hasNextPage: pagedResults?.HasNextPage ?? false,
                    hasPreviousPage: pagedResults?.HasPreviousPage ?? false,
                    startCursor: firstEdge?.Cursor,
                    endCursor: lastEdge?.Cursor,
                    totalCount: totalCount ?? 0
                    );

                var graphQLConnection = new Connection <TEntity>(
                    selectedEdges,
                    connectionPageInfo,
                    ct => new ValueTask <int>(connectionPageInfo.TotalCount ?? 0)
                    );

                return(new ValueTask <Connection>(graphQLConnection));
            }

            throw new GraphQLException($"[{nameof(PreProcessedCursorPagingHandler<TEntity>)}] cannot handle the specified data source of type [{source.GetType().Name}].");
        }
コード例 #4
0
    /// <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));
    }