1package graphql 2 3import ( 4 "context" 5 "errors" 6 "fmt" 7 "reflect" 8 "sort" 9 "strings" 10 11 "github.com/graphql-go/graphql/gqlerrors" 12 "github.com/graphql-go/graphql/language/ast" 13) 14 15type ExecuteParams struct { 16 Schema Schema 17 Root interface{} 18 AST *ast.Document 19 OperationName string 20 Args map[string]interface{} 21 22 // Context may be provided to pass application-specific per-request 23 // information to resolve functions. 24 Context context.Context 25} 26 27func Execute(p ExecuteParams) (result *Result) { 28 // Use background context if no context was provided 29 ctx := p.Context 30 if ctx == nil { 31 ctx = context.Background() 32 } 33 // run executionDidStart functions from extensions 34 extErrs, executionFinishFn := handleExtensionsExecutionDidStart(&p) 35 if len(extErrs) != 0 { 36 return &Result{ 37 Errors: extErrs, 38 } 39 } 40 41 defer func() { 42 extErrs = executionFinishFn(result) 43 if len(extErrs) != 0 { 44 result.Errors = append(result.Errors, extErrs...) 45 } 46 47 addExtensionResults(&p, result) 48 }() 49 50 resultChannel := make(chan *Result, 2) 51 52 go func() { 53 result := &Result{} 54 55 defer func() { 56 if err := recover(); err != nil { 57 result.Errors = append(result.Errors, gqlerrors.FormatError(err.(error))) 58 } 59 resultChannel <- result 60 }() 61 62 exeContext, err := buildExecutionContext(buildExecutionCtxParams{ 63 Schema: p.Schema, 64 Root: p.Root, 65 AST: p.AST, 66 OperationName: p.OperationName, 67 Args: p.Args, 68 Result: result, 69 Context: p.Context, 70 }) 71 72 if err != nil { 73 result.Errors = append(result.Errors, gqlerrors.FormatError(err.(error))) 74 resultChannel <- result 75 return 76 } 77 78 resultChannel <- executeOperation(executeOperationParams{ 79 ExecutionContext: exeContext, 80 Root: p.Root, 81 Operation: exeContext.Operation, 82 }) 83 }() 84 85 select { 86 case <-ctx.Done(): 87 result := &Result{} 88 result.Errors = append(result.Errors, gqlerrors.FormatError(ctx.Err())) 89 return result 90 case r := <-resultChannel: 91 return r 92 } 93} 94 95type buildExecutionCtxParams struct { 96 Schema Schema 97 Root interface{} 98 AST *ast.Document 99 OperationName string 100 Args map[string]interface{} 101 Result *Result 102 Context context.Context 103} 104 105type executionContext struct { 106 Schema Schema 107 Fragments map[string]ast.Definition 108 Root interface{} 109 Operation ast.Definition 110 VariableValues map[string]interface{} 111 Errors []gqlerrors.FormattedError 112 Context context.Context 113} 114 115func buildExecutionContext(p buildExecutionCtxParams) (*executionContext, error) { 116 eCtx := &executionContext{} 117 var operation *ast.OperationDefinition 118 fragments := map[string]ast.Definition{} 119 120 for _, definition := range p.AST.Definitions { 121 switch definition := definition.(type) { 122 case *ast.OperationDefinition: 123 if (p.OperationName == "") && operation != nil { 124 return nil, errors.New("Must provide operation name if query contains multiple operations.") 125 } 126 if p.OperationName == "" || definition.GetName() != nil && definition.GetName().Value == p.OperationName { 127 operation = definition 128 } 129 case *ast.FragmentDefinition: 130 key := "" 131 if definition.GetName() != nil && definition.GetName().Value != "" { 132 key = definition.GetName().Value 133 } 134 fragments[key] = definition 135 default: 136 return nil, fmt.Errorf("GraphQL cannot execute a request containing a %v", definition.GetKind()) 137 } 138 } 139 140 if operation == nil { 141 if p.OperationName != "" { 142 return nil, fmt.Errorf(`Unknown operation named "%v".`, p.OperationName) 143 } 144 return nil, fmt.Errorf(`Must provide an operation.`) 145 } 146 147 variableValues, err := getVariableValues(p.Schema, operation.GetVariableDefinitions(), p.Args) 148 if err != nil { 149 return nil, err 150 } 151 152 eCtx.Schema = p.Schema 153 eCtx.Fragments = fragments 154 eCtx.Root = p.Root 155 eCtx.Operation = operation 156 eCtx.VariableValues = variableValues 157 eCtx.Context = p.Context 158 return eCtx, nil 159} 160 161type executeOperationParams struct { 162 ExecutionContext *executionContext 163 Root interface{} 164 Operation ast.Definition 165} 166 167func executeOperation(p executeOperationParams) *Result { 168 operationType, err := getOperationRootType(p.ExecutionContext.Schema, p.Operation) 169 if err != nil { 170 return &Result{Errors: gqlerrors.FormatErrors(err)} 171 } 172 173 fields := collectFields(collectFieldsParams{ 174 ExeContext: p.ExecutionContext, 175 RuntimeType: operationType, 176 SelectionSet: p.Operation.GetSelectionSet(), 177 }) 178 179 executeFieldsParams := executeFieldsParams{ 180 ExecutionContext: p.ExecutionContext, 181 ParentType: operationType, 182 Source: p.Root, 183 Fields: fields, 184 } 185 186 if p.Operation.GetOperation() == ast.OperationTypeMutation { 187 return executeFieldsSerially(executeFieldsParams) 188 } 189 return executeFields(executeFieldsParams) 190 191} 192 193// Extracts the root type of the operation from the schema. 194func getOperationRootType(schema Schema, operation ast.Definition) (*Object, error) { 195 if operation == nil { 196 return nil, errors.New("Can only execute queries, mutations and subscription") 197 } 198 199 switch operation.GetOperation() { 200 case ast.OperationTypeQuery: 201 return schema.QueryType(), nil 202 case ast.OperationTypeMutation: 203 mutationType := schema.MutationType() 204 if mutationType == nil || mutationType.PrivateName == "" { 205 return nil, gqlerrors.NewError( 206 "Schema is not configured for mutations", 207 []ast.Node{operation}, 208 "", 209 nil, 210 []int{}, 211 nil, 212 ) 213 } 214 return mutationType, nil 215 case ast.OperationTypeSubscription: 216 subscriptionType := schema.SubscriptionType() 217 if subscriptionType == nil || subscriptionType.PrivateName == "" { 218 return nil, gqlerrors.NewError( 219 "Schema is not configured for subscriptions", 220 []ast.Node{operation}, 221 "", 222 nil, 223 []int{}, 224 nil, 225 ) 226 } 227 return subscriptionType, nil 228 default: 229 return nil, gqlerrors.NewError( 230 "Can only execute queries, mutations and subscription", 231 []ast.Node{operation}, 232 "", 233 nil, 234 []int{}, 235 nil, 236 ) 237 } 238} 239 240type executeFieldsParams struct { 241 ExecutionContext *executionContext 242 ParentType *Object 243 Source interface{} 244 Fields map[string][]*ast.Field 245 Path *ResponsePath 246} 247 248// Implements the "Evaluating selection sets" section of the spec for "write" mode. 249func executeFieldsSerially(p executeFieldsParams) *Result { 250 if p.Source == nil { 251 p.Source = map[string]interface{}{} 252 } 253 if p.Fields == nil { 254 p.Fields = map[string][]*ast.Field{} 255 } 256 257 finalResults := make(map[string]interface{}, len(p.Fields)) 258 for _, orderedField := range orderedFields(p.Fields) { 259 responseName := orderedField.responseName 260 fieldASTs := orderedField.fieldASTs 261 fieldPath := p.Path.WithKey(responseName) 262 resolved, state := resolveField(p.ExecutionContext, p.ParentType, p.Source, fieldASTs, fieldPath) 263 if state.hasNoFieldDefs { 264 continue 265 } 266 finalResults[responseName] = resolved 267 } 268 dethunkMapDepthFirst(finalResults) 269 270 return &Result{ 271 Data: finalResults, 272 Errors: p.ExecutionContext.Errors, 273 } 274} 275 276// Implements the "Evaluating selection sets" section of the spec for "read" mode. 277func executeFields(p executeFieldsParams) *Result { 278 finalResults := executeSubFields(p) 279 280 dethunkMapWithBreadthFirstTraversal(finalResults) 281 282 return &Result{ 283 Data: finalResults, 284 Errors: p.ExecutionContext.Errors, 285 } 286} 287 288func executeSubFields(p executeFieldsParams) map[string]interface{} { 289 290 if p.Source == nil { 291 p.Source = map[string]interface{}{} 292 } 293 if p.Fields == nil { 294 p.Fields = map[string][]*ast.Field{} 295 } 296 297 finalResults := make(map[string]interface{}, len(p.Fields)) 298 for responseName, fieldASTs := range p.Fields { 299 fieldPath := p.Path.WithKey(responseName) 300 resolved, state := resolveField(p.ExecutionContext, p.ParentType, p.Source, fieldASTs, fieldPath) 301 if state.hasNoFieldDefs { 302 continue 303 } 304 finalResults[responseName] = resolved 305 } 306 307 return finalResults 308} 309 310// dethunkQueue is a structure that allows us to execute a classic breadth-first traversal. 311type dethunkQueue struct { 312 DethunkFuncs []func() 313} 314 315func (d *dethunkQueue) push(f func()) { 316 d.DethunkFuncs = append(d.DethunkFuncs, f) 317} 318 319func (d *dethunkQueue) shift() func() { 320 f := d.DethunkFuncs[0] 321 d.DethunkFuncs = d.DethunkFuncs[1:] 322 return f 323} 324 325// dethunkWithBreadthFirstTraversal performs a breadth-first descent of the map, calling any thunks 326// in the map values and replacing each thunk with that thunk's return value. This parallels 327// the reference graphql-js implementation, which calls Promise.all on thunks at each depth (which 328// is an implicit parallel descent). 329func dethunkMapWithBreadthFirstTraversal(finalResults map[string]interface{}) { 330 dethunkQueue := &dethunkQueue{DethunkFuncs: []func(){}} 331 dethunkMapBreadthFirst(finalResults, dethunkQueue) 332 for len(dethunkQueue.DethunkFuncs) > 0 { 333 f := dethunkQueue.shift() 334 f() 335 } 336} 337 338func dethunkMapBreadthFirst(m map[string]interface{}, dethunkQueue *dethunkQueue) { 339 for k, v := range m { 340 if f, ok := v.(func() interface{}); ok { 341 m[k] = f() 342 } 343 switch val := m[k].(type) { 344 case map[string]interface{}: 345 dethunkQueue.push(func() { dethunkMapBreadthFirst(val, dethunkQueue) }) 346 case []interface{}: 347 dethunkQueue.push(func() { dethunkListBreadthFirst(val, dethunkQueue) }) 348 } 349 } 350} 351 352func dethunkListBreadthFirst(list []interface{}, dethunkQueue *dethunkQueue) { 353 for i, v := range list { 354 if f, ok := v.(func() interface{}); ok { 355 list[i] = f() 356 } 357 switch val := list[i].(type) { 358 case map[string]interface{}: 359 dethunkQueue.push(func() { dethunkMapBreadthFirst(val, dethunkQueue) }) 360 case []interface{}: 361 dethunkQueue.push(func() { dethunkListBreadthFirst(val, dethunkQueue) }) 362 } 363 } 364} 365 366// dethunkMapDepthFirst performs a serial descent of the map, calling any thunks 367// in the map values and replacing each thunk with that thunk's return value. This is needed 368// to conform to the graphql-js reference implementation, which requires serial (depth-first) 369// implementations for mutation selects. 370func dethunkMapDepthFirst(m map[string]interface{}) { 371 for k, v := range m { 372 if f, ok := v.(func() interface{}); ok { 373 m[k] = f() 374 } 375 switch val := m[k].(type) { 376 case map[string]interface{}: 377 dethunkMapDepthFirst(val) 378 case []interface{}: 379 dethunkListDepthFirst(val) 380 } 381 } 382} 383 384func dethunkListDepthFirst(list []interface{}) { 385 for i, v := range list { 386 if f, ok := v.(func() interface{}); ok { 387 list[i] = f() 388 } 389 switch val := list[i].(type) { 390 case map[string]interface{}: 391 dethunkMapDepthFirst(val) 392 case []interface{}: 393 dethunkListDepthFirst(val) 394 } 395 } 396} 397 398type collectFieldsParams struct { 399 ExeContext *executionContext 400 RuntimeType *Object // previously known as OperationType 401 SelectionSet *ast.SelectionSet 402 Fields map[string][]*ast.Field 403 VisitedFragmentNames map[string]bool 404} 405 406// Given a selectionSet, adds all of the fields in that selection to 407// the passed in map of fields, and returns it at the end. 408// CollectFields requires the "runtime type" of an object. For a field which 409// returns and Interface or Union type, the "runtime type" will be the actual 410// Object type returned by that field. 411func collectFields(p collectFieldsParams) (fields map[string][]*ast.Field) { 412 // overlying SelectionSet & Fields to fields 413 if p.SelectionSet == nil { 414 return p.Fields 415 } 416 fields = p.Fields 417 if fields == nil { 418 fields = map[string][]*ast.Field{} 419 } 420 if p.VisitedFragmentNames == nil { 421 p.VisitedFragmentNames = map[string]bool{} 422 } 423 for _, iSelection := range p.SelectionSet.Selections { 424 switch selection := iSelection.(type) { 425 case *ast.Field: 426 if !shouldIncludeNode(p.ExeContext, selection.Directives) { 427 continue 428 } 429 name := getFieldEntryKey(selection) 430 if _, ok := fields[name]; !ok { 431 fields[name] = []*ast.Field{} 432 } 433 fields[name] = append(fields[name], selection) 434 case *ast.InlineFragment: 435 436 if !shouldIncludeNode(p.ExeContext, selection.Directives) || 437 !doesFragmentConditionMatch(p.ExeContext, selection, p.RuntimeType) { 438 continue 439 } 440 innerParams := collectFieldsParams{ 441 ExeContext: p.ExeContext, 442 RuntimeType: p.RuntimeType, 443 SelectionSet: selection.SelectionSet, 444 Fields: fields, 445 VisitedFragmentNames: p.VisitedFragmentNames, 446 } 447 collectFields(innerParams) 448 case *ast.FragmentSpread: 449 fragName := "" 450 if selection.Name != nil { 451 fragName = selection.Name.Value 452 } 453 if visited, ok := p.VisitedFragmentNames[fragName]; (ok && visited) || 454 !shouldIncludeNode(p.ExeContext, selection.Directives) { 455 continue 456 } 457 p.VisitedFragmentNames[fragName] = true 458 fragment, hasFragment := p.ExeContext.Fragments[fragName] 459 if !hasFragment { 460 continue 461 } 462 463 if fragment, ok := fragment.(*ast.FragmentDefinition); ok { 464 if !doesFragmentConditionMatch(p.ExeContext, fragment, p.RuntimeType) { 465 continue 466 } 467 innerParams := collectFieldsParams{ 468 ExeContext: p.ExeContext, 469 RuntimeType: p.RuntimeType, 470 SelectionSet: fragment.GetSelectionSet(), 471 Fields: fields, 472 VisitedFragmentNames: p.VisitedFragmentNames, 473 } 474 collectFields(innerParams) 475 } 476 } 477 } 478 return fields 479} 480 481// Determines if a field should be included based on the @include and @skip 482// directives, where @skip has higher precedence than @include. 483func shouldIncludeNode(eCtx *executionContext, directives []*ast.Directive) bool { 484 var ( 485 skipAST, includeAST *ast.Directive 486 argValues map[string]interface{} 487 ) 488 for _, directive := range directives { 489 if directive == nil || directive.Name == nil { 490 continue 491 } 492 switch directive.Name.Value { 493 case SkipDirective.Name: 494 skipAST = directive 495 case IncludeDirective.Name: 496 includeAST = directive 497 } 498 } 499 // precedence: skipAST > includeAST 500 if skipAST != nil { 501 argValues = getArgumentValues(SkipDirective.Args, skipAST.Arguments, eCtx.VariableValues) 502 if skipIf, ok := argValues["if"].(bool); ok && skipIf { 503 return false // excluded selectionSet's fields 504 } 505 } 506 if includeAST != nil { 507 argValues = getArgumentValues(IncludeDirective.Args, includeAST.Arguments, eCtx.VariableValues) 508 if includeIf, ok := argValues["if"].(bool); ok && !includeIf { 509 return false // excluded selectionSet's fields 510 } 511 } 512 return true 513} 514 515// Determines if a fragment is applicable to the given type. 516func doesFragmentConditionMatch(eCtx *executionContext, fragment ast.Node, ttype *Object) bool { 517 518 switch fragment := fragment.(type) { 519 case *ast.FragmentDefinition: 520 typeConditionAST := fragment.TypeCondition 521 if typeConditionAST == nil { 522 return true 523 } 524 conditionalType, err := typeFromAST(eCtx.Schema, typeConditionAST) 525 if err != nil { 526 return false 527 } 528 if conditionalType == ttype { 529 return true 530 } 531 if conditionalType.Name() == ttype.Name() { 532 return true 533 } 534 if conditionalType, ok := conditionalType.(*Interface); ok { 535 return eCtx.Schema.IsPossibleType(conditionalType, ttype) 536 } 537 if conditionalType, ok := conditionalType.(*Union); ok { 538 return eCtx.Schema.IsPossibleType(conditionalType, ttype) 539 } 540 case *ast.InlineFragment: 541 typeConditionAST := fragment.TypeCondition 542 if typeConditionAST == nil { 543 return true 544 } 545 conditionalType, err := typeFromAST(eCtx.Schema, typeConditionAST) 546 if err != nil { 547 return false 548 } 549 if conditionalType == ttype { 550 return true 551 } 552 if conditionalType.Name() == ttype.Name() { 553 return true 554 } 555 if conditionalType, ok := conditionalType.(*Interface); ok { 556 return eCtx.Schema.IsPossibleType(conditionalType, ttype) 557 } 558 if conditionalType, ok := conditionalType.(*Union); ok { 559 return eCtx.Schema.IsPossibleType(conditionalType, ttype) 560 } 561 } 562 563 return false 564} 565 566// Implements the logic to compute the key of a given field’s entry 567func getFieldEntryKey(node *ast.Field) string { 568 569 if node.Alias != nil && node.Alias.Value != "" { 570 return node.Alias.Value 571 } 572 if node.Name != nil && node.Name.Value != "" { 573 return node.Name.Value 574 } 575 return "" 576} 577 578// Internal resolveField state 579type resolveFieldResultState struct { 580 hasNoFieldDefs bool 581} 582 583func handleFieldError(r interface{}, fieldNodes []ast.Node, path *ResponsePath, returnType Output, eCtx *executionContext) { 584 err := NewLocatedErrorWithPath(r, fieldNodes, path.AsArray()) 585 // send panic upstream 586 if _, ok := returnType.(*NonNull); ok { 587 panic(err) 588 } 589 eCtx.Errors = append(eCtx.Errors, gqlerrors.FormatError(err)) 590} 591 592// Resolves the field on the given source object. In particular, this 593// figures out the value that the field returns by calling its resolve function, 594// then calls completeValue to complete promises, serialize scalars, or execute 595// the sub-selection-set for objects. 596func resolveField(eCtx *executionContext, parentType *Object, source interface{}, fieldASTs []*ast.Field, path *ResponsePath) (result interface{}, resultState resolveFieldResultState) { 597 // catch panic from resolveFn 598 var returnType Output 599 defer func() (interface{}, resolveFieldResultState) { 600 if r := recover(); r != nil { 601 handleFieldError(r, FieldASTsToNodeASTs(fieldASTs), path, returnType, eCtx) 602 return result, resultState 603 } 604 return result, resultState 605 }() 606 607 fieldAST := fieldASTs[0] 608 fieldName := "" 609 if fieldAST.Name != nil { 610 fieldName = fieldAST.Name.Value 611 } 612 613 fieldDef := getFieldDef(eCtx.Schema, parentType, fieldName) 614 if fieldDef == nil { 615 resultState.hasNoFieldDefs = true 616 return nil, resultState 617 } 618 returnType = fieldDef.Type 619 resolveFn := fieldDef.Resolve 620 if resolveFn == nil { 621 resolveFn = DefaultResolveFn 622 } 623 624 // Build a map of arguments from the field.arguments AST, using the 625 // variables scope to fulfill any variable references. 626 // TODO: find a way to memoize, in case this field is within a List type. 627 args := getArgumentValues(fieldDef.Args, fieldAST.Arguments, eCtx.VariableValues) 628 629 info := ResolveInfo{ 630 FieldName: fieldName, 631 FieldASTs: fieldASTs, 632 Path: path, 633 ReturnType: returnType, 634 ParentType: parentType, 635 Schema: eCtx.Schema, 636 Fragments: eCtx.Fragments, 637 RootValue: eCtx.Root, 638 Operation: eCtx.Operation, 639 VariableValues: eCtx.VariableValues, 640 } 641 642 var resolveFnError error 643 644 extErrs, resolveFieldFinishFn := handleExtensionsResolveFieldDidStart(eCtx.Schema.extensions, eCtx, &info) 645 if len(extErrs) != 0 { 646 eCtx.Errors = append(eCtx.Errors, extErrs...) 647 } 648 649 result, resolveFnError = resolveFn(ResolveParams{ 650 Source: source, 651 Args: args, 652 Info: info, 653 Context: eCtx.Context, 654 }) 655 656 extErrs = resolveFieldFinishFn(result, resolveFnError) 657 if len(extErrs) != 0 { 658 eCtx.Errors = append(eCtx.Errors, extErrs...) 659 } 660 661 if resolveFnError != nil { 662 panic(resolveFnError) 663 } 664 665 completed := completeValueCatchingError(eCtx, returnType, fieldASTs, info, path, result) 666 return completed, resultState 667} 668 669func completeValueCatchingError(eCtx *executionContext, returnType Type, fieldASTs []*ast.Field, info ResolveInfo, path *ResponsePath, result interface{}) (completed interface{}) { 670 // catch panic 671 defer func() interface{} { 672 if r := recover(); r != nil { 673 handleFieldError(r, FieldASTsToNodeASTs(fieldASTs), path, returnType, eCtx) 674 return completed 675 } 676 return completed 677 }() 678 679 if returnType, ok := returnType.(*NonNull); ok { 680 completed := completeValue(eCtx, returnType, fieldASTs, info, path, result) 681 return completed 682 } 683 completed = completeValue(eCtx, returnType, fieldASTs, info, path, result) 684 return completed 685} 686 687func completeValue(eCtx *executionContext, returnType Type, fieldASTs []*ast.Field, info ResolveInfo, path *ResponsePath, result interface{}) interface{} { 688 689 resultVal := reflect.ValueOf(result) 690 if resultVal.IsValid() && resultVal.Kind() == reflect.Func { 691 return func() interface{} { 692 return completeThunkValueCatchingError(eCtx, returnType, fieldASTs, info, path, result) 693 } 694 } 695 696 // If field type is NonNull, complete for inner type, and throw field error 697 // if result is null. 698 if returnType, ok := returnType.(*NonNull); ok { 699 completed := completeValue(eCtx, returnType.OfType, fieldASTs, info, path, result) 700 if completed == nil { 701 err := NewLocatedErrorWithPath( 702 fmt.Sprintf("Cannot return null for non-nullable field %v.%v.", info.ParentType, info.FieldName), 703 FieldASTsToNodeASTs(fieldASTs), 704 path.AsArray(), 705 ) 706 panic(gqlerrors.FormatError(err)) 707 } 708 return completed 709 } 710 711 // If result value is null-ish (null, undefined, or NaN) then return null. 712 if isNullish(result) { 713 return nil 714 } 715 716 // If field type is List, complete each item in the list with the inner type 717 if returnType, ok := returnType.(*List); ok { 718 return completeListValue(eCtx, returnType, fieldASTs, info, path, result) 719 } 720 721 // If field type is a leaf type, Scalar or Enum, serialize to a valid value, 722 // returning null if serialization is not possible. 723 if returnType, ok := returnType.(*Scalar); ok { 724 return completeLeafValue(returnType, result) 725 } 726 if returnType, ok := returnType.(*Enum); ok { 727 return completeLeafValue(returnType, result) 728 } 729 730 // If field type is an abstract type, Interface or Union, determine the 731 // runtime Object type and complete for that type. 732 if returnType, ok := returnType.(*Union); ok { 733 return completeAbstractValue(eCtx, returnType, fieldASTs, info, path, result) 734 } 735 if returnType, ok := returnType.(*Interface); ok { 736 return completeAbstractValue(eCtx, returnType, fieldASTs, info, path, result) 737 } 738 739 // If field type is Object, execute and complete all sub-selections. 740 if returnType, ok := returnType.(*Object); ok { 741 return completeObjectValue(eCtx, returnType, fieldASTs, info, path, result) 742 } 743 744 // Not reachable. All possible output types have been considered. 745 err := invariantf(false, 746 `Cannot complete value of unexpected type "%v."`, returnType) 747 748 if err != nil { 749 panic(gqlerrors.FormatError(err)) 750 } 751 return nil 752} 753 754func completeThunkValueCatchingError(eCtx *executionContext, returnType Type, fieldASTs []*ast.Field, info ResolveInfo, path *ResponsePath, result interface{}) (completed interface{}) { 755 756 // catch any panic invoked from the propertyFn (thunk) 757 defer func() { 758 if r := recover(); r != nil { 759 handleFieldError(r, FieldASTsToNodeASTs(fieldASTs), path, returnType, eCtx) 760 } 761 }() 762 763 propertyFn, ok := result.(func() (interface{}, error)) 764 if !ok { 765 err := gqlerrors.NewFormattedError("Error resolving func. Expected `func() (interface{}, error)` signature") 766 panic(gqlerrors.FormatError(err)) 767 } 768 fnResult, err := propertyFn() 769 if err != nil { 770 panic(gqlerrors.FormatError(err)) 771 } 772 773 result = fnResult 774 775 if returnType, ok := returnType.(*NonNull); ok { 776 completed := completeValue(eCtx, returnType, fieldASTs, info, path, result) 777 return completed 778 } 779 completed = completeValue(eCtx, returnType, fieldASTs, info, path, result) 780 781 return completed 782} 783 784// completeAbstractValue completes value of an Abstract type (Union / Interface) by determining the runtime type 785// of that value, then completing based on that type. 786func completeAbstractValue(eCtx *executionContext, returnType Abstract, fieldASTs []*ast.Field, info ResolveInfo, path *ResponsePath, result interface{}) interface{} { 787 788 var runtimeType *Object 789 790 resolveTypeParams := ResolveTypeParams{ 791 Value: result, 792 Info: info, 793 Context: eCtx.Context, 794 } 795 if unionReturnType, ok := returnType.(*Union); ok && unionReturnType.ResolveType != nil { 796 runtimeType = unionReturnType.ResolveType(resolveTypeParams) 797 } else if interfaceReturnType, ok := returnType.(*Interface); ok && interfaceReturnType.ResolveType != nil { 798 runtimeType = interfaceReturnType.ResolveType(resolveTypeParams) 799 } else { 800 runtimeType = defaultResolveTypeFn(resolveTypeParams, returnType) 801 } 802 803 err := invariant(runtimeType != nil, 804 fmt.Sprintf(`Abstract type %v must resolve to an Object type at runtime `+ 805 `for field %v.%v with value "%v", received "%v".`, 806 returnType, info.ParentType, info.FieldName, result, runtimeType), 807 ) 808 if err != nil { 809 panic(err) 810 } 811 812 if !eCtx.Schema.IsPossibleType(returnType, runtimeType) { 813 panic(gqlerrors.NewFormattedError( 814 fmt.Sprintf(`Runtime Object type "%v" is not a possible type `+ 815 `for "%v".`, runtimeType, returnType), 816 )) 817 } 818 819 return completeObjectValue(eCtx, runtimeType, fieldASTs, info, path, result) 820} 821 822// completeObjectValue complete an Object value by executing all sub-selections. 823func completeObjectValue(eCtx *executionContext, returnType *Object, fieldASTs []*ast.Field, info ResolveInfo, path *ResponsePath, result interface{}) interface{} { 824 825 // If there is an isTypeOf predicate function, call it with the 826 // current result. If isTypeOf returns false, then raise an error rather 827 // than continuing execution. 828 if returnType.IsTypeOf != nil { 829 p := IsTypeOfParams{ 830 Value: result, 831 Info: info, 832 Context: eCtx.Context, 833 } 834 if !returnType.IsTypeOf(p) { 835 panic(gqlerrors.NewFormattedError( 836 fmt.Sprintf(`Expected value of type "%v" but got: %T.`, returnType, result), 837 )) 838 } 839 } 840 841 // Collect sub-fields to execute to complete this value. 842 subFieldASTs := map[string][]*ast.Field{} 843 visitedFragmentNames := map[string]bool{} 844 for _, fieldAST := range fieldASTs { 845 if fieldAST == nil { 846 continue 847 } 848 selectionSet := fieldAST.SelectionSet 849 if selectionSet != nil { 850 innerParams := collectFieldsParams{ 851 ExeContext: eCtx, 852 RuntimeType: returnType, 853 SelectionSet: selectionSet, 854 Fields: subFieldASTs, 855 VisitedFragmentNames: visitedFragmentNames, 856 } 857 subFieldASTs = collectFields(innerParams) 858 } 859 } 860 executeFieldsParams := executeFieldsParams{ 861 ExecutionContext: eCtx, 862 ParentType: returnType, 863 Source: result, 864 Fields: subFieldASTs, 865 Path: path, 866 } 867 return executeSubFields(executeFieldsParams) 868} 869 870// completeLeafValue complete a leaf value (Scalar / Enum) by serializing to a valid value, returning nil if serialization is not possible. 871func completeLeafValue(returnType Leaf, result interface{}) interface{} { 872 serializedResult := returnType.Serialize(result) 873 if isNullish(serializedResult) { 874 return nil 875 } 876 return serializedResult 877} 878 879// completeListValue complete a list value by completing each item in the list with the inner type 880func completeListValue(eCtx *executionContext, returnType *List, fieldASTs []*ast.Field, info ResolveInfo, path *ResponsePath, result interface{}) interface{} { 881 resultVal := reflect.ValueOf(result) 882 if resultVal.Kind() == reflect.Ptr { 883 resultVal = resultVal.Elem() 884 } 885 parentTypeName := "" 886 if info.ParentType != nil { 887 parentTypeName = info.ParentType.Name() 888 } 889 err := invariantf( 890 resultVal.IsValid() && isIterable(result), 891 "User Error: expected iterable, but did not find one "+ 892 "for field %v.%v.", parentTypeName, info.FieldName) 893 894 if err != nil { 895 panic(gqlerrors.FormatError(err)) 896 } 897 898 itemType := returnType.OfType 899 completedResults := make([]interface{}, 0, resultVal.Len()) 900 for i := 0; i < resultVal.Len(); i++ { 901 val := resultVal.Index(i).Interface() 902 fieldPath := path.WithKey(i) 903 completedItem := completeValueCatchingError(eCtx, itemType, fieldASTs, info, fieldPath, val) 904 completedResults = append(completedResults, completedItem) 905 } 906 return completedResults 907} 908 909// defaultResolveTypeFn If a resolveType function is not given, then a default resolve behavior is 910// used which tests each possible type for the abstract type by calling 911// isTypeOf for the object being coerced, returning the first type that matches. 912func defaultResolveTypeFn(p ResolveTypeParams, abstractType Abstract) *Object { 913 possibleTypes := p.Info.Schema.PossibleTypes(abstractType) 914 for _, possibleType := range possibleTypes { 915 if possibleType.IsTypeOf == nil { 916 continue 917 } 918 isTypeOfParams := IsTypeOfParams{ 919 Value: p.Value, 920 Info: p.Info, 921 Context: p.Context, 922 } 923 if res := possibleType.IsTypeOf(isTypeOfParams); res { 924 return possibleType 925 } 926 } 927 return nil 928} 929 930// FieldResolver is used in DefaultResolveFn when the the source value implements this interface. 931type FieldResolver interface { 932 // Resolve resolves the value for the given ResolveParams. It has the same semantics as FieldResolveFn. 933 Resolve(p ResolveParams) (interface{}, error) 934} 935 936// DefaultResolveFn If a resolve function is not given, then a default resolve behavior is used 937// which takes the property of the source object of the same name as the field 938// and returns it as the result, or if it's a function, returns the result 939// of calling that function. 940func DefaultResolveFn(p ResolveParams) (interface{}, error) { 941 sourceVal := reflect.ValueOf(p.Source) 942 // Check if value implements 'Resolver' interface 943 if resolver, ok := sourceVal.Interface().(FieldResolver); ok { 944 return resolver.Resolve(p) 945 } 946 947 // try to resolve p.Source as a struct 948 if sourceVal.IsValid() && sourceVal.Type().Kind() == reflect.Ptr { 949 sourceVal = sourceVal.Elem() 950 } 951 if !sourceVal.IsValid() { 952 return nil, nil 953 } 954 955 if sourceVal.Type().Kind() == reflect.Struct { 956 for i := 0; i < sourceVal.NumField(); i++ { 957 valueField := sourceVal.Field(i) 958 typeField := sourceVal.Type().Field(i) 959 // try matching the field name first 960 if strings.EqualFold(typeField.Name, p.Info.FieldName) { 961 return valueField.Interface(), nil 962 } 963 tag := typeField.Tag 964 checkTag := func(tagName string) bool { 965 t := tag.Get(tagName) 966 tOptions := strings.Split(t, ",") 967 if len(tOptions) == 0 { 968 return false 969 } 970 if tOptions[0] != p.Info.FieldName { 971 return false 972 } 973 return true 974 } 975 if checkTag("json") || checkTag("graphql") { 976 return valueField.Interface(), nil 977 } else { 978 continue 979 } 980 } 981 return nil, nil 982 } 983 984 // try p.Source as a map[string]interface 985 if sourceMap, ok := p.Source.(map[string]interface{}); ok { 986 property := sourceMap[p.Info.FieldName] 987 val := reflect.ValueOf(property) 988 if val.IsValid() && val.Type().Kind() == reflect.Func { 989 // try type casting the func to the most basic func signature 990 // for more complex signatures, user have to define ResolveFn 991 if propertyFn, ok := property.(func() interface{}); ok { 992 return propertyFn(), nil 993 } 994 } 995 return property, nil 996 } 997 998 // Try accessing as map via reflection 999 if r := reflect.ValueOf(p.Source); r.Kind() == reflect.Map && r.Type().Key().Kind() == reflect.String { 1000 val := r.MapIndex(reflect.ValueOf(p.Info.FieldName)) 1001 if val.IsValid() { 1002 property := val.Interface() 1003 if val.Type().Kind() == reflect.Func { 1004 // try type casting the func to the most basic func signature 1005 // for more complex signatures, user have to define ResolveFn 1006 if propertyFn, ok := property.(func() interface{}); ok { 1007 return propertyFn(), nil 1008 } 1009 } 1010 return property, nil 1011 } 1012 } 1013 1014 // last resort, return nil 1015 return nil, nil 1016} 1017 1018// This method looks up the field on the given type definition. 1019// It has special casing for the two introspection fields, __schema 1020// and __typename. __typename is special because it can always be 1021// queried as a field, even in situations where no other fields 1022// are allowed, like on a Union. __schema could get automatically 1023// added to the query type, but that would require mutating type 1024// definitions, which would cause issues. 1025func getFieldDef(schema Schema, parentType *Object, fieldName string) *FieldDefinition { 1026 1027 if parentType == nil { 1028 return nil 1029 } 1030 1031 if fieldName == SchemaMetaFieldDef.Name && 1032 schema.QueryType() == parentType { 1033 return SchemaMetaFieldDef 1034 } 1035 if fieldName == TypeMetaFieldDef.Name && 1036 schema.QueryType() == parentType { 1037 return TypeMetaFieldDef 1038 } 1039 if fieldName == TypeNameMetaFieldDef.Name { 1040 return TypeNameMetaFieldDef 1041 } 1042 return parentType.Fields()[fieldName] 1043} 1044 1045// contains field information that will be placed in an ordered slice 1046type orderedField struct { 1047 responseName string 1048 fieldASTs []*ast.Field 1049} 1050 1051// orders fields from a fields map by location in the source 1052func orderedFields(fields map[string][]*ast.Field) []*orderedField { 1053 orderedFields := []*orderedField{} 1054 fieldMap := map[int]*orderedField{} 1055 startLocs := []int{} 1056 1057 for responseName, fieldASTs := range fields { 1058 // find the lowest location in the current fieldASTs 1059 lowest := -1 1060 for _, fieldAST := range fieldASTs { 1061 loc := fieldAST.GetLoc().Start 1062 if lowest == -1 || loc < lowest { 1063 lowest = loc 1064 } 1065 } 1066 startLocs = append(startLocs, lowest) 1067 fieldMap[lowest] = &orderedField{ 1068 responseName: responseName, 1069 fieldASTs: fieldASTs, 1070 } 1071 } 1072 1073 sort.Ints(startLocs) 1074 for _, startLoc := range startLocs { 1075 orderedFields = append(orderedFields, fieldMap[startLoc]) 1076 } 1077 1078 return orderedFields 1079} 1080