예제 #1
0
 /// <summary>
 /// Initializes <see cref="CollectionSegment" />.
 /// </summary>
 /// <param name="items">
 /// The items that belong to this page.
 /// </param>
 /// <param name="info">
 /// Additional information about this page.
 /// </param>
 /// <param name="getTotalCount">
 /// A delegate to request the the total count.
 /// </param>
 public CollectionSegment(
     IReadOnlyCollection<T> items,
     CollectionSegmentInfo info,
     Func<CancellationToken, ValueTask<int>> getTotalCount)
     : base(new CollectionWrapper(items), info, getTotalCount)
 {
     Items = items;
 }
예제 #2
0
 /// <summary>
 /// Initializes <see cref="CollectionSegment" />.
 /// </summary>
 /// <param name="items">
 /// The items that belong to this page.
 /// </param>
 /// <param name="info">
 /// Additional information about this page.
 /// </param>
 /// <param name="getTotalCount">
 /// A delegate to request the the total count.
 /// </param>
 public CollectionSegment(
     IReadOnlyCollection <object> items,
     CollectionSegmentInfo info,
     Func <CancellationToken, ValueTask <int> > getTotalCount)
 {
     Items = items ??
             throw new ArgumentNullException(nameof(items));
     Info           = info;
     _getTotalCount = getTotalCount ??
                      throw new ArgumentNullException(nameof(getTotalCount));
 }
        public void CreateCollectionSegment_ItemsNull_ArgumentNullException()
        {
            // arrange
            var pageInfo = new CollectionSegmentInfo(true, true);

            // act
            Action a = () => new CollectionSegment <string>(
                null, pageInfo, ct => throw new NotSupportedException());

            // assert
            Assert.Throws <ArgumentNullException>(a);
        }
        public void CreateCollectionSegment_PageInfoAndItems_PassedCorrectly()
        {
            // arrange
            var pageInfo = new CollectionSegmentInfo(true, true);
            var items    = new List <string>();

            // act
            var collection = new CollectionSegment(
                items,
                pageInfo,
                ct => throw new NotSupportedException());

            // assert
            Assert.Equal(pageInfo, collection.Info);
            Assert.Equal(items, collection.Items);
        }
        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);
            }

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

            async ValueTask <int> CountAsync(CancellationToken cancellationToken) =>
            await Task.Run(original.Count, cancellationToken).ConfigureAwait(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));
        }