public override void OnConfigure(
            IDescriptorContext context,
            IObjectFieldDescriptor descriptor,
            MemberInfo member)
        {
            descriptor.Resolve(async ctx =>
            {
                ICharacter character            = ctx.Parent <ICharacter>();
                ICharacterRepository repository = ctx.Service <ICharacterRepository>();
                //This is injected by the PreProcessing middleware wen enabled...
                var graphQLParams = new GraphQLParamsContext(ctx);

                //********************************************************************************
                //Perform some pre-processed retrieval of data from the Repository...
                //Notice Pagination processing is pushed down to the Repository layer also!

                //Get RepoDb specific mapper for the GraphQL parameter context...
                //Note: It's important that we map to the DB Model (not the GraphQL model).
                var repoDbParams = new GraphQLRepoDbMapper <CharacterDbModel>(graphQLParams);

                //Now we can retrieve the related and paginated data from the Repo...
                var pagedFriends = await repository.GetCharacterFriendsAsync(character.Id, repoDbParams.GetCursorPagingParameters());
                return(new PreProcessedCursorSlice <ICharacter>(pagedFriends));
                //********************************************************************************
            });
        }
Exemple #2
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}].");
        }
        public override void OnConfigure(
            IDescriptorContext context,
            IObjectFieldDescriptor descriptor,
            MemberInfo member)
        {
            descriptor.Resolver(ctx =>
            {
                ICharacter character            = ctx.Parent <ICharacter>();
                ICharacterRepository repository = ctx.Service <ICharacterRepository>();

                //********************************************************************************
                //Perform some pre-processed Paging (FYI, without sorting this may be unprdeicatble
                //  but works here due to the in-memory store used by Star Wars example!
                var graphQLParams = new GraphQLParamsContext(ctx);
                var friends       = repository.GetCharacters(character.Friends.ToArray());

                var pagedFriends = friends.SliceAsCursorPage(graphQLParams.PagingArgs);
                return(new PreProcessedCursorSlice <ICharacter>(pagedFriends));
                //********************************************************************************
            });
        }
Exemple #4
0
        protected override ValueTask <CollectionSegment> SliceAsync(IResolverContext context, object source, OffsetPagingArguments 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 Collection Segment with appropriate Paging Details...
            if (source is IPreProcessedOffsetPageResults <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.
                var segmentResults = pagedResults?.ToList() ?? new List <TEntity>();

                var collectionSegmentInfo = new CollectionSegmentInfo(
                    hasNextPage: pagedResults?.HasNextPage ?? false,
                    hasPreviousPage: pagedResults?.HasPreviousPage ?? false
                    );

                var graphQLConnection = new CollectionSegment(
                    (IReadOnlyCollection <object>)segmentResults,
                    collectionSegmentInfo,
                    ct => new ValueTask <int>(totalCount ?? throw new InvalidOperationException())
                    );

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

            throw new GraphQLException($"[{nameof(PreProcessedOffsetPagingHandler<TEntity>)}] cannot handle the specified data source of type [{source.GetType().Name}].");
        }