@@ -641,8 +641,9 @@ function executeFields(
641
641
/**
642
642
* Implements the "Executing fields" section of the spec
643
643
* In particular, this function figures out the value that the field returns by
644
- * calling its resolve function, then calls completeValue to complete promises,
645
- * serialize scalars, or execute the sub-selection-set for objects.
644
+ * calling its resolve function, checks for promises, and then serializes leaf
645
+ * values or calls completeNonLeafValue to execute the sub-selection-set for
646
+ * objects and/or complete lists as necessary.
646
647
*/
647
648
function executeField (
648
649
exeContext : ExecutionContext ,
@@ -699,9 +700,32 @@ function executeField(
699
700
) ;
700
701
}
701
702
702
- const completed = completeValue (
703
+ if ( result instanceof Error ) {
704
+ throw result ;
705
+ }
706
+
707
+ let nullableType : GraphQLNullableOutputType ;
708
+ if ( isNonNullType ( returnType ) ) {
709
+ if ( result == null ) {
710
+ throw new Error (
711
+ `Cannot return null for non-nullable field ${ info . parentType . name } .${ info . fieldName } .` ,
712
+ ) ;
713
+ }
714
+ nullableType = returnType . ofType ;
715
+ } else {
716
+ if ( result == null ) {
717
+ return null ;
718
+ }
719
+ nullableType = returnType ;
720
+ }
721
+
722
+ if ( isLeafType ( nullableType ) ) {
723
+ return completeLeafValue ( nullableType , result ) ;
724
+ }
725
+
726
+ const completed = completeNonLeafValue (
703
727
exeContext ,
704
- returnType ,
728
+ nullableType ,
705
729
fieldGroup ,
706
730
info ,
707
731
path ,
@@ -789,57 +813,27 @@ function handleFieldError(
789
813
}
790
814
791
815
/**
792
- * Implements the instructions for completeValue as defined in the
816
+ * Implements the instructions for completing non-leaf values as defined in the
793
817
* "Value Completion" section of the spec.
794
818
*
795
- * If the field type is Non-Null, then this recursively completes the value
796
- * for the inner type. It throws a field error if that completion returns null,
797
- * as per the "Nullability" section of the spec.
798
- *
799
819
* If the field type is a List, then this recursively completes the value
800
820
* for the inner type on each item in the list.
801
821
*
802
- * If the field type is a Scalar or Enum, ensures the completed value is a legal
803
- * value of the type by calling the `serialize` method of GraphQL type
804
- * definition.
805
- *
806
822
* If the field is an abstract type, determine the runtime type of the value
807
823
* and then complete based on that type
808
824
*
809
825
* Otherwise, the field type expects a sub-selection set, and will complete the
810
826
* value by executing all sub-selections.
811
827
*/
812
- function completeValue (
828
+ function completeNonLeafValue (
813
829
exeContext : ExecutionContext ,
814
- returnType : GraphQLOutputType ,
830
+ nullableType : GraphQLNullableOutputType ,
815
831
fieldGroup : FieldGroup ,
816
832
info : GraphQLResolveInfo ,
817
833
path : Path ,
818
834
result : unknown ,
819
835
incrementalDataRecord : IncrementalDataRecord ,
820
836
) : PromiseOrValue < unknown > {
821
- // If result is an Error, throw a located error.
822
- if ( result instanceof Error ) {
823
- throw result ;
824
- }
825
-
826
- let nullableType : GraphQLNullableOutputType ;
827
- if ( isNonNullType ( returnType ) ) {
828
- // If result value is null or undefined then throw an error.
829
- if ( result == null ) {
830
- throw new Error (
831
- `Cannot return null for non-nullable field ${ info . parentType . name } .${ info . fieldName } .` ,
832
- ) ;
833
- }
834
- nullableType = returnType . ofType ;
835
- } else {
836
- // If result value is null or undefined then return null.
837
- if ( result == null ) {
838
- return null ;
839
- }
840
- nullableType = returnType ;
841
- }
842
-
843
837
// If field type is List, complete each item in the list with the inner type
844
838
if ( isListType ( nullableType ) ) {
845
839
return completeListValue (
@@ -853,12 +847,6 @@ function completeValue(
853
847
) ;
854
848
}
855
849
856
- // If field type is a leaf type, Scalar or Enum, serialize to a valid value,
857
- // returning null if serialization is not possible.
858
- if ( isLeafType ( nullableType ) ) {
859
- return completeLeafValue ( nullableType , result ) ;
860
- }
861
-
862
850
// If field type is an abstract type, Interface or Union, determine the
863
851
// runtime Object type and complete for that type.
864
852
if ( isAbstractType ( nullableType ) ) {
@@ -904,9 +892,33 @@ async function completePromisedValue(
904
892
) : Promise < unknown > {
905
893
try {
906
894
const resolved = await result ;
907
- let completed = completeValue (
895
+
896
+ if ( resolved instanceof Error ) {
897
+ throw resolved ;
898
+ }
899
+
900
+ let nullableType : GraphQLNullableOutputType ;
901
+ if ( isNonNullType ( returnType ) ) {
902
+ if ( resolved == null ) {
903
+ throw new Error (
904
+ `Cannot return null for non-nullable field ${ info . parentType . name } .${ info . fieldName } .` ,
905
+ ) ;
906
+ }
907
+ nullableType = returnType . ofType ;
908
+ } else {
909
+ if ( resolved == null ) {
910
+ return null ;
911
+ }
912
+ nullableType = returnType ;
913
+ }
914
+
915
+ if ( isLeafType ( nullableType ) ) {
916
+ return completeLeafValue ( nullableType , resolved ) ;
917
+ }
918
+
919
+ let completed = completeNonLeafValue (
908
920
exeContext ,
909
- returnType ,
921
+ nullableType ,
910
922
fieldGroup ,
911
923
info ,
912
924
path ,
@@ -1179,9 +1191,34 @@ function completeListItemValue(
1179
1191
}
1180
1192
1181
1193
try {
1182
- const completedItem = completeValue (
1194
+ if ( item instanceof Error ) {
1195
+ throw item ;
1196
+ }
1197
+
1198
+ let nullableType : GraphQLNullableOutputType ;
1199
+ if ( isNonNullType ( itemType ) ) {
1200
+ if ( item == null ) {
1201
+ throw new Error (
1202
+ `Cannot return null for non-nullable field ${ info . parentType . name } .${ info . fieldName } .` ,
1203
+ ) ;
1204
+ }
1205
+ nullableType = itemType . ofType ;
1206
+ } else {
1207
+ if ( item == null ) {
1208
+ completedResults . push ( null ) ;
1209
+ return false ;
1210
+ }
1211
+ nullableType = itemType ;
1212
+ }
1213
+
1214
+ if ( isLeafType ( nullableType ) ) {
1215
+ completedResults . push ( completeLeafValue ( nullableType , item ) ) ;
1216
+ return false ;
1217
+ }
1218
+
1219
+ const completedItem = completeNonLeafValue (
1183
1220
exeContext ,
1184
- itemType ,
1221
+ nullableType ,
1185
1222
fieldGroup ,
1186
1223
info ,
1187
1224
itemPath ,
@@ -1852,9 +1889,35 @@ function executeStreamField(
1852
1889
let completedItem : PromiseOrValue < unknown > ;
1853
1890
try {
1854
1891
try {
1855
- completedItem = completeValue (
1892
+ let nullableType : GraphQLNullableOutputType ;
1893
+ if ( isNonNullType ( itemType ) ) {
1894
+ if ( item == null ) {
1895
+ throw new Error (
1896
+ `Cannot return null for non-nullable field ${ info . parentType . name } .${ info . fieldName } .` ,
1897
+ ) ;
1898
+ }
1899
+ nullableType = itemType . ofType ;
1900
+ } else {
1901
+ if ( item == null ) {
1902
+ incrementalPublisher . completeStreamItemsRecord (
1903
+ incrementalDataRecord ,
1904
+ [ null ] ,
1905
+ ) ;
1906
+ return incrementalDataRecord ;
1907
+ }
1908
+ nullableType = itemType ;
1909
+ }
1910
+
1911
+ if ( isLeafType ( nullableType ) ) {
1912
+ incrementalPublisher . completeStreamItemsRecord ( incrementalDataRecord , [
1913
+ completeLeafValue ( nullableType , item ) ,
1914
+ ] ) ;
1915
+ return incrementalDataRecord ;
1916
+ }
1917
+
1918
+ completedItem = completeNonLeafValue (
1856
1919
exeContext ,
1857
- itemType ,
1920
+ nullableType ,
1858
1921
fieldGroup ,
1859
1922
info ,
1860
1923
itemPath ,
@@ -1945,9 +2008,28 @@ async function executeStreamAsyncIteratorItem(
1945
2008
}
1946
2009
let completedItem ;
1947
2010
try {
1948
- completedItem = completeValue (
2011
+ let nullableType : GraphQLNullableOutputType ;
2012
+ if ( isNonNullType ( itemType ) ) {
2013
+ if ( item == null ) {
2014
+ throw new Error (
2015
+ `Cannot return null for non-nullable field ${ info . parentType . name } .${ info . fieldName } .` ,
2016
+ ) ;
2017
+ }
2018
+ nullableType = itemType . ofType ;
2019
+ } else {
2020
+ if ( item == null ) {
2021
+ return { done : false , value : null } ;
2022
+ }
2023
+ nullableType = itemType ;
2024
+ }
2025
+
2026
+ if ( isLeafType ( nullableType ) ) {
2027
+ return { done : false , value : completeLeafValue ( nullableType , item ) } ;
2028
+ }
2029
+
2030
+ completedItem = completeNonLeafValue (
1949
2031
exeContext ,
1950
- itemType ,
2032
+ nullableType ,
1951
2033
fieldGroup ,
1952
2034
info ,
1953
2035
itemPath ,
0 commit comments