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