@@ -905,6 +905,83 @@ function completeValue(
905
905
) ;
906
906
}
907
907
908
+ async function completePromiseCatchingErrors (
909
+ exeContext : ExecutionContext ,
910
+ returnType : GraphQLOutputType ,
911
+ fieldNodes : ReadonlyArray < FieldNode > ,
912
+ info : GraphQLResolveInfo ,
913
+ path : Path ,
914
+ result : Promise < unknown > ,
915
+ asyncPayloadRecord ?: AsyncPayloadRecord ,
916
+ ) : Promise < unknown > {
917
+ try {
918
+ const resolved = await result ;
919
+ let completed = completeValue (
920
+ exeContext ,
921
+ returnType ,
922
+ fieldNodes ,
923
+ info ,
924
+ path ,
925
+ resolved ,
926
+ asyncPayloadRecord ,
927
+ ) ;
928
+ if ( isPromise ( completed ) ) {
929
+ // see: https://github.com/tc39/proposal-faster-promise-adoption
930
+ // it is faster to await a promise prior to returning it from an async function
931
+ completed = await completed ;
932
+ }
933
+ return completed ;
934
+ } catch ( rawError ) {
935
+ const errors = asyncPayloadRecord ?. errors ?? exeContext . errors ;
936
+ const error = locatedError ( rawError , fieldNodes , pathToArray ( path ) ) ;
937
+ const handledError = handleFieldError ( error , returnType , errors ) ;
938
+ filterSubsequentPayloads ( exeContext , path , asyncPayloadRecord ) ;
939
+ return handledError ;
940
+ }
941
+ }
942
+
943
+ function completeValueCatchingErrors (
944
+ exeContext : ExecutionContext ,
945
+ returnType : GraphQLOutputType ,
946
+ fieldNodes : ReadonlyArray < FieldNode > ,
947
+ info : GraphQLResolveInfo ,
948
+ path : Path ,
949
+ result : unknown ,
950
+ asyncPayloadRecord ?: AsyncPayloadRecord ,
951
+ ) : PromiseOrValue < unknown > {
952
+ let completedValue : PromiseOrValue < unknown > ;
953
+ try {
954
+ completedValue = completeValue (
955
+ exeContext ,
956
+ returnType ,
957
+ fieldNodes ,
958
+ info ,
959
+ path ,
960
+ result ,
961
+ asyncPayloadRecord ,
962
+ ) ;
963
+ } catch ( rawError ) {
964
+ const errors = asyncPayloadRecord ?. errors ?? exeContext . errors ;
965
+ const error = locatedError ( rawError , fieldNodes , pathToArray ( path ) ) ;
966
+ const handledError = handleFieldError ( error , returnType , errors ) ;
967
+ filterSubsequentPayloads ( exeContext , path , asyncPayloadRecord ) ;
968
+ return handledError ;
969
+ }
970
+
971
+ if ( isPromise ( completedValue ) ) {
972
+ // Note: we don't rely on a `catch` method, but we do expect "thenable"
973
+ // to take a second callback for the error case.
974
+ completedValue = completedValue . then ( undefined , ( rawError ) => {
975
+ const errors = asyncPayloadRecord ?. errors ?? exeContext . errors ;
976
+ const error = locatedError ( rawError , fieldNodes , pathToArray ( path ) ) ;
977
+ const handledError = handleFieldError ( error , returnType , errors ) ;
978
+ filterSubsequentPayloads ( exeContext , path , asyncPayloadRecord ) ;
979
+ return handledError ;
980
+ } ) ;
981
+ }
982
+ return completedValue ;
983
+ }
984
+
908
985
/**
909
986
* Returns an object containing the `@stream` arguments if a field should be
910
987
* streamed based on the experimental flag, stream directive present and
@@ -1867,69 +1944,17 @@ function executeStreamField(
1867
1944
parentContext,
1868
1945
exeContext,
1869
1946
} ) ;
1870
- let completedItem : PromiseOrValue < unknown > ;
1871
- try {
1872
- try {
1873
- if ( isPromise ( item ) ) {
1874
- completedItem = item . then ( ( resolved ) =>
1875
- completeValue (
1876
- exeContext ,
1877
- itemType ,
1878
- fieldNodes ,
1879
- info ,
1880
- itemPath ,
1881
- resolved ,
1882
- asyncPayloadRecord ,
1883
- ) ,
1884
- ) ;
1885
- } else {
1886
- completedItem = completeValue (
1887
- exeContext ,
1888
- itemType ,
1889
- fieldNodes ,
1890
- info ,
1891
- itemPath ,
1892
- item ,
1893
- asyncPayloadRecord ,
1894
- ) ;
1895
- }
1896
-
1897
- if ( isPromise ( completedItem ) ) {
1898
- // Note: we don't rely on a `catch` method, but we do expect "thenable"
1899
- // to take a second callback for the error case.
1900
- completedItem = completedItem . then ( undefined , ( rawError ) => {
1901
- const error = locatedError (
1902
- rawError ,
1903
- fieldNodes ,
1904
- pathToArray ( itemPath ) ,
1905
- ) ;
1906
- const handledError = handleFieldError (
1907
- error ,
1908
- itemType ,
1909
- asyncPayloadRecord . errors ,
1910
- ) ;
1911
- filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
1912
- return handledError ;
1913
- } ) ;
1914
- }
1915
- } catch ( rawError ) {
1916
- const error = locatedError ( rawError , fieldNodes , pathToArray ( itemPath ) ) ;
1917
- completedItem = handleFieldError (
1918
- error ,
1919
- itemType ,
1920
- asyncPayloadRecord . errors ,
1921
- ) ;
1922
- filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
1923
- }
1924
- } catch ( error ) {
1925
- asyncPayloadRecord . errors . push ( error ) ;
1926
- filterSubsequentPayloads ( exeContext , path , asyncPayloadRecord ) ;
1927
- asyncPayloadRecord . addItems ( null ) ;
1928
- return asyncPayloadRecord ;
1929
- }
1930
-
1931
1947
let completedItems : PromiseOrValue < Array < unknown > | null > ;
1932
- if ( isPromise ( completedItem ) ) {
1948
+ if ( isPromise ( item ) ) {
1949
+ const completedItem = completePromiseCatchingErrors (
1950
+ exeContext ,
1951
+ itemType ,
1952
+ fieldNodes ,
1953
+ info ,
1954
+ itemPath ,
1955
+ item ,
1956
+ asyncPayloadRecord ,
1957
+ ) ;
1933
1958
completedItems = completedItem . then (
1934
1959
( value ) => [ value ] ,
1935
1960
( error ) => {
@@ -1939,6 +1964,23 @@ function executeStreamField(
1939
1964
} ,
1940
1965
) ;
1941
1966
} else {
1967
+ let completedItem ;
1968
+ try {
1969
+ completedItem = completeValueCatchingErrors (
1970
+ exeContext ,
1971
+ itemType ,
1972
+ fieldNodes ,
1973
+ info ,
1974
+ itemPath ,
1975
+ item ,
1976
+ asyncPayloadRecord ,
1977
+ ) ;
1978
+ } catch ( error ) {
1979
+ asyncPayloadRecord . errors . push ( error ) ;
1980
+ filterSubsequentPayloads ( exeContext , path , asyncPayloadRecord ) ;
1981
+ asyncPayloadRecord . addItems ( null ) ;
1982
+ return asyncPayloadRecord ;
1983
+ }
1942
1984
completedItems = [ completedItem ] ;
1943
1985
}
1944
1986
@@ -1969,37 +2011,18 @@ async function executeStreamIteratorItem(
1969
2011
// don't continue if iterator throws
1970
2012
return { done : true , value } ;
1971
2013
}
1972
- let completedItem ;
1973
- try {
1974
- completedItem = completeValue (
2014
+ return {
2015
+ done : false ,
2016
+ value : completeValueCatchingErrors (
1975
2017
exeContext ,
1976
2018
itemType ,
1977
2019
fieldNodes ,
1978
2020
info ,
1979
2021
itemPath ,
1980
2022
item ,
1981
2023
asyncPayloadRecord ,
1982
- ) ;
1983
-
1984
- if ( isPromise ( completedItem ) ) {
1985
- completedItem = completedItem . then ( undefined , ( rawError ) => {
1986
- const error = locatedError ( rawError , fieldNodes , pathToArray ( itemPath ) ) ;
1987
- const handledError = handleFieldError (
1988
- error ,
1989
- itemType ,
1990
- asyncPayloadRecord . errors ,
1991
- ) ;
1992
- filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
1993
- return handledError ;
1994
- } ) ;
1995
- }
1996
- return { done : false , value : completedItem } ;
1997
- } catch ( rawError ) {
1998
- const error = locatedError ( rawError , fieldNodes , pathToArray ( itemPath ) ) ;
1999
- const value = handleFieldError ( error , itemType , asyncPayloadRecord . errors ) ;
2000
- filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
2001
- return { done : false , value } ;
2002
- }
2024
+ ) ,
2025
+ } ;
2003
2026
}
2004
2027
2005
2028
async function executeStreamIterator (
0 commit comments