@@ -224,6 +224,7 @@ type executeFieldsParams struct {
224
224
ParentType * Object
225
225
Source interface {}
226
226
Fields map [string ][]* ast.Field
227
+ Path * responsePath
227
228
}
228
229
229
230
// Implements the "Evaluating selection sets" section of the spec for "write" mode.
@@ -237,7 +238,8 @@ func executeFieldsSerially(p executeFieldsParams) *Result {
237
238
238
239
finalResults := make (map [string ]interface {}, len (p .Fields ))
239
240
for responseName , fieldASTs := range p .Fields {
240
- resolved , state := resolveField (p .ExecutionContext , p .ParentType , p .Source , fieldASTs )
241
+ fieldPath := p .Path .WithKey (responseName )
242
+ resolved , state := resolveField (p .ExecutionContext , p .ParentType , p .Source , fieldASTs , fieldPath )
241
243
if state .hasNoFieldDefs {
242
244
continue
243
245
}
@@ -261,7 +263,8 @@ func executeFields(p executeFieldsParams) *Result {
261
263
262
264
finalResults := make (map [string ]interface {}, len (p .Fields ))
263
265
for responseName , fieldASTs := range p .Fields {
264
- resolved , state := resolveField (p .ExecutionContext , p .ParentType , p .Source , fieldASTs )
266
+ fieldPath := p .Path .WithKey (responseName )
267
+ resolved , state := resolveField (p .ExecutionContext , p .ParentType , p .Source , fieldASTs , fieldPath )
265
268
if state .hasNoFieldDefs {
266
269
continue
267
270
}
@@ -459,31 +462,25 @@ type resolveFieldResultState struct {
459
462
hasNoFieldDefs bool
460
463
}
461
464
465
+ func handleFieldError (r interface {}, fieldNodes []ast.Node , path * responsePath , returnType Output , eCtx * executionContext ) {
466
+ err := NewLocatedErrorWithPath (r , fieldNodes , path .AsArray ())
467
+ // send panic upstream
468
+ if _ , ok := returnType .(* NonNull ); ok {
469
+ panic (err )
470
+ }
471
+ eCtx .Errors = append (eCtx .Errors , gqlerrors .FormatError (err ))
472
+ }
473
+
462
474
// Resolves the field on the given source object. In particular, this
463
475
// figures out the value that the field returns by calling its resolve function,
464
476
// then calls completeValue to complete promises, serialize scalars, or execute
465
477
// the sub-selection-set for objects.
466
- func resolveField (eCtx * executionContext , parentType * Object , source interface {}, fieldASTs []* ast.Field ) (result interface {}, resultState resolveFieldResultState ) {
478
+ func resolveField (eCtx * executionContext , parentType * Object , source interface {}, fieldASTs []* ast.Field , path * responsePath ) (result interface {}, resultState resolveFieldResultState ) {
467
479
// catch panic from resolveFn
468
480
var returnType Output
469
481
defer func () (interface {}, resolveFieldResultState ) {
470
482
if r := recover (); r != nil {
471
-
472
- var err error
473
- if r , ok := r .(string ); ok {
474
- err = NewLocatedError (
475
- fmt .Sprintf ("%v" , r ),
476
- FieldASTsToNodeASTs (fieldASTs ),
477
- )
478
- }
479
- if r , ok := r .(error ); ok {
480
- err = gqlerrors .FormatError (r )
481
- }
482
- // send panic upstream
483
- if _ , ok := returnType .(* NonNull ); ok {
484
- panic (gqlerrors .FormatError (err ))
485
- }
486
- eCtx .Errors = append (eCtx .Errors , gqlerrors .FormatError (err ))
483
+ handleFieldError (r , FieldASTsToNodeASTs (fieldASTs ), path , returnType , eCtx )
487
484
return result , resultState
488
485
}
489
486
return result , resultState
@@ -533,38 +530,32 @@ func resolveField(eCtx *executionContext, parentType *Object, source interface{}
533
530
})
534
531
535
532
if resolveFnError != nil {
536
- panic (gqlerrors . FormatError ( resolveFnError ) )
533
+ panic (resolveFnError )
537
534
}
538
535
539
- completed := completeValueCatchingError (eCtx , returnType , fieldASTs , info , result )
536
+ completed := completeValueCatchingError (eCtx , returnType , fieldASTs , info , path , result )
540
537
return completed , resultState
541
538
}
542
539
543
- func completeValueCatchingError (eCtx * executionContext , returnType Type , fieldASTs []* ast.Field , info ResolveInfo , result interface {}) (completed interface {}) {
540
+ func completeValueCatchingError (eCtx * executionContext , returnType Type , fieldASTs []* ast.Field , info ResolveInfo , path * responsePath , result interface {}) (completed interface {}) {
544
541
// catch panic
545
542
defer func () interface {} {
546
543
if r := recover (); r != nil {
547
- //send panic upstream
548
- if _ , ok := returnType .(* NonNull ); ok {
549
- panic (r )
550
- }
551
- if err , ok := r .(gqlerrors.FormattedError ); ok {
552
- eCtx .Errors = append (eCtx .Errors , err )
553
- }
544
+ handleFieldError (r , FieldASTsToNodeASTs (fieldASTs ), path , returnType , eCtx )
554
545
return completed
555
546
}
556
547
return completed
557
548
}()
558
549
559
550
if returnType , ok := returnType .(* NonNull ); ok {
560
- completed := completeValue (eCtx , returnType , fieldASTs , info , result )
551
+ completed := completeValue (eCtx , returnType , fieldASTs , info , path , result )
561
552
return completed
562
553
}
563
- completed = completeValue (eCtx , returnType , fieldASTs , info , result )
554
+ completed = completeValue (eCtx , returnType , fieldASTs , info , path , result )
564
555
return completed
565
556
}
566
557
567
- func completeValue (eCtx * executionContext , returnType Type , fieldASTs []* ast.Field , info ResolveInfo , result interface {}) interface {} {
558
+ func completeValue (eCtx * executionContext , returnType Type , fieldASTs []* ast.Field , info ResolveInfo , path * responsePath , result interface {}) interface {} {
568
559
569
560
resultVal := reflect .ValueOf (result )
570
561
for resultVal .IsValid () && resultVal .Type ().Kind () == reflect .Func {
@@ -580,11 +571,12 @@ func completeValue(eCtx *executionContext, returnType Type, fieldASTs []*ast.Fie
580
571
// If field type is NonNull, complete for inner type, and throw field error
581
572
// if result is null.
582
573
if returnType , ok := returnType .(* NonNull ); ok {
583
- completed := completeValue (eCtx , returnType .OfType , fieldASTs , info , result )
574
+ completed := completeValue (eCtx , returnType .OfType , fieldASTs , info , path , result )
584
575
if completed == nil {
585
- err := NewLocatedError (
576
+ err := NewLocatedErrorWithPath (
586
577
fmt .Sprintf ("Cannot return null for non-nullable field %v.%v." , info .ParentType , info .FieldName ),
587
578
FieldASTsToNodeASTs (fieldASTs ),
579
+ path .AsArray (),
588
580
)
589
581
panic (gqlerrors .FormatError (err ))
590
582
}
@@ -598,7 +590,7 @@ func completeValue(eCtx *executionContext, returnType Type, fieldASTs []*ast.Fie
598
590
599
591
// If field type is List, complete each item in the list with the inner type
600
592
if returnType , ok := returnType .(* List ); ok {
601
- return completeListValue (eCtx , returnType , fieldASTs , info , result )
593
+ return completeListValue (eCtx , returnType , fieldASTs , info , path , result )
602
594
}
603
595
604
596
// If field type is a leaf type, Scalar or Enum, serialize to a valid value,
@@ -613,15 +605,15 @@ func completeValue(eCtx *executionContext, returnType Type, fieldASTs []*ast.Fie
613
605
// If field type is an abstract type, Interface or Union, determine the
614
606
// runtime Object type and complete for that type.
615
607
if returnType , ok := returnType .(* Union ); ok {
616
- return completeAbstractValue (eCtx , returnType , fieldASTs , info , result )
608
+ return completeAbstractValue (eCtx , returnType , fieldASTs , info , path , result )
617
609
}
618
610
if returnType , ok := returnType .(* Interface ); ok {
619
- return completeAbstractValue (eCtx , returnType , fieldASTs , info , result )
611
+ return completeAbstractValue (eCtx , returnType , fieldASTs , info , path , result )
620
612
}
621
613
622
614
// If field type is Object, execute and complete all sub-selections.
623
615
if returnType , ok := returnType .(* Object ); ok {
624
- return completeObjectValue (eCtx , returnType , fieldASTs , info , result )
616
+ return completeObjectValue (eCtx , returnType , fieldASTs , info , path , result )
625
617
}
626
618
627
619
// Not reachable. All possible output types have been considered.
@@ -636,7 +628,7 @@ func completeValue(eCtx *executionContext, returnType Type, fieldASTs []*ast.Fie
636
628
637
629
// completeAbstractValue completes value of an Abstract type (Union / Interface) by determining the runtime type
638
630
// of that value, then completing based on that type.
639
- func completeAbstractValue (eCtx * executionContext , returnType Abstract , fieldASTs []* ast.Field , info ResolveInfo , result interface {}) interface {} {
631
+ func completeAbstractValue (eCtx * executionContext , returnType Abstract , fieldASTs []* ast.Field , info ResolveInfo , path * responsePath , result interface {}) interface {} {
640
632
641
633
var runtimeType * Object
642
634
@@ -669,11 +661,11 @@ func completeAbstractValue(eCtx *executionContext, returnType Abstract, fieldAST
669
661
))
670
662
}
671
663
672
- return completeObjectValue (eCtx , runtimeType , fieldASTs , info , result )
664
+ return completeObjectValue (eCtx , runtimeType , fieldASTs , info , path , result )
673
665
}
674
666
675
667
// completeObjectValue complete an Object value by executing all sub-selections.
676
- func completeObjectValue (eCtx * executionContext , returnType * Object , fieldASTs []* ast.Field , info ResolveInfo , result interface {}) interface {} {
668
+ func completeObjectValue (eCtx * executionContext , returnType * Object , fieldASTs []* ast.Field , info ResolveInfo , path * responsePath , result interface {}) interface {} {
677
669
678
670
// If there is an isTypeOf predicate function, call it with the
679
671
// current result. If isTypeOf returns false, then raise an error rather
@@ -715,6 +707,7 @@ func completeObjectValue(eCtx *executionContext, returnType *Object, fieldASTs [
715
707
ParentType : returnType ,
716
708
Source : result ,
717
709
Fields : subFieldASTs ,
710
+ Path : path ,
718
711
}
719
712
results := executeFields (executeFieldsParams )
720
713
@@ -732,7 +725,7 @@ func completeLeafValue(returnType Leaf, result interface{}) interface{} {
732
725
}
733
726
734
727
// completeListValue complete a list value by completing each item in the list with the inner type
735
- func completeListValue (eCtx * executionContext , returnType * List , fieldASTs []* ast.Field , info ResolveInfo , result interface {}) interface {} {
728
+ func completeListValue (eCtx * executionContext , returnType * List , fieldASTs []* ast.Field , info ResolveInfo , path * responsePath , result interface {}) interface {} {
736
729
resultVal := reflect .ValueOf (result )
737
730
parentTypeName := ""
738
731
if info .ParentType != nil {
@@ -751,7 +744,8 @@ func completeListValue(eCtx *executionContext, returnType *List, fieldASTs []*as
751
744
completedResults := make ([]interface {}, 0 , resultVal .Len ())
752
745
for i := 0 ; i < resultVal .Len (); i ++ {
753
746
val := resultVal .Index (i ).Interface ()
754
- completedItem := completeValueCatchingError (eCtx , itemType , fieldASTs , info , val )
747
+ fieldPath := path .WithKey (i )
748
+ completedItem := completeValueCatchingError (eCtx , itemType , fieldASTs , info , fieldPath , val )
755
749
completedResults = append (completedResults , completedItem )
756
750
}
757
751
return completedResults
0 commit comments