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)); }