public ExecutionContext BuildExecutionContext(
            Schema schema,
            object root,
            Document document,
            string operationName,
            Inputs inputs)
        {
            var context = new ExecutionContext();
            context.Schema = schema;
            context.RootObject = root;

            var operation = !string.IsNullOrWhiteSpace(operationName)
                ? document.Operations.WithName(operationName)
                : document.Operations.FirstOrDefault();

            if (operation == null)
            {
                context.Errors.Add(new ExecutionError("Unknown operation name: {0}".ToFormat(operationName)));
                return context;
            }

            context.Operation = operation;
            context.Variables = GetVariableValues(schema, operation.Variables, inputs);
            context.Fragments = document.Fragments;

            return context;
        }
예제 #2
0
        public Task <object> ExecuteOperation(ExecutionContext context)
        {
            var rootType = GetOperationRootType(context.Schema, context.Operation);
            var fields   = CollectFields(
                context,
                rootType,
                context.Operation.Selections,
                new Dictionary <string, Fields>(),
                new List <string>());

            return(ExecuteFields(context, rootType, context.RootValue, fields));
        }
        public Task <Dictionary <string, object> > ExecuteOperationAsync(ExecutionContext context)
        {
            var rootType = GetOperationRootType(context.Document, context.Schema, context.Operation);
            var fields   = CollectFields(
                context,
                rootType,
                context.Operation.SelectionSet,
                new Dictionary <string, Field>(),
                new List <string>());

            return(ExecuteFieldsAsync(context, rootType, context.RootValue, fields, new string[0]));
        }
예제 #4
0
        private IDictionary <string, Field> SubFieldsFor(ExecutionContext context, IGraphType fieldType, Field field)
        {
            if (!(fieldType is IObjectGraphType) || !field.SelectionSet.Selections.Any())
            {
                return(null);
            }

            var subFields        = new Dictionary <string, Field>();
            var visitedFragments = new List <string>();
            var fields           = CollectFields(context, fieldType, field.SelectionSet, subFields, visitedFragments);

            return(fields);
        }
예제 #5
0
        private ResolveFieldResult <object> GenerateError(
            ResolveFieldResult <object> resolveResult,
            Field field,
            ExecutionContext context,
            Exception exc,
            IEnumerable <string> path)
        {
            var error = new ExecutionError("Error trying to resolve {0}.".ToFormat(field.Name), exc);

            error.AddLocation(field, context.Document);
            error.Path = path;
            context.Errors.Add(error);
            resolveResult.Skip = false;
            return(resolveResult);
        }
        public async Task <IDictionary <string, object> > ExecuteFieldsAsync(ExecutionContext context, IObjectGraphType rootType, object source, Dictionary <string, Field> fields, IEnumerable <string> path)
        {
            var data          = new ConcurrentDictionary <string, object>();
            var externalTasks = new List <Task>();

            foreach (var fieldCollection in fields)
            {
                var currentPath = path.Concat(new[] { fieldCollection.Key });

                var field     = fieldCollection.Value;
                var fieldType = GetFieldDefinition(context.Document, context.Schema, rootType, field);

                if (fieldType?.Resolver == null || !fieldType.Resolver.RunThreaded() || context.Operation.OperationType == OperationType.Mutation || fields.Count == 1)
                {
                    await ExtractFieldAsync(context, rootType, source, field, fieldType, data, currentPath)
                    .ConfigureAwait(false);
                }
                else
                {
                    var task = Task.Run(() => ExtractFieldAsync(context, rootType, source, field, fieldType, data, currentPath), context.CancellationToken);

                    externalTasks.Add(task);
                }
            }

            if (externalTasks.Count > 0)
            {
                await Task.WhenAll(externalTasks)
                .ConfigureAwait(false);
            }

            var ordered = new Dictionary <string, object>();

            foreach (var fieldCollection in fields)
            {
                var name = fieldCollection.Key;

                if (!data.ContainsKey(name))
                {
                    continue;
                }

                ordered.Add(name, data[name]);
            }

            return(ordered);
        }
예제 #7
0
        protected override IExecutionStrategy SelectExecutionStrategy(ExecutionContext context)
        {
            switch (context.Operation.OperationType)
            {
            case OperationType.Query:
                return(new ParallelExecutionWithAuthorizationStrategy());

            case OperationType.Mutation:
                return(new SerialExecutionWithAuthorizationStrategy());

            case OperationType.Subscription:
                return(new SubscriptionExecutionStrategy());

            default:
                throw new InvalidOperationException($"Unexpected OperationType {context.Operation.OperationType}");
            }
        }
예제 #8
0
        protected virtual IExecutionStrategy SelectExecutionStrategy(ExecutionContext context)
        {
            // TODO: Should we use cached instances of the default execution strategies?
            switch (context.Operation.OperationType)
            {
            case OperationType.Query:
                return(new ParallelExecutionStrategy());

            case OperationType.Mutation:
                return(new SerialExecutionStrategy());

            case OperationType.Subscription:
                return(new SubscriptionExecutionStrategy());

            default:
                throw new InvalidOperationException($"Unexpected OperationType {context.Operation.OperationType}");
            }
        }
        /// <summary>
        ///     Resolve simple fields in a performant manor
        /// </summary>
        private static async Task <object> ResolveFieldFromDataAsync(ExecutionContext context, IObjectGraphType rootType, object source,
                                                                     FieldType fieldType, Field field, IEnumerable <string> path)
        {
            object result = null;

            try
            {
                if (fieldType.Resolver != null)
                {
                    var rfc = new ResolveFieldContext(context, field, fieldType, source, rootType, null, path);

                    result = fieldType.Resolver.Resolve(rfc);

                    result = await UnwrapResultAsync(result)
                             .ConfigureAwait(false);
                }
                else
                {
                    result = NameFieldResolver.Resolve(source, field.Name);
                }

                if (result != null)
                {
                    var scalarType = fieldType.ResolvedType as ScalarGraphType;

                    result = scalarType?.Serialize(result);
                }
            }
            catch (Exception exc)
            {
                var error = new ExecutionError($"Error trying to resolve {field.Name}.", exc);
                error.AddLocation(field, context.Document);
                error.Path = path.ToList();
                context.Errors.Add(error);

                // If there was an exception, the value of result cannot be trusted
                result = null;
            }

            return(result);
        }
        /// <summary>
        ///     Resolve lists in a performant manor
        /// </summary>
        private async Task <List <object> > ResolveListFromData(ExecutionContext context, object source, IObjectGraphType parentType,
                                                                IGraphType graphType, Field field, IEnumerable <string> path)
        {
            var result           = new List <object>();
            var listInfo         = graphType as ListGraphType;
            var subType          = listInfo?.ResolvedType as IObjectGraphType;
            var data             = source as IEnumerable;
            var visitedFragments = new List <string>();
            var subFields        = CollectFields(context, subType, field.SelectionSet, null, visitedFragments);

            if (data == null)
            {
                var error = new ExecutionError("User error: expected an IEnumerable list though did not find one.");
                error.AddLocation(field, context.Document);
                throw error;
            }

            var index = 0;

            foreach (var node in data)
            {
                var currentPath = path.Concat(new[] { $"{index++}" });

                if (subType != null)
                {
                    var nodeResult = await ExecuteFieldsAsync(context, subType, node, subFields, currentPath)
                                     .ConfigureAwait(false);

                    result.Add(nodeResult);
                }
                else
                {
                    var nodeResult = await CompleteValueAsync(context, parentType, listInfo?.ResolvedType, field, node, currentPath)
                                     .ConfigureAwait(false);

                    result.Add(nodeResult);
                }
            }

            return(result);
        }
예제 #11
0
        public bool ShouldIncludeNode(ExecutionContext context, Directives directives)
        {
            if (directives != null)
            {
                var directive = directives.Find(DirectiveGraphType.Skip.Name);
                if (directive != null)
                {
                    var values = GetArgumentValues(
                        context.Schema,
                        DirectiveGraphType.Skip.Arguments,
                        directive.Arguments,
                        context.Variables);

                    object ifObj;
                    values.TryGetValue("if", out ifObj);

                    bool ifVal;
                    return(!(bool.TryParse(ifObj?.ToString() ?? string.Empty, out ifVal) && ifVal));
                }

                directive = directives.Find(DirectiveGraphType.Include.Name);
                if (directive != null)
                {
                    var values = GetArgumentValues(
                        context.Schema,
                        DirectiveGraphType.Include.Arguments,
                        directive.Arguments,
                        context.Variables);

                    object ifObj;
                    values.TryGetValue("if", out ifObj);

                    bool ifVal;
                    return(bool.TryParse(ifObj?.ToString() ?? string.Empty, out ifVal) && ifVal);
                }
            }

            return(true);
        }
예제 #12
0
        public bool DoesFragmentConditionMatch(ExecutionContext context, IHaveFragmentType fragment, GraphType type)
        {
            var conditionalType = context.Schema.FindType(fragment.Type);

            if (conditionalType == type)
            {
                return(true);
            }

            if (conditionalType is InterfaceGraphType)
            {
                var interfaceType = (InterfaceGraphType)conditionalType;
                var hasInterfaces = type as IImplementInterfaces;
                if (hasInterfaces != null)
                {
                    var interfaces = context.Schema.FindTypes(hasInterfaces.Interfaces);
                    return(interfaceType.IsPossibleType(interfaces));
                }
            }

            return(false);
        }
예제 #13
0
        private ExecutionContext BuildExecutionContext(
            ISchema schema,
            object root,
            Document document,
            Operation operation,
            Inputs inputs,
            IDictionary <string, object> userContext,
            CancellationToken cancellationToken,
            Metrics metrics,
            List <IDocumentExecutionListener> listeners,
            bool throwOnUnhandledException,
            Action <UnhandledExceptionContext> unhandledExceptionDelegate,
            int?maxParallelExecutionCount,
            IServiceProvider requestServices)
        {
            var context = new ExecutionContext
            {
                Document    = document,
                Schema      = schema,
                RootValue   = root,
                UserContext = userContext,

                Operation         = operation,
                Variables         = inputs == null ? null : GetVariableValues(document, schema, operation?.Variables, inputs),
                Fragments         = document.Fragments,
                Errors            = new ExecutionErrors(),
                Extensions        = new Dictionary <string, object>(),
                CancellationToken = cancellationToken,

                Metrics   = metrics,
                Listeners = listeners,
                ThrowOnUnhandledException  = throwOnUnhandledException,
                UnhandledExceptionDelegate = unhandledExceptionDelegate,
                MaxParallelExecutionCount  = maxParallelExecutionCount,
                RequestServices            = requestServices
            };

            return(context);
        }
        private async Task ExtractFieldAsync(ExecutionContext context, IObjectGraphType rootType, object source,
                                             Field field, FieldType fieldType, ConcurrentDictionary <string, object> data, IEnumerable <string> path)
        {
            context.CancellationToken.ThrowIfCancellationRequested();

            var name = field.Alias ?? field.Name;

            if (data.ContainsKey(name))
            {
                return;
            }

            if (!ShouldIncludeNode(context, field.Directives))
            {
                return;
            }

            if (CanResolveFromData(field, fieldType))
            {
                var result = await ResolveFieldFromDataAsync(context, rootType, source, fieldType, field, path)
                             .ConfigureAwait(false);

                data.TryAdd(name, result);
            }
            else
            {
                var result = await ResolveFieldAsync(context, rootType, source, field, path)
                             .ConfigureAwait(false);

                if (result.Skip)
                {
                    return;
                }

                data.TryAdd(name, result.Value);
            }
        }
예제 #15
0
        public async Task <object> CompleteValueAsync(ExecutionContext context, IGraphType fieldType, Fields fields, object result)
        {
            var field = fields != null?fields.FirstOrDefault() : null;

            var fieldName = field != null ? field.Name : null;

            var nonNullType = fieldType as NonNullGraphType;

            if (nonNullType != null)
            {
                var type      = nonNullType.ResolvedType;
                var completed = await CompleteValueAsync(context, type, fields, result).ConfigureAwait(false);

                if (completed == null)
                {
                    var error = new ExecutionError("Cannot return null for non-null type. Field: {0}, Type: {1}!."
                                                   .ToFormat(fieldName, type.Name));
                    error.AddLocation(field, context.Document);
                    throw error;
                }

                return(completed);
            }

            if (result == null)
            {
                return(null);
            }

            if (fieldType is ScalarGraphType)
            {
                var scalarType   = fieldType as ScalarGraphType;
                var coercedValue = scalarType.Serialize(result);
                return(coercedValue);
            }

            if (fieldType is ListGraphType)
            {
                var list = result as IEnumerable;

                if (list == null)
                {
                    var error = new ExecutionError("User error: expected an IEnumerable list though did not find one.");
                    error.AddLocation(field, context.Document);
                    throw error;
                }

                var listType = fieldType as ListGraphType;
                var itemType = listType.ResolvedType;

                var results = await list.MapAsync(async item => await CompleteValueAsync(context, itemType, fields, item).ConfigureAwait(false)).ConfigureAwait(false);

                return(results);
            }

            var objectType = fieldType as IObjectGraphType;

            if (fieldType is IAbstractGraphType)
            {
                var abstractType = fieldType as IAbstractGraphType;
                objectType = abstractType.GetObjectType(result);

                if (objectType != null && !abstractType.IsPossibleType(objectType))
                {
                    var error = new ExecutionError(
                        "Runtime Object type \"{0}\" is not a possible type for \"{1}\""
                        .ToFormat(objectType, abstractType));
                    error.AddLocation(field, context.Document);
                    throw error;
                }
            }

            if (objectType == null)
            {
                return(null);
            }

            if (objectType.IsTypeOf != null && !objectType.IsTypeOf(result))
            {
                var error = new ExecutionError(
                    "Expected value of type \"{0}\" but got: {1}."
                    .ToFormat(objectType, result));
                error.AddLocation(field, context.Document);
                throw error;
            }

            var subFields        = new Dictionary <string, Fields>();
            var visitedFragments = new List <string>();

            fields.Apply(f =>
            {
                subFields = CollectFields(context, objectType, f.SelectionSet, subFields, visitedFragments);
            });

            return(await ExecuteFieldsAsync(context, objectType, result, subFields).ConfigureAwait(false));
        }
예제 #16
0
 public async Task <object> ExecuteFields(ExecutionContext context, ObjectGraphType rootType, object source, Dictionary <string, Fields> fields)
 {
     return(await fields.ToDictionaryAsync(
                pair => pair.Key,
                pair => ResolveField(context, rootType, source, pair.Value)));
 }
예제 #17
0
        public bool DoesFragmentConditionMatch(ExecutionContext context, IHaveFragmentType fragment, GraphType type)
        {
            var conditionalType = context.Schema.FindType(fragment.Type);
            if (conditionalType == type)
            {
                return true;
            }

            if (conditionalType is InterfaceGraphType)
            {
                return ((InterfaceGraphType)conditionalType).IsPossibleType(type as IImplementInterfaces);
            }

            return false;
        }
예제 #18
0
 /// <summary>
 /// Processes data from the source stream via <see cref="IObserver{T}.OnNext(T)"/> and
 /// returns an <see cref="ExecutionResult"/>.
 /// <br/><br/>
 /// Executes with a scoped service provider in <see cref="ExecutionContext.RequestServices"/>
 /// which is disposed once this method completes.
 /// </summary>
 protected override async ValueTask <ExecutionResult> ProcessDataAsync(ExecutionContext context, ExecutionNode node, object?value)
 {
     using var scope         = _serviceScopeFactory.CreateScope();
     context.RequestServices = scope.ServiceProvider;
     return(await base.ProcessDataAsync(context, node, value).ConfigureAwait(false));
 }
 private ResolveFieldResult<object> GenerateError(ResolveFieldResult<object> resolveResult, Field field, ExecutionContext context, Exception exc)
 {
     var error = new ExecutionError("Error trying to resolve {0}.".ToFormat(field.Name), exc);
     error.AddLocation(field, context.Document);
     context.Errors.Add(error);
     resolveResult.Skip = false;
     return resolveResult;
 }
예제 #20
0
        public async Task <ResolveFieldResult <object> > ResolveFieldAsync(ExecutionContext context, IObjectGraphType parentType, object source, Field field, IEnumerable <string> path)
        {
            context.CancellationToken.ThrowIfCancellationRequested();

            var fieldPath = path?.ToList() ?? new List <string>();

            var resolveResult = new ResolveFieldResult <object>
            {
                Skip = false
            };

            var fieldDefinition = GetFieldDefinition(context.Document, context.Schema, parentType, field);

            if (fieldDefinition == null)
            {
                resolveResult.Skip = true;
                return(resolveResult);
            }

            var arguments = GetArgumentValues(context.Schema, fieldDefinition.Arguments, field.Arguments, context.Variables);

            try
            {
                var resolveContext = new ResolveFieldContext();
                resolveContext.FieldName         = field.Name;
                resolveContext.FieldAst          = field;
                resolveContext.FieldDefinition   = fieldDefinition;
                resolveContext.ReturnType        = fieldDefinition.ResolvedType;
                resolveContext.ParentType        = parentType;
                resolveContext.Arguments         = arguments;
                resolveContext.Source            = source;
                resolveContext.Schema            = context.Schema;
                resolveContext.Document          = context.Document;
                resolveContext.Fragments         = context.Fragments;
                resolveContext.RootValue         = context.RootValue;
                resolveContext.UserContext       = context.UserContext;
                resolveContext.Operation         = context.Operation;
                resolveContext.Variables         = context.Variables;
                resolveContext.CancellationToken = context.CancellationToken;
                resolveContext.Metrics           = context.Metrics;
                resolveContext.Errors            = context.Errors;
                resolveContext.Path = fieldPath;

                var subFields = SubFieldsFor(context, fieldDefinition.ResolvedType, field);
                resolveContext.SubFields = subFields;

                var resolver = fieldDefinition.Resolver ?? new NameFieldResolver();
                var result   = resolver.Resolve(resolveContext);

                if (result is Task)
                {
                    var task = result as Task;
                    if (task.IsFaulted)
                    {
                        var aggregateException = task.Exception;
                        var exception          = aggregateException.InnerExceptions.Count == 1
                            ? aggregateException.InnerException
                            : aggregateException;
                        return(GenerateError(resolveResult, field, context, exception, fieldPath));
                    }
                    await task.ConfigureAwait(false);

                    result = task.GetProperyValue("Result");
                }

                resolveResult.Value =
                    await CompleteValueAsync(context, parentType, fieldDefinition.ResolvedType, field, result, fieldPath).ConfigureAwait(false);

                return(resolveResult);
            }
            catch (Exception exc)
            {
                return(GenerateError(resolveResult, field, context, exc, path));
            }
        }
예제 #21
0
 public async Task<object> ExecuteFields(ExecutionContext context, ObjectGraphType rootType, object source, Dictionary<string, Fields> fields)
 {
     return await fields.ToDictionaryAsync(
         pair => pair.Key,
         pair => ResolveField(context, rootType, source, pair.Value));
 }
 /// <summary>
 /// Returns an instance of an <see cref="IExecutionStrategy"/> given specified execution parameters.
 /// <br/><br/>
 /// Typically the strategy is selected based on the type of operation.
 /// <br/><br/>
 /// By default, the selection is handled by the <see cref="IExecutionStrategySelector"/> implementation passed to the
 /// constructor, which will select an execution strategy based on a set of <see cref="ExecutionStrategyRegistration"/>
 /// instances passed to it.
 /// <br/><br/>
 /// For the <see cref="DefaultExecutionStrategySelector"/> without any registrations,
 /// query operations will return a <see cref="ParallelExecutionStrategy"/> while mutation operations return a
 /// <see cref="SerialExecutionStrategy"/>. Subscription operations return a <see cref="SubscriptionExecutionStrategy"/>.
 /// </summary>
 protected virtual IExecutionStrategy SelectExecutionStrategy(ExecutionContext context)
 => _executionStrategySelector.Select(context);
예제 #23
0
 public Task<Dictionary<string, object>> ExecuteFieldsAsync(ExecutionContext context, IObjectGraphType rootType, object source, Dictionary<string, Fields> fields)
 {
     return fields.ToDictionaryAsync<KeyValuePair<string, Fields>, string, ResolveFieldResult<object>, object>(
         pair => pair.Key,
         pair => ResolveFieldAsync(context, rootType, source, pair.Value));
 }
예제 #24
0
        public async Task <ExecutionResult> ExecuteAsync(ExecutionOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (options.Schema == null)
            {
                throw new InvalidOperationException("Cannot execute request if no schema is specified");
            }
            if (options.Query == null)
            {
                throw new InvalidOperationException("Cannot execute request if no query is specified");
            }
            if (options.FieldMiddleware == null)
            {
                throw new InvalidOperationException("Cannot execute request if no middleware builder specified");
            }

            var metrics = new Metrics(options.EnableMetrics).Start(options.OperationName);

            options.Schema.NameConverter = options.NameConverter;
            options.Schema.Filter        = options.SchemaFilter;

            ExecutionResult  result  = null;
            ExecutionContext context = null;

            try
            {
                if (!options.Schema.Initialized)
                {
                    using (metrics.Subject("schema", "Initializing schema"))
                    {
                        options.FieldMiddleware.ApplyTo(options.Schema);
                        options.Schema.Initialize();
                    }
                }

                var document = options.Document;
                using (metrics.Subject("document", "Building document"))
                {
                    if (document == null)
                    {
                        document = _documentBuilder.Build(options.Query);
                    }
                }

                if (document.Operations.Count == 0)
                {
                    throw new NoOperationError();
                }

                var operation = GetOperation(options.OperationName, document);
                metrics.SetOperationName(operation?.Name);

                if (operation == null)
                {
                    throw new InvalidOperationException($"Query does not contain operation '{options.OperationName}'.");
                }

                IValidationResult validationResult;
                using (metrics.Subject("document", "Validating document"))
                {
                    validationResult = await _documentValidator.ValidateAsync(
                        options.Query,
                        options.Schema,
                        document,
                        options.ValidationRules,
                        options.UserContext,
                        options.Inputs);
                }

                if (options.ComplexityConfiguration != null && validationResult.IsValid)
                {
                    using (metrics.Subject("document", "Analyzing complexity"))
                        _complexityAnalyzer.Validate(document, options.ComplexityConfiguration);
                }

                context = BuildExecutionContext(
                    options.Schema,
                    options.Root,
                    document,
                    operation,
                    options.Inputs,
                    options.UserContext,
                    options.CancellationToken,
                    metrics,
                    options.Listeners,
                    options.ThrowOnUnhandledException,
                    options.UnhandledExceptionDelegate,
                    options.MaxParallelExecutionCount,
                    options.RequestServices);

                foreach (var listener in options.Listeners)
                {
                    await listener.AfterValidationAsync(context, validationResult)
                    .ConfigureAwait(false);
                }

                if (!validationResult.IsValid)
                {
                    return(new ExecutionResult
                    {
                        Errors = validationResult.Errors,
                        Perf = metrics.Finish()
                    });
                }

                if (context.Errors.Count > 0)
                {
                    return(new ExecutionResult
                    {
                        Errors = context.Errors,
                        Perf = metrics.Finish()
                    });
                }

                using (metrics.Subject("execution", "Executing operation"))
                {
                    if (context.Listeners != null)
                    {
                        foreach (var listener in context.Listeners)
                        {
                            await listener.BeforeExecutionAsync(context)
                            .ConfigureAwait(false);
                        }
                    }

                    IExecutionStrategy executionStrategy = SelectExecutionStrategy(context);

                    if (executionStrategy == null)
                    {
                        throw new InvalidOperationException("Invalid ExecutionStrategy!");
                    }

                    var task = executionStrategy.ExecuteAsync(context)
                               .ConfigureAwait(false);

                    if (context.Listeners != null)
                    {
                        foreach (var listener in context.Listeners)
                        {
                            await listener.BeforeExecutionAwaitedAsync(context)
                            .ConfigureAwait(false);
                        }
                    }

                    result = await task;

                    if (context.Listeners != null)
                    {
                        foreach (var listener in context.Listeners)
                        {
                            await listener.AfterExecutionAsync(context)
                            .ConfigureAwait(false);
                        }
                    }
                }

                if (context.Errors.Count > 0)
                {
                    result.Errors = context.Errors;
                }
            }
            catch (OperationCanceledException) when(options.CancellationToken.IsCancellationRequested)
            {
                throw;
            }
            catch (ExecutionError ex)
            {
                result = new ExecutionResult
                {
                    Errors = new ExecutionErrors
                    {
                        ex
                    }
                };
            }
            catch (Exception ex)
            {
                if (options.ThrowOnUnhandledException)
                {
                    throw;
                }

                UnhandledExceptionContext exceptionContext = null;
                if (options.UnhandledExceptionDelegate != null)
                {
                    exceptionContext = new UnhandledExceptionContext(context, null, ex);
                    options.UnhandledExceptionDelegate(exceptionContext);
                    ex = exceptionContext.Exception;
                }

                result = new ExecutionResult
                {
                    Errors = new ExecutionErrors
                    {
                        ex is ExecutionError executionError ? executionError : new UnhandledError(exceptionContext?.ErrorMessage ?? "Error executing document.", ex)
                    }
                };
            }
            finally
            {
                result ??= new ExecutionResult();
                result.Perf = metrics.Finish();
            }

            return(result);
        }
예제 #25
0
        public Task<Dictionary<string, object>> ExecuteOperationAsync(ExecutionContext context)
        {
            var rootType = GetOperationRootType(context.Document, context.Schema, context.Operation);
            var fields = CollectFields(
                context,
                rootType,
                context.Operation.SelectionSet,
                new Dictionary<string, Fields>(),
                new List<string>());

            return ExecuteFieldsAsync(context, rootType, context.RootValue, fields);
        }
예제 #26
0
        public ExecutionContext BuildExecutionContext(
            ISchema schema,
            object root,
            Document document,
            Operation operation,
            Inputs inputs,
            object userContext,
            CancellationToken cancellationToken,
            Metrics metrics)
        {
            var context = new ExecutionContext();
            context.Document = document;
            context.Schema = schema;
            context.RootValue = root;
            context.UserContext = userContext;

            context.Operation = operation;
            context.Variables = GetVariableValues(document, schema, operation.Variables, inputs);
            context.Fragments = document.Fragments;
            context.CancellationToken = cancellationToken;

            context.Metrics = metrics;

            return context;
        }
예제 #27
0
 /// <summary>
 /// Encapsulates an error within an <see cref="ExecutionResult"/> for errors generated
 /// by the event stream via <see cref="IObserver{T}.OnError(Exception)"/>.
 /// <br/><br/>
 /// Executes with a scoped service provider in <see cref="ExecutionContext.RequestServices"/>
 /// which is disposed once this method completes.
 /// </summary>
 protected override Task <ExecutionError> ProcessErrorAsync(ExecutionContext context, ExecutionNode node, Exception exception)
 {
     using var scope         = _serviceScopeFactory.CreateScope();
     context.RequestServices = scope.ServiceProvider;
     return(base.ProcessErrorAsync(context, node, exception));
 }
예제 #28
0
        public async Task <object> CompleteValue(ExecutionContext context, GraphType fieldType, Fields fields, object result)
        {
            if (fieldType is NonNullGraphType)
            {
                var nonNullType = fieldType as NonNullGraphType;
                var completed   = await CompleteValue(context, context.Schema.FindType(nonNullType.Type), fields, result);

                if (completed == null)
                {
                    throw new ExecutionError("Cannot return null for non-null type. Field: {0}".ToFormat(nonNullType.Name));
                }

                return(completed);
            }

            if (result == null)
            {
                return(null);
            }

            if (fieldType is ScalarGraphType)
            {
                var scalarType   = fieldType as ScalarGraphType;
                var coercedValue = scalarType.Coerce(result);
                return(coercedValue);
            }

            if (fieldType is ListGraphType)
            {
                var list = result as IEnumerable;

                if (list == null)
                {
                    throw new ExecutionError("User error: expected an IEnumerable list though did not find one.");
                }

                var listType = fieldType as ListGraphType;
                var itemType = context.Schema.FindType(listType.Type);

                var results = await list.MapAsync(async item =>
                {
                    return(await CompleteValue(context, itemType, fields, item));
                });

                return(results);
            }

            var objectType = fieldType as ObjectGraphType;

            if (fieldType is InterfaceGraphType)
            {
                var interfaceType = fieldType as InterfaceGraphType;
                objectType = interfaceType.ResolveType(result);
            }

            if (objectType == null)
            {
                return(null);
            }

            var subFields = new Dictionary <string, Fields>();

            fields.Apply(field =>
            {
                subFields = CollectFields(context, objectType, field.Selections, subFields);
            });

            return(await ExecuteFields(context, objectType, result, subFields));
        }
예제 #29
0
        public async Task<object> CompleteValue(ExecutionContext context, GraphType fieldType, Fields fields, object result)
        {
            var nonNullType = fieldType as NonNullGraphType;
            if (nonNullType != null)
            {
                var completed = await CompleteValue(context, context.Schema.FindType(nonNullType.Type), fields, result);
                if (completed == null)
                {
                    throw new ExecutionError("Cannot return null for non-null type. Field: {0}".ToFormat(nonNullType.Name));
                }

                return completed;
            }

            if (result == null)
            {
                return null;
            }

            if (fieldType is ScalarGraphType)
            {
                var scalarType = fieldType as ScalarGraphType;
                var coercedValue = scalarType.Coerce(result);
                return coercedValue;
            }

            if (fieldType is ListGraphType)
            {
                var list = result as IEnumerable;

                if (list == null)
                {
                    throw new ExecutionError("User error: expected an IEnumerable list though did not find one.");
                }

                var listType = fieldType as ListGraphType;
                var itemType = context.Schema.FindType(listType.Type);

                var results = await list.MapAsync(async item =>
                {
                    return await CompleteValue(context, itemType, fields, item);
                });

                return results;
            }

            var objectType = fieldType as ObjectGraphType;

            if (fieldType is InterfaceGraphType)
            {
                var interfaceType = fieldType as InterfaceGraphType;
                objectType = interfaceType.ResolveType(result);
            }

            if (objectType == null)
            {
                return null;
            }

            var subFields = new Dictionary<string, Fields>();

            fields.Apply(field =>
            {
                subFields = CollectFields(context, objectType, field.Selections, subFields);
            });

            return await ExecuteFields(context, objectType, result, subFields);
        }
        public async Task <ResolveFieldResult <object> > ResolveFieldAsync(ExecutionContext context, IObjectGraphType parentType, object source, Field field, IEnumerable <string> path)
        {
            context.CancellationToken.ThrowIfCancellationRequested();

            var fieldPath = path?.ToList() ?? new List <string>();

            var resolveResult = new ResolveFieldResult <object>
            {
                Skip = false
            };

            var fieldDefinition = GetFieldDefinition(context.Document, context.Schema, parentType, field);

            if (fieldDefinition == null)
            {
                resolveResult.Skip = true;
                return(resolveResult);
            }

            var arguments = GetArgumentValues(context.Schema, fieldDefinition.Arguments, field.Arguments, context.Variables);

            try
            {
                var resolveContext = new ResolveFieldContext
                {
                    FieldName         = field.Name,
                    FieldAst          = field,
                    FieldDefinition   = fieldDefinition,
                    ReturnType        = fieldDefinition.ResolvedType,
                    ParentType        = parentType,
                    Arguments         = arguments,
                    Source            = source,
                    Schema            = context.Schema,
                    Document          = context.Document,
                    Fragments         = context.Fragments,
                    RootValue         = context.RootValue,
                    UserContext       = context.UserContext,
                    Operation         = context.Operation,
                    Variables         = context.Variables,
                    CancellationToken = context.CancellationToken,
                    Metrics           = context.Metrics,
                    Errors            = context.Errors,
                    Path = fieldPath
                };

                var subFields = SubFieldsFor(context, fieldDefinition.ResolvedType, field);
                resolveContext.SubFields = subFields;

                var resolver = fieldDefinition.Resolver ?? new NameFieldResolver();
                var result   = resolver.Resolve(resolveContext);

                result = await UnwrapResultAsync(result)
                         .ConfigureAwait(false);

                resolveResult.Value = await CompleteValueAsync(context, parentType, fieldDefinition.ResolvedType, field, result, fieldPath)
                                      .ConfigureAwait(false);

                return(resolveResult);
            }
            catch (Exception exc)
            {
                return(GenerateError(resolveResult, field, context, exc, path));
            }
        }
예제 #31
0
        public bool ShouldIncludeNode(ExecutionContext context, Directives directives)
        {
            if (directives != null)
            {
                var directive = directives.Find(DirectiveGraphType.Skip.Name);
                if (directive != null)
                {
                    var values = GetArgumentValues(
                        context.Schema,
                        DirectiveGraphType.Skip.Arguments,
                        directive.Arguments,
                        context.Variables);
                    return !((bool) values["if"]);
                }

                directive = directives.Find(DirectiveGraphType.Include.Name);
                if (directive != null)
                {
                    var values = GetArgumentValues(
                        context.Schema,
                        DirectiveGraphType.Include.Arguments,
                        directive.Arguments,
                        context.Variables);
                    return (bool) values["if"];
                }
            }

            return true;
        }
        public object ExecuteFields(ExecutionContext context, ObjectGraphType rootType, object source, Dictionary<string, Fields> fields)
        {
            var result = new Dictionary<string, object>();

            fields.Apply(pair =>
            {
                result[pair.Key] = ResolveField(context, rootType, source, pair.Value);
            });

            return result;
        }
예제 #33
0
        public async Task <ResolveFieldResult <object> > ResolveField(ExecutionContext context, ObjectGraphType parentType, object source, Fields fields)
        {
            context.CancellationToken.ThrowIfCancellationRequested();

            var resolveResult = new ResolveFieldResult <object>
            {
                Skip = false
            };

            var field = fields.First();

            var fieldDefinition = GetFieldDefinition(context.Schema, parentType, field);

            if (fieldDefinition == null)
            {
                resolveResult.Skip = true;
                return(resolveResult);
            }

            var arguments = GetArgumentValues(context.Schema, fieldDefinition.Arguments, field.Arguments, context.Variables);

            Func <ResolveFieldContext, object> defaultResolve = (ctx) =>
            {
                return(ctx.Source != null?GetProperyValue(ctx.Source, ctx.FieldAst.Name) : null);
            };

            try
            {
                var resolveContext = new ResolveFieldContext();
                resolveContext.FieldName         = field.Name;
                resolveContext.FieldAst          = field;
                resolveContext.FieldDefinition   = fieldDefinition;
                resolveContext.ReturnType        = context.Schema.FindType(fieldDefinition.Type);
                resolveContext.ParentType        = parentType;
                resolveContext.Arguments         = arguments;
                resolveContext.Source            = source;
                resolveContext.Schema            = context.Schema;
                resolveContext.Fragments         = context.Fragments;
                resolveContext.RootValue         = context.RootValue;
                resolveContext.Operation         = context.Operation;
                resolveContext.Variables         = context.Variables;
                resolveContext.CancellationToken = context.CancellationToken;
                var resolve = fieldDefinition.Resolve ?? defaultResolve;
                var result  = resolve(resolveContext);

                if (result is Task)
                {
                    var   task = result as Task;
                    await task;

                    result = GetProperyValue(task, "Result");
                }

                if (parentType is __Field && result is Type)
                {
                    result = context.Schema.FindType(result as Type);
                }

                resolveResult.Value = await CompleteValue(context, context.Schema.FindType(fieldDefinition.Type), fields, result);

                return(resolveResult);
            }
            catch (Exception exc)
            {
                context.Errors.Add(new ExecutionError("Error trying to resolve {0}.".ToFormat(field.Name), exc));
                resolveResult.Skip = false;
                return(resolveResult);
            }
        }
예제 #34
0
 public Task <Dictionary <string, object> > ExecuteFieldsAsync(ExecutionContext context, IObjectGraphType rootType, object source, Dictionary <string, Field> fields, IEnumerable <string> path)
 {
     return(fields.ToDictionaryAsync <KeyValuePair <string, Field>, string, ResolveFieldResult <object>, object>(
                pair => pair.Key,
                pair => ResolveFieldAsync(context, rootType, source, pair.Value, path.Concat(new[] { pair.Key }))));
 }
예제 #35
0
        public Dictionary <string, Field> CollectFields(
            ExecutionContext context,
            IGraphType specificType,
            SelectionSet selectionSet,
            Dictionary <string, Field> fields,
            List <string> visitedFragmentNames)
        {
            if (fields == null)
            {
                fields = new Dictionary <string, Field>();
            }

            selectionSet?.Selections.Apply(selection =>
            {
                if (selection is Field)
                {
                    var field = (Field)selection;
                    if (!ShouldIncludeNode(context, field.Directives))
                    {
                        return;
                    }

                    var name     = field.Alias ?? field.Name;
                    fields[name] = field;
                }
                else if (selection is FragmentSpread)
                {
                    var spread = (FragmentSpread)selection;

                    if (visitedFragmentNames.Contains(spread.Name) ||
                        !ShouldIncludeNode(context, spread.Directives))
                    {
                        return;
                    }

                    visitedFragmentNames.Add(spread.Name);

                    var fragment = context.Fragments.FindDefinition(spread.Name);
                    if (fragment == null ||
                        !ShouldIncludeNode(context, fragment.Directives) ||
                        !DoesFragmentConditionMatch(context, fragment.Type.Name, specificType))
                    {
                        return;
                    }

                    CollectFields(context, specificType, fragment.SelectionSet, fields, visitedFragmentNames);
                }
                else if (selection is InlineFragment)
                {
                    var inline = (InlineFragment)selection;

                    var name = inline.Type != null ? inline.Type.Name : specificType.Name;

                    if (!ShouldIncludeNode(context, inline.Directives) ||
                        !DoesFragmentConditionMatch(context, name, specificType))
                    {
                        return;
                    }

                    CollectFields(context, specificType, inline.SelectionSet, fields, visitedFragmentNames);
                }
            });

            return(fields);
        }
예제 #36
0
        public object ResolveField(ExecutionContext context, ObjectGraphType parentType, object source, Fields fields)
        {
            var field = fields.First();

            var fieldDefinition = GetFieldDefinition(context.Schema, parentType, field);
            if (fieldDefinition == null)
            {
                return null;
            }

            var arguments = GetArgumentValues(fieldDefinition.Arguments, field.Arguments, context.Variables);

            Func<ResolveFieldContext, object> defaultResolve = (ctx) =>
            {
                return ctx.Source != null ? GetProperyValue(ctx.Source, ctx.FieldAst.Name) : null;
            };

            try
            {
                var resolveContext = new ResolveFieldContext();
                resolveContext.FieldAst = field;
                resolveContext.FieldDefinition = fieldDefinition;
                resolveContext.Schema = context.Schema;
                resolveContext.ParentType = parentType;
                resolveContext.Arguments = arguments;
                resolveContext.Source = source;
                var resolve = fieldDefinition.Resolve ?? defaultResolve;
                var result = resolve(resolveContext);
                return CompleteValue(context, fieldDefinition.Type, fields, result);
            }
            catch (Exception exc)
            {
                context.Errors.Add(new ExecutionError("Error trying to resolve {0}.".ToFormat(field.Name), exc));
                return null;
            }
        }
예제 #37
0
 public override Task <ExecutionResult> ExecuteAsync(GraphQL.Execution.ExecutionContext context)
 {
     Executed.ShouldBeFalse();
     Executed = true;
     return(base.ExecuteAsync(context));
 }
예제 #38
0
        public async Task <object> CompleteValueAsync(ExecutionContext context, IObjectGraphType parentType, IGraphType fieldType, Field field, object result, IEnumerable <string> path)
        {
            var fieldName = field?.Name;

            var nonNullType = fieldType as NonNullGraphType;

            if (nonNullType != null)
            {
                var type      = nonNullType.ResolvedType;
                var completed = await CompleteValueAsync(context, parentType, type, field, result, path).ConfigureAwait(false);

                if (completed == null)
                {
                    var error = new ExecutionError("Cannot return null for non-null type. Field: {0}, Type: {1}!."
                                                   .ToFormat(fieldName, type.Name));
                    error.AddLocation(field, context.Document);
                    throw error;
                }

                return(completed);
            }

            if (result == null)
            {
                return(null);
            }

            if (fieldType is ScalarGraphType)
            {
                var scalarType   = fieldType as ScalarGraphType;
                var coercedValue = scalarType.Serialize(result);
                return(coercedValue);
            }

            if (fieldType is ListGraphType)
            {
                var list = result as IEnumerable;

                if (list == null)
                {
                    var error = new ExecutionError("User error: expected an IEnumerable list though did not find one.");
                    error.AddLocation(field, context.Document);
                    throw error;
                }

                var listType = fieldType as ListGraphType;
                var itemType = listType.ResolvedType;

                var results = await list
                              .MapAsync(async (index, item) =>
                                        await CompleteValueAsync(context, parentType, itemType, field, item, path.Concat(new[] { $"{index}" })).ConfigureAwait(false))
                              .ConfigureAwait(false);

                return(results);
            }

            var objectType = fieldType as IObjectGraphType;

            if (fieldType is IAbstractGraphType)
            {
                var abstractType = fieldType as IAbstractGraphType;
                objectType = abstractType.GetObjectType(result);

                if (objectType == null)
                {
                    var error = new ExecutionError(
                        $"Abstract type {abstractType.Name} must resolve to an Object type at " +
                        $"runtime for field {parentType.Name}.{fieldName} " +
                        $"with value {result}, received 'null'.");
                    error.AddLocation(field, context.Document);
                    throw error;
                }

                if (!abstractType.IsPossibleType(objectType))
                {
                    var error = new ExecutionError(
                        "Runtime Object type \"{0}\" is not a possible type for \"{1}\""
                        .ToFormat(objectType, abstractType));
                    error.AddLocation(field, context.Document);
                    throw error;
                }
            }

            if (objectType == null)
            {
                return(null);
            }

            if (objectType.IsTypeOf != null && !objectType.IsTypeOf(result))
            {
                var error = new ExecutionError(
                    "Expected value of type \"{0}\" but got: {1}."
                    .ToFormat(objectType, result));
                error.AddLocation(field, context.Document);
                throw error;
            }

            var subFields        = new Dictionary <string, Field>();
            var visitedFragments = new List <string>();

            subFields = CollectFields(context, objectType, field?.SelectionSet, subFields, visitedFragments);

            return(await ExecuteFieldsAsync(context, objectType, result, subFields, path).ConfigureAwait(false));
        }
예제 #39
0
        public Dictionary <string, Fields> CollectFields(
            ExecutionContext context,
            GraphType specificType,
            Selections selections,
            Dictionary <string, Fields> fields,
            List <string> visitedFragmentNames)
        {
            if (fields == null)
            {
                fields = new Dictionary <string, Fields>();
            }

            selections.Apply(selection =>
            {
                if (selection.Field != null)
                {
                    if (!ShouldIncludeNode(context, selection.Field.Directives))
                    {
                        return;
                    }

                    var name = selection.Field.Alias ?? selection.Field.Name;
                    if (!fields.ContainsKey(name))
                    {
                        fields[name] = new Fields();
                    }
                    fields[name].Add(selection.Field);
                }
                else if (selection.Fragment != null)
                {
                    if (selection.Fragment is FragmentSpread)
                    {
                        var spread = selection.Fragment as FragmentSpread;

                        if (visitedFragmentNames.Contains(spread.Name) ||
                            !ShouldIncludeNode(context, spread.Directives))
                        {
                            return;
                        }

                        visitedFragmentNames.Add(spread.Name);

                        var fragment = context.Fragments.FindDefinition(spread.Name);
                        if (fragment == null ||
                            !ShouldIncludeNode(context, fragment.Directives) ||
                            !DoesFragmentConditionMatch(context, fragment, specificType))
                        {
                            return;
                        }

                        CollectFields(context, specificType, fragment.Selections, fields, visitedFragmentNames);
                    }
                    else if (selection.Fragment is InlineFragment)
                    {
                        var inline = selection.Fragment as InlineFragment;

                        if (!ShouldIncludeNode(context, inline.Directives) ||
                            !DoesFragmentConditionMatch(context, inline, specificType))
                        {
                            return;
                        }

                        CollectFields(context, specificType, inline.Selections, fields, visitedFragmentNames);
                    }
                }
            });

            return(fields);
        }
예제 #40
0
        public async Task<ResolveFieldResult<object>> ResolveFieldAsync(ExecutionContext context, IObjectGraphType parentType, object source, Fields fields)
        {
            context.CancellationToken.ThrowIfCancellationRequested();

            var resolveResult = new ResolveFieldResult<object>
            {
                Skip = false
            };

            var field = fields.First();

            var fieldDefinition = GetFieldDefinition(context.Schema, parentType, field);
            if (fieldDefinition == null)
            {
                resolveResult.Skip = true;
                return resolveResult;
            }

            var arguments = GetArgumentValues(context.Schema, fieldDefinition.Arguments, field.Arguments, context.Variables);

            try
            {
                var resolveContext = new ResolveFieldContext();
                resolveContext.FieldName = field.Name;
                resolveContext.FieldAst = field;
                resolveContext.FieldDefinition = fieldDefinition;
                resolveContext.ReturnType = fieldDefinition.ResolvedType;
                resolveContext.ParentType = parentType;
                resolveContext.Arguments = arguments;
                resolveContext.Source = source;
                resolveContext.Schema = context.Schema;
                resolveContext.Document = context.Document;
                resolveContext.Fragments = context.Fragments;
                resolveContext.RootValue = context.RootValue;
                resolveContext.UserContext = context.UserContext;
                resolveContext.Operation = context.Operation;
                resolveContext.Variables = context.Variables;
                resolveContext.CancellationToken = context.CancellationToken;
                resolveContext.Metrics = context.Metrics;

                var resolver = fieldDefinition.Resolver ?? new NameFieldResolver();
                var result = resolver.Resolve(resolveContext);

                if (result is Task)
                {
                    var task = result as Task;
                    await task.ConfigureAwait(false);

                    result = task.GetProperyValue("Result");
                }

                resolveResult.Value =
                    await CompleteValueAsync(context, fieldDefinition.ResolvedType, fields, result).ConfigureAwait(false);
                return resolveResult;
            }
            catch (Exception exc)
            {
                var error = new ExecutionError("Error trying to resolve {0}.".ToFormat(field.Name), exc);
                error.AddLocation(field, context.Document);
                context.Errors.Add(error);
                resolveResult.Skip = false;
                return resolveResult;
            }
        }
예제 #41
0
 public Task <Dictionary <string, object> > ExecuteFieldsAsync(ExecutionContext context, IObjectGraphType rootType, object source, Dictionary <string, Fields> fields)
 {
     return(fields.ToDictionaryAsync <KeyValuePair <string, Fields>, string, ResolveFieldResult <object>, object>(
                pair => pair.Key,
                pair => ResolveFieldAsync(context, rootType, source, pair.Value)));
 }
예제 #42
0
        public Task<object> ExecuteOperation(ExecutionContext context)
        {
            var rootType = GetOperationRootType(context.Schema, context.Operation);
            var fields = CollectFields(context, rootType, context.Operation.Selections, null);

            return ExecuteFields(context, rootType, context.RootObject, fields);
        }
예제 #43
0
        public async Task<object> CompleteValueAsync(ExecutionContext context, IGraphType fieldType, Fields fields, object result)
        {
            var field = fields != null ? fields.FirstOrDefault() : null;
            var fieldName = field != null ? field.Name : null;

            var nonNullType = fieldType as NonNullGraphType;
            if (nonNullType != null)
            {
                var type = nonNullType.ResolvedType;
                var completed = await CompleteValueAsync(context, type, fields, result).ConfigureAwait(false);
                if (completed == null)
                {
                    var error = new ExecutionError("Cannot return null for non-null type. Field: {0}, Type: {1}!."
                        .ToFormat(fieldName, type.Name));
                    error.AddLocation(field, context.Document);
                    throw error;
                }

                return completed;
            }

            if (result == null)
            {
                return null;
            }

            if (fieldType is ScalarGraphType)
            {
                var scalarType = fieldType as ScalarGraphType;
                var coercedValue = scalarType.Serialize(result);
                return coercedValue;
            }

            if (fieldType is ListGraphType)
            {
                var list = result as IEnumerable;

                if (list == null)
                {
                    var error = new ExecutionError("User error: expected an IEnumerable list though did not find one.");
                    error.AddLocation(field, context.Document);
                    throw error;
                }

                var listType = fieldType as ListGraphType;
                var itemType = listType.ResolvedType;

                var results = await list.MapAsync(async item => await CompleteValueAsync(context, itemType, fields, item).ConfigureAwait(false)).ConfigureAwait(false);

                return results;
            }

            var objectType = fieldType as IObjectGraphType;

            if (fieldType is IAbstractGraphType)
            {
                var abstractType = fieldType as IAbstractGraphType;
                objectType = abstractType.GetObjectType(result);

                if (objectType != null && !abstractType.IsPossibleType(objectType))
                {
                    var error = new ExecutionError(
                        "Runtime Object type \"{0}\" is not a possible type for \"{1}\""
                        .ToFormat(objectType, abstractType));
                    error.AddLocation(field, context.Document);
                    throw error;
                }
            }

            if (objectType == null)
            {
                return null;
            }

            if (objectType.IsTypeOf != null && !objectType.IsTypeOf(result))
            {
                var error = new ExecutionError(
                    "Expected value of type \"{0}\" but got: {1}."
                    .ToFormat(objectType, result));
                error.AddLocation(field, context.Document);
                throw error;
            }

            var subFields = new Dictionary<string, Fields>();
            var visitedFragments = new List<string>();

            fields.Apply(f =>
            {
                subFields = CollectFields(context, objectType, f.SelectionSet, subFields, visitedFragments);
            });

            return await ExecuteFieldsAsync(context, objectType, result, subFields).ConfigureAwait(false);
        }
예제 #44
0
        public async Task<object> ResolveField(ExecutionContext context, ObjectGraphType parentType, object source, Fields fields)
        {
            context.CancellationToken.ThrowIfCancellationRequested();

            var field = fields.First();

            var fieldDefinition = GetFieldDefinition(context.Schema, parentType, field);
            if (fieldDefinition == null)
            {
                return null;
            }

            var arguments = GetArgumentValues(context.Schema, fieldDefinition.Arguments, field.Arguments, context.Variables);

            Func<ResolveFieldContext, object> defaultResolve = (ctx) =>
            {
                return ctx.Source != null ? GetProperyValue(ctx.Source, ctx.FieldAst.Name) : null;
            };

            try
            {
                var resolveContext = new ResolveFieldContext();
                resolveContext.FieldAst = field;
                resolveContext.FieldDefinition = fieldDefinition;
                resolveContext.Schema = context.Schema;
                resolveContext.ParentType = parentType;
                resolveContext.Arguments = arguments;
                resolveContext.Source = source;
                resolveContext.CancellationToken = context.CancellationToken;
                var resolve = fieldDefinition.Resolve ?? defaultResolve;
                var result = resolve(resolveContext);

                if(result is Task)
                {
                    var task = result as Task;
                    await task;

                    result = GetProperyValue(task, "Result");
                }

                if (parentType is __Field && result is Type)
                {
                    result = context.Schema.FindType(result as Type);
                }

                return await CompleteValue(context, context.Schema.FindType(fieldDefinition.Type), fields, result);
            }
            catch (Exception exc)
            {
                context.Errors.Add(new ExecutionError("Error trying to resolve {0}.".ToFormat(field.Name), exc));
                return null;
            }
        }
예제 #45
0
        public Dictionary<string, Fields> CollectFields(
            ExecutionContext context,
            IGraphType specificType,
            SelectionSet selectionSet,
            Dictionary<string, Fields> fields,
            List<string> visitedFragmentNames)
        {
            if (fields == null)
            {
                fields = new Dictionary<string, Fields>();
            }

            selectionSet.Selections.Apply(selection =>
            {
                if (selection is Field)
                {
                    var field = (Field)selection;
                    if (!ShouldIncludeNode(context, field.Directives))
                    {
                        return;
                    }

                    var name = field.Alias ?? field.Name;
                    if (!fields.ContainsKey(name))
                    {
                        fields[name] = new Fields();
                    }
                    fields[name].Add(field);
                }
                else if (selection is FragmentSpread)
                {
                    var spread = (FragmentSpread)selection;

                    if (visitedFragmentNames.Contains(spread.Name)
                        || !ShouldIncludeNode(context, spread.Directives))
                    {
                        return;
                    }

                    visitedFragmentNames.Add(spread.Name);

                    var fragment = context.Fragments.FindDefinition(spread.Name);
                    if (fragment == null
                        || !ShouldIncludeNode(context, fragment.Directives)
                        || !DoesFragmentConditionMatch(context, fragment.Type.Name, specificType))
                    {
                        return;
                    }

                    CollectFields(context, specificType, fragment.SelectionSet, fields, visitedFragmentNames);
                }
                else if (selection is InlineFragment)
                {
                    var inline = (InlineFragment)selection;

                    var name = inline.Type != null ? inline.Type.Name : specificType.Name;

                    if (!ShouldIncludeNode(context, inline.Directives)
                      || !DoesFragmentConditionMatch(context, name, specificType))
                    {
                        return;
                    }

                    CollectFields(context, specificType, inline.SelectionSet, fields, visitedFragmentNames);
                }
            });

            return fields;
        }
예제 #46
0
        public Dictionary<string, Fields> CollectFields(ExecutionContext context, GraphType type, Selections selections, Dictionary<string, Fields> fields)
        {
            if (fields == null)
            {
                fields = new Dictionary<string, Fields>();
            }

            selections.Apply(selection =>
            {
                if (selection.Field != null)
                {
                    if (!ShouldIncludeNode(context, selection.Field.Directives))
                    {
                        return;
                    }

                    var name = selection.Field.Alias ?? selection.Field.Name;
                    if (!fields.ContainsKey(name))
                    {
                        fields[name] = new Fields();
                    }
                    fields[name].Add(selection.Field);
                }
                else if (selection.Fragment != null)
                {
                    if (selection.Fragment is FragmentSpread)
                    {
                        var spread = selection.Fragment as FragmentSpread;

                        if (!ShouldIncludeNode(context, spread.Directives))
                        {
                            return;
                        }

                        var fragment = context.Fragments.FindDefinition(spread.Name);
                        if (!ShouldIncludeNode(context, fragment.Directives)
                            || !DoesFragmentConditionMatch(context, fragment, type))
                        {
                            return;
                        }

                        CollectFields(context, type, fragment.Selections, fields);
                    }
                    else if (selection.Fragment is InlineFragment)
                    {
                        var inline = selection.Fragment as InlineFragment;

                        if (!ShouldIncludeNode(context, inline.Directives)
                          || !DoesFragmentConditionMatch(context, inline, type))
                        {
                            return;
                        }

                        CollectFields(context, type, inline.Selections, fields);
                    }
                }
            });

            return fields;
        }
예제 #47
0
        public bool ShouldIncludeNode(ExecutionContext context, Directives directives)
        {
            if (directives != null)
            {
                var directive = directives.Find(DirectiveGraphType.Skip.Name);
                if (directive != null)
                {
                    var values = GetArgumentValues(
                        context.Schema,
                        DirectiveGraphType.Skip.Arguments,
                        directive.Arguments,
                        context.Variables);

                    object ifObj;
                    values.TryGetValue("if", out ifObj);

                    bool ifVal;
                    return !(bool.TryParse(ifObj?.ToString() ?? string.Empty, out ifVal) && ifVal);
                }

                directive = directives.Find(DirectiveGraphType.Include.Name);
                if (directive != null)
                {
                    var values = GetArgumentValues(
                        context.Schema,
                        DirectiveGraphType.Include.Arguments,
                        directive.Arguments,
                        context.Variables);

                    object ifObj;
                    values.TryGetValue("if", out ifObj);

                    bool ifVal;
                    return bool.TryParse(ifObj?.ToString() ?? string.Empty, out ifVal) && ifVal;
                }
            }

            return true;
        }
예제 #48
0
        public bool DoesFragmentConditionMatch(ExecutionContext context, IHaveFragmentType fragment, GraphType type)
        {
            var conditionalType = context.Schema.FindType(fragment.Type);
            if (conditionalType == type)
            {
                return true;
            }

            if (conditionalType is InterfaceGraphType)
            {
                var interfaceType = (InterfaceGraphType) conditionalType;
                var hasInterfaces = type as IImplementInterfaces;
                if (hasInterfaces != null)
                {
                    var interfaces = context.Schema.FindTypes(hasInterfaces.Interfaces);
                    return interfaceType.IsPossibleType(interfaces);
                }
            }

            return false;
        }
예제 #49
0
        public bool DoesFragmentConditionMatch(ExecutionContext context, string fragmentName, IGraphType type)
        {
            if (string.IsNullOrWhiteSpace(fragmentName))
            {
                return true;
            }

            var conditionalType = context.Schema.FindType(fragmentName);

            if (conditionalType == null)
            {
                return false;
            }

            if (conditionalType.Equals(type))
            {
                return true;
            }

            if (conditionalType is IAbstractGraphType)
            {
                var abstractType = (IAbstractGraphType)conditionalType;
                return abstractType.IsPossibleType(type);
            }

            return false;
        }
예제 #50
0
        public async Task <ResolveFieldResult <object> > ResolveFieldAsync(ExecutionContext context, IObjectGraphType parentType, object source, Fields fields)
        {
            context.CancellationToken.ThrowIfCancellationRequested();

            var resolveResult = new ResolveFieldResult <object>
            {
                Skip = false
            };

            var field = fields.First();

            var fieldDefinition = GetFieldDefinition(context.Schema, parentType, field);

            if (fieldDefinition == null)
            {
                resolveResult.Skip = true;
                return(resolveResult);
            }

            var arguments = GetArgumentValues(context.Schema, fieldDefinition.Arguments, field.Arguments, context.Variables);

            try
            {
                var resolveContext = new ResolveFieldContext();
                resolveContext.FieldName         = field.Name;
                resolveContext.FieldAst          = field;
                resolveContext.FieldDefinition   = fieldDefinition;
                resolveContext.ReturnType        = fieldDefinition.ResolvedType;
                resolveContext.ParentType        = parentType;
                resolveContext.Arguments         = arguments;
                resolveContext.Source            = source;
                resolveContext.Schema            = context.Schema;
                resolveContext.Document          = context.Document;
                resolveContext.Fragments         = context.Fragments;
                resolveContext.RootValue         = context.RootValue;
                resolveContext.UserContext       = context.UserContext;
                resolveContext.Operation         = context.Operation;
                resolveContext.Variables         = context.Variables;
                resolveContext.CancellationToken = context.CancellationToken;
                resolveContext.Metrics           = context.Metrics;

                var resolver = fieldDefinition.Resolver ?? new NameFieldResolver();
                var result   = resolver.Resolve(resolveContext);

                if (result is Task)
                {
                    var task = result as Task;
                    await task.ConfigureAwait(false);

                    result = task.GetProperyValue("Result");
                }

                resolveResult.Value =
                    await CompleteValueAsync(context, fieldDefinition.ResolvedType, fields, result).ConfigureAwait(false);

                return(resolveResult);
            }
            catch (Exception exc)
            {
                var error = new ExecutionError("Error trying to resolve {0}.".ToFormat(field.Name), exc);
                error.AddLocation(field, context.Document);
                context.Errors.Add(error);
                resolveResult.Skip = false;
                return(resolveResult);
            }
        }
예제 #51
0
        public async Task<ResolveFieldResult<object>> ResolveFieldAsync(ExecutionContext context, ObjectGraphType parentType, object source, Fields fields)
        {
            context.CancellationToken.ThrowIfCancellationRequested();

            var resolveResult = new ResolveFieldResult<object>
            {
                Skip = false
            };

            var field = fields.First();

            var fieldDefinition = GetFieldDefinition(context.Schema, parentType, field);
            if (fieldDefinition == null)
            {
                resolveResult.Skip = true;
                return resolveResult;
            }

            var arguments = GetArgumentValues(context.Schema, fieldDefinition.Arguments, field.Arguments, context.Variables);

            Func<ResolveFieldContext, object> defaultResolve =
                ctx => ctx.Source != null
                    ? GetProperyValue(ctx.Source, ctx.FieldAst.Name)
                    : null;

            try
            {
                var resolveContext = new ResolveFieldContext();
                resolveContext.FieldName = field.Name;
                resolveContext.FieldAst = field;
                resolveContext.FieldDefinition = fieldDefinition;
                resolveContext.ReturnType = context.Schema.FindType(fieldDefinition.Type);
                resolveContext.ParentType = parentType;
                resolveContext.Arguments = arguments;
                resolveContext.Source = source;
                resolveContext.Schema = context.Schema;
                resolveContext.Fragments = context.Fragments;
                resolveContext.RootValue = context.RootValue;
                resolveContext.Operation = context.Operation;
                resolveContext.Variables = context.Variables;
                resolveContext.CancellationToken = context.CancellationToken;
                var resolve = fieldDefinition.Resolve ?? defaultResolve;
                var result = resolve(resolveContext);

                if(result is Task)
                {
                    var task = result as Task;
                    await task.ConfigureAwait(false);

                    result = GetProperyValue(task, "Result");
                }

                if (parentType is __Field && result is Type)
                {
                    result = context.Schema.FindType(result as Type);
                }

                resolveResult.Value = await CompleteValueAsync(context, context.Schema.FindType(fieldDefinition.Type), fields, result).ConfigureAwait(false);
                return resolveResult;
            }
            catch (Exception exc)
            {
                var error = new ExecutionError("Error trying to resolve {0}.".ToFormat(field.Name), exc);
                error.AddLocation(field.SourceLocation.Line, field.SourceLocation.Column);
                context.Errors.Add(error);
                resolveResult.Skip = false;
                return resolveResult;
            }
        }