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); }
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)); }
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); } }
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); }
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)); }
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)); } }