// subscribe will use the subscribe resolver to create a source stream that yields
            // the event messages from the underlying pub/sub-system.
            private async ValueTask <ISourceStream> SubscribeAsync()
            {
                OperationContext operationContext = _operationContextPool.Get();

                try
                {
                    // first we will create the root value which essentially
                    // is the subscription object. In some cases this object is null.
                    var rootValue = RootValueResolver.Resolve(
                        _requestContext,
                        _requestContext.Services,
                        _subscriptionType,
                        ref _cachedRootValue);

                    // next we need to initialize our operation context so that we have access to
                    // variables services and other things.
                    // The subscribe resolver will use a noop dispatcher and all DataLoader are
                    // dispatched immediately.
                    operationContext.Initialize(
                        _requestContext,
                        _requestContext.Services,
                        NoopBatchDispatcher.Default,
                        _requestContext.Operation !,
                        _queryPlan,
                        _requestContext.Variables !,
                        rootValue,
                        _resolveQueryRootValue);

                    // next we need a result map so that we can store the subscribe temporarily
                    // while executing the subscribe pipeline.
                    ResultMap  resultMap     = operationContext.Result.RentResultMap(1);
                    ISelection rootSelection = _rootSelections.Selections[0];

                    // we create a temporary middleware context so that we can use the standard
                    // resolver pipeline.
                    var middlewareContext = new MiddlewareContext();
                    middlewareContext.Initialize(
                        operationContext,
                        rootSelection,
                        resultMap,
                        1,
                        rootValue,
                        Path.New(rootSelection.ResponseName),
                        ImmutableDictionary <string, object?> .Empty);

                    // it is important that we correctly coerce the arguments before
                    // invoking subscribe.
                    if (!rootSelection.Arguments.TryCoerceArguments(
                            middlewareContext,
                            out IReadOnlyDictionary <NameString, ArgumentValue>?coercedArgs))
                    {
                        // the middleware context reports errors to the operation context,
                        // this means if we failed, we need to grab the coercion errors from there
                        // and just throw a GraphQLException.
                        throw new GraphQLException(operationContext.Result.Errors);
                    }

                    // if everything is fine with the arguments we still need to assign them.
                    middlewareContext.Arguments = coercedArgs;

                    // last but not least we can invoke the subscribe resolver which will subscribe
                    // to the underlying pub/sub-system yielding the source stream.
                    ISourceStream sourceStream =
                        await rootSelection.Field.SubscribeResolver !.Invoke(middlewareContext)
                        .ConfigureAwait(false);

                    if (operationContext.Result.Errors.Count > 0)
                    {
                        // again if we have any errors we will just throw them and not opening
                        // any subscription context.
                        throw new GraphQLException(operationContext.Result.Errors);
                    }

                    return(sourceStream);
                }
                catch
                {
                    // if there is an error we will just dispose our instrumentation scope
                    // the error is reported in the request level in this case.
                    _subscriptionScope?.Dispose();
                    _subscriptionScope = null;
                    throw;
                }
                finally
                {
                    operationContext.Result.DropResult();
                    _operationContextPool.Return(operationContext);
                }
            }
Exemple #2
0
        public static bool TryComplete(
            IOperationContext operationContext,
            MiddlewareContext resolverContext,
            ISelection selection,
            Path path,
            IType fieldType,
            string responseName,
            int responseIndex,
            object?result,
            List <ResolverTask> bufferedTasks,
            out object?completedResult)
        {
            TypeKind typeKind = fieldType.Kind;

            if (typeKind is TypeKind.NonNull)
            {
                return(TryComplete(
                           operationContext,
                           resolverContext,
                           selection,
                           path,
                           fieldType.InnerType(),
                           responseName,
                           responseIndex,
                           result,
                           bufferedTasks,
                           out completedResult) &&
                       completedResult is not null);
            }

            if (result is null)
            {
                completedResult = null;
                return(true);
            }

            if (typeKind is TypeKind.List)
            {
                return(TryCompleteListValue(
                           operationContext,
                           resolverContext,
                           selection,
                           path,
                           fieldType,
                           responseName,
                           responseIndex,
                           result,
                           bufferedTasks,
                           out completedResult));
            }

            if (typeKind is TypeKind.Scalar or TypeKind.Enum)
            {
                return(TryCompleteLeafValue(
                           operationContext,
                           resolverContext,
                           selection,
                           path,
                           fieldType,
                           result,
                           out completedResult));
            }

            if (typeKind is TypeKind.Object or TypeKind.Interface or TypeKind.Union)
            {
                return(TryCompleteCompositeValue(
                           operationContext,
                           resolverContext,
                           selection,
                           path,
                           fieldType,
                           result,
                           bufferedTasks,
                           out completedResult));
            }

            ReportError(
                operationContext,
                resolverContext,
                selection,
                UnexpectedValueCompletionError(selection.SyntaxNode, path));

            completedResult = null;
            return(false);
        }