예제 #1
0
        private static void CollectSelections(
            IResolverContext context,
            IFieldSelection selection,
            ICollection <IFieldSelection> collected)
        {
            if (selection.Field.Type.IsLeafType())
            {
                collected.Add(selection);
            }

            if (selection.Field.Type.NamedType() is ObjectType objectType)
            {
                foreach (IFieldSelection child in context.GetSelections(
                             objectType, selection.SyntaxNode.SelectionSet))
                {
                    CollectSelections(context, child, collected);
                }
            }
        }
    /// <summary>
    /// TotalCount is one of the heaviest operations. It is only necessary to load totalCount
    /// when it is enabled (IncludeTotalCount) and when it is contained in the selection set.
    ///
    /// This method checks if the total count is selected
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public static bool IsTotalCountSelected(this IResolverContext context)
    {
        // TotalCount is one of the heaviest operations. It is only necessary to load totalCount
        // when it is enabled (IncludeTotalCount) and when it is contained in the selection set.
        if (context.Selection.Type is ObjectType objectType &&
            context.Selection.SyntaxNode.SelectionSet is { } selectionSet)
        {
            IReadOnlyList <IFieldSelection> selections =
                context.GetSelections(objectType, selectionSet, true);

            for (var i = 0; i < selections.Count; i++)
            {
                if (selections[i].Field.Name.Value is ConnectionType.Names.TotalCount)
                {
                    return(true);
                }
            }
        }

        return(false);
    }
        protected override async ValueTask <CollectionSegment> SliceAsync(
            IResolverContext context,
            object source,
            OffsetPagingArguments arguments)
        {
            IQueryable <TItemType> queryable = source switch
            {
                IQueryable <TItemType> q => q,
                IEnumerable <TItemType> e => e.AsQueryable(),
                _ => throw new GraphQLException("Cannot handle the specified data source.")
            };

            IQueryable <TItemType> original = queryable;

            if (arguments.Skip.HasValue)
            {
                queryable = queryable.Skip(arguments.Skip.Value);
            }

            queryable = queryable.Take(arguments.Take + 1);
            List <TItemType> items =
                await ExecuteQueryableAsync(queryable, context.RequestAborted)
                .ConfigureAwait(false);

            var pageInfo = new CollectionSegmentInfo(
                items.Count == arguments.Take + 1,
                (arguments.Skip ?? 0) > 0);

            if (items.Count > arguments.Take)
            {
                items.RemoveAt(arguments.Take);
            }

            Func <CancellationToken, ValueTask <int> > getTotalCount =
                ct => throw new InvalidOperationException();

            // TotalCount is one of the heaviest operations. It is only necessary to load totalCount
            // when it is enabled (IncludeTotalCount) and when it is contained in the selection set.
            if (IncludeTotalCount &&
                context.Field.Type is ObjectType objectType &&
                context.FieldSelection.SelectionSet is {} selectionSet)
            {
                IReadOnlyList <IFieldSelection> selections = context
                                                             .GetSelections(objectType, selectionSet, true);

                var includeTotalCount = false;
                for (var i = 0; i < selections.Count; i++)
                {
                    if (selections[i].Field.Name.Value is "totalCount")
                    {
                        includeTotalCount = true;
                        break;
                    }
                }

                // When totalCount is included in the selection set we prefetch it, then capture the
                // count in a variable, to pass it into the clojure
                if (includeTotalCount)
                {
                    var captureCount = original.Count();
                    getTotalCount = ct => new ValueTask <int>(captureCount);
                }
            }

            return(new CollectionSegment(
                       (IReadOnlyCollection <object>)items,
                       pageInfo,
                       getTotalCount));
        }