@@ -908,6 +908,83 @@ function completeValue(
908
908
) ;
909
909
}
910
910
911
+ async function completePromiseCatchingErrors (
912
+ exeContext : ExecutionContext ,
913
+ returnType : GraphQLOutputType ,
914
+ fieldNodes : ReadonlyArray < FieldNode > ,
915
+ info : GraphQLResolveInfo ,
916
+ path : Path ,
917
+ result : Promise < unknown > ,
918
+ asyncPayloadRecord ?: AsyncPayloadRecord ,
919
+ ) : Promise < unknown > {
920
+ try {
921
+ const resolved = await result ;
922
+ let completed = completeValue (
923
+ exeContext ,
924
+ returnType ,
925
+ fieldNodes ,
926
+ info ,
927
+ path ,
928
+ resolved ,
929
+ asyncPayloadRecord ,
930
+ ) ;
931
+ if ( isPromise ( completed ) ) {
932
+ // see: https://github.com/tc39/proposal-faster-promise-adoption
933
+ // it is faster to await a promise prior to returning it from an async function
934
+ completed = await completed ;
935
+ }
936
+ return completed ;
937
+ } catch ( rawError ) {
938
+ const errors = asyncPayloadRecord ?. errors ?? exeContext . errors ;
939
+ const error = locatedError ( rawError , fieldNodes , pathToArray ( path ) ) ;
940
+ const handledError = handleFieldError ( error , returnType , errors ) ;
941
+ filterSubsequentPayloads ( exeContext , path , asyncPayloadRecord ) ;
942
+ return handledError ;
943
+ }
944
+ }
945
+
946
+ function completeValueCatchingErrors (
947
+ exeContext : ExecutionContext ,
948
+ returnType : GraphQLOutputType ,
949
+ fieldNodes : ReadonlyArray < FieldNode > ,
950
+ info : GraphQLResolveInfo ,
951
+ path : Path ,
952
+ result : unknown ,
953
+ asyncPayloadRecord ?: AsyncPayloadRecord ,
954
+ ) : PromiseOrValue < unknown > {
955
+ let completedValue : PromiseOrValue < unknown > ;
956
+ try {
957
+ completedValue = completeValue (
958
+ exeContext ,
959
+ returnType ,
960
+ fieldNodes ,
961
+ info ,
962
+ path ,
963
+ result ,
964
+ asyncPayloadRecord ,
965
+ ) ;
966
+ } catch ( rawError ) {
967
+ const errors = asyncPayloadRecord ?. errors ?? exeContext . errors ;
968
+ const error = locatedError ( rawError , fieldNodes , pathToArray ( path ) ) ;
969
+ const handledError = handleFieldError ( error , returnType , errors ) ;
970
+ filterSubsequentPayloads ( exeContext , path , asyncPayloadRecord ) ;
971
+ return handledError ;
972
+ }
973
+
974
+ if ( isPromise ( completedValue ) ) {
975
+ // Note: we don't rely on a `catch` method, but we do expect "thenable"
976
+ // to take a second callback for the error case.
977
+ completedValue = completedValue . then ( undefined , ( rawError ) => {
978
+ const errors = asyncPayloadRecord ?. errors ?? exeContext . errors ;
979
+ const error = locatedError ( rawError , fieldNodes , pathToArray ( path ) ) ;
980
+ const handledError = handleFieldError ( error , returnType , errors ) ;
981
+ filterSubsequentPayloads ( exeContext , path , asyncPayloadRecord ) ;
982
+ return handledError ;
983
+ } ) ;
984
+ }
985
+ return completedValue ;
986
+ }
987
+
911
988
/**
912
989
* Returns an object containing the `@stream` arguments if a field should be
913
990
* streamed based on the experimental flag, stream directive present and
@@ -1925,69 +2002,17 @@ function executeStreamIteratorItem(
1925
2002
exeContext,
1926
2003
streamContext,
1927
2004
} ) ;
1928
- let completedItem : PromiseOrValue < unknown > ;
1929
- try {
1930
- try {
1931
- if ( isPromise ( item ) ) {
1932
- completedItem = item . then ( ( resolved ) =>
1933
- completeValue (
1934
- exeContext ,
1935
- itemType ,
1936
- fieldNodes ,
1937
- info ,
1938
- itemPath ,
1939
- resolved ,
1940
- asyncPayloadRecord ,
1941
- ) ,
1942
- ) ;
1943
- } else {
1944
- completedItem = completeValue (
1945
- exeContext ,
1946
- itemType ,
1947
- fieldNodes ,
1948
- info ,
1949
- itemPath ,
1950
- item ,
1951
- asyncPayloadRecord ,
1952
- ) ;
1953
- }
1954
-
1955
- if ( isPromise ( completedItem ) ) {
1956
- // Note: we don't rely on a `catch` method, but we do expect "thenable"
1957
- // to take a second callback for the error case.
1958
- completedItem = completedItem . then ( undefined , ( rawError ) => {
1959
- const error = locatedError (
1960
- rawError ,
1961
- fieldNodes ,
1962
- pathToArray ( itemPath ) ,
1963
- ) ;
1964
- const handledError = handleFieldError (
1965
- error ,
1966
- itemType ,
1967
- asyncPayloadRecord . errors ,
1968
- ) ;
1969
- filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
1970
- return handledError ;
1971
- } ) ;
1972
- }
1973
- } catch ( rawError ) {
1974
- const error = locatedError ( rawError , fieldNodes , pathToArray ( itemPath ) ) ;
1975
- completedItem = handleFieldError (
1976
- error ,
1977
- itemType ,
1978
- asyncPayloadRecord . errors ,
1979
- ) ;
1980
- filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
1981
- }
1982
- } catch ( error ) {
1983
- asyncPayloadRecord . errors . push ( error ) ;
1984
- filterSubsequentPayloads ( exeContext , path , asyncPayloadRecord ) ;
1985
- asyncPayloadRecord . addItems ( null ) ;
1986
- return asyncPayloadRecord ;
1987
- }
1988
-
1989
2005
let completedItems : PromiseOrValue < Array < unknown > | null > ;
1990
- if ( isPromise ( completedItem ) ) {
2006
+ if ( isPromise ( item ) ) {
2007
+ const completedItem = completePromiseCatchingErrors (
2008
+ exeContext ,
2009
+ itemType ,
2010
+ fieldNodes ,
2011
+ info ,
2012
+ itemPath ,
2013
+ item ,
2014
+ asyncPayloadRecord ,
2015
+ ) ;
1991
2016
completedItems = completedItem . then (
1992
2017
( value ) => [ value ] ,
1993
2018
( error ) => {
@@ -1997,6 +2022,23 @@ function executeStreamIteratorItem(
1997
2022
} ,
1998
2023
) ;
1999
2024
} else {
2025
+ let completedItem ;
2026
+ try {
2027
+ completedItem = completeValueCatchingErrors (
2028
+ exeContext ,
2029
+ itemType ,
2030
+ fieldNodes ,
2031
+ info ,
2032
+ itemPath ,
2033
+ item ,
2034
+ asyncPayloadRecord ,
2035
+ ) ;
2036
+ } catch ( error ) {
2037
+ asyncPayloadRecord . errors . push ( error ) ;
2038
+ filterSubsequentPayloads ( exeContext , path , asyncPayloadRecord ) ;
2039
+ asyncPayloadRecord . addItems ( null ) ;
2040
+ return asyncPayloadRecord ;
2041
+ }
2000
2042
completedItems = [ completedItem ] ;
2001
2043
}
2002
2044
@@ -2027,37 +2069,18 @@ async function executeStreamAsyncIteratorItem(
2027
2069
// don't continue if iterator throws
2028
2070
return { done : true , value } ;
2029
2071
}
2030
- let completedItem ;
2031
- try {
2032
- completedItem = completeValue (
2072
+ return {
2073
+ done : false ,
2074
+ value : completeValueCatchingErrors (
2033
2075
exeContext ,
2034
2076
itemType ,
2035
2077
fieldNodes ,
2036
2078
info ,
2037
2079
itemPath ,
2038
2080
item ,
2039
2081
asyncPayloadRecord ,
2040
- ) ;
2041
-
2042
- if ( isPromise ( completedItem ) ) {
2043
- completedItem = completedItem . then ( undefined , ( rawError ) => {
2044
- const error = locatedError ( rawError , fieldNodes , pathToArray ( itemPath ) ) ;
2045
- const handledError = handleFieldError (
2046
- error ,
2047
- itemType ,
2048
- asyncPayloadRecord . errors ,
2049
- ) ;
2050
- filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
2051
- return handledError ;
2052
- } ) ;
2053
- }
2054
- return { done : false , value : completedItem } ;
2055
- } catch ( rawError ) {
2056
- const error = locatedError ( rawError , fieldNodes , pathToArray ( itemPath ) ) ;
2057
- const value = handleFieldError ( error , itemType , asyncPayloadRecord . errors ) ;
2058
- filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
2059
- return { done : false , value } ;
2060
- }
2082
+ ) ,
2083
+ } ;
2061
2084
}
2062
2085
2063
2086
async function executeStreamAsyncIterator (
0 commit comments