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