Beispiel #1
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);
        }
Beispiel #2
0
        public async Task <object> CompleteValue(ExecutionContext context, GraphType fieldType, Fields fields, object result)
        {
            var nonNullType = fieldType as NonNullGraphType;

            if (nonNullType != null)
            {
                var type      = context.Schema.FindType(nonNullType.Type);
                var completed = await CompleteValue(context, type, fields, result);

                if (completed == null)
                {
                    var field = fields != null?fields.FirstOrDefault() : null;

                    var fieldName = field != null ? field.Name : null;
                    throw new ExecutionError("Cannot return null for non-null type. Field: {0}, Type: {1}!."
                                             .ToFormat(fieldName, type.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 GraphQLAbstractType)
            {
                var abstractType = fieldType as GraphQLAbstractType;
                objectType = abstractType.GetObjectType(result);

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

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

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

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

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

            return(await ExecuteFields(context, objectType, result, subFields));
        }
Beispiel #3
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);
            }
        }
Beispiel #4
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>(StringComparer.OrdinalIgnoreCase);
            }

            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);
        }
Beispiel #5
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>(StringComparer.OrdinalIgnoreCase);
            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));
        }
Beispiel #6
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;
                    if (task.IsFaulted)
                    {
                        var aggregateException = task.Exception;
                        var exception          = aggregateException.InnerExceptions.Count == 1
                            ? aggregateException.InnerException
                            : aggregateException;
                        return(GenerateError(resolveResult, field, context, exception));
                    }
                    await task.ConfigureAwait(false);

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

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

                return(resolveResult);
            }
            catch (Exception exc)
            {
                return(GenerateError(resolveResult, field, context, exc));
            }
        }