@@ -1018,13 +1018,13 @@ function getStreamUsage(
10181018 * Complete a async iterator value by completing the result and calling
10191019 * recursively until all the results are completed.
10201020 */
1021- async function completeAsyncIteratorValue (
1021+ async function completeAsyncIterable (
10221022 exeContext : ExecutionContext ,
10231023 itemType : GraphQLOutputType ,
10241024 fieldDetailsList : FieldDetailsList ,
10251025 info : GraphQLResolveInfo ,
10261026 path : Path ,
1027- asyncIterator : AsyncIterator < unknown > ,
1027+ items : AsyncIterable < unknown > ,
10281028 incrementalContext : IncrementalContext | undefined ,
10291029 deferMap : ReadonlyMap < DeferUsage , DeferredFragmentRecord > | undefined ,
10301030) : Promise < GraphQLWrappedResult < ReadonlyArray < unknown > > > {
@@ -1035,6 +1035,7 @@ async function completeAsyncIteratorValue(
10351035 newDeferredFragmentRecords : undefined ,
10361036 incrementalDataRecords : undefined ,
10371037 } ;
1038+ const asyncIterator = items [ Symbol . asyncIterator ] ( ) ;
10381039 let index = 0 ;
10391040 const streamUsage = getStreamUsage (
10401041 exeContext . validatedExecutionArgs ,
@@ -1131,10 +1132,7 @@ async function completeAsyncIteratorValue(
11311132 index ++ ;
11321133 }
11331134 } catch ( error ) {
1134- asyncIterator . return ?.( ) . catch ( ( ) => {
1135- /* c8 ignore next 1 */
1136- // ignore error
1137- } ) ;
1135+ returnIteratorIgnoringErrors ( asyncIterator ) ;
11381136 throw error ;
11391137 }
11401138
@@ -1169,15 +1167,14 @@ function completeListValue(
11691167 const maybeCancellableIterable = abortSignalListener
11701168 ? cancellableIterable ( result , abortSignalListener )
11711169 : result ;
1172- const asyncIterator = maybeCancellableIterable [ Symbol . asyncIterator ] ( ) ;
11731170
1174- return completeAsyncIteratorValue (
1171+ return completeAsyncIterable (
11751172 exeContext ,
11761173 itemType ,
11771174 fieldDetailsList ,
11781175 info ,
11791176 path ,
1180- asyncIterator ,
1177+ maybeCancellableIterable ,
11811178 incrementalContext ,
11821179 deferMap ,
11831180 ) ;
@@ -1211,8 +1208,6 @@ function completeIterableValue(
12111208 incrementalContext : IncrementalContext | undefined ,
12121209 deferMap : ReadonlyMap < DeferUsage , DeferredFragmentRecord > | undefined ,
12131210) : PromiseOrValue < GraphQLWrappedResult < ReadonlyArray < unknown > > > {
1214- // This is specified as a simple map, however we're optimizing the path
1215- // where the list contains no Promises by avoiding creating another Promise.
12161211 let containsPromise = false ;
12171212 const completedResults : Array < unknown > = [ ] ;
12181213 const graphqlWrappedResult : GraphQLWrappedResult < Array < unknown > > = {
@@ -1227,38 +1222,62 @@ function completeIterableValue(
12271222 path ,
12281223 ) ;
12291224 const iterator = items [ Symbol . iterator ] ( ) ;
1230- let iteration = iterator . next ( ) ;
1231- while ( ! iteration . done ) {
1232- const item = iteration . value ;
1225+ try {
1226+ while ( true ) {
1227+ if ( streamUsage && index >= streamUsage . initialCount ) {
1228+ const iteration = iterator . next ( ) ;
1229+ if ( ! iteration . done ) {
1230+ const item = iteration . value ;
1231+ const syncStreamRecord : StreamRecord = {
1232+ label : streamUsage . label ,
1233+ path,
1234+ streamItemQueue : buildSyncStreamItemQueue (
1235+ item ,
1236+ index ,
1237+ path ,
1238+ iterator ,
1239+ exeContext ,
1240+ streamUsage . fieldDetailsList ,
1241+ info ,
1242+ itemType ,
1243+ ) ,
1244+ } ;
12331245
1234- if ( streamUsage && index >= streamUsage . initialCount ) {
1235- const syncStreamRecord : StreamRecord = {
1236- label : streamUsage . label ,
1237- path,
1238- streamItemQueue : buildSyncStreamItemQueue (
1239- item ,
1240- index ,
1241- path ,
1242- iterator ,
1243- exeContext ,
1244- streamUsage . fieldDetailsList ,
1245- info ,
1246- itemType ,
1247- ) ,
1248- } ;
1246+ addIncrementalDataRecords ( graphqlWrappedResult , [ syncStreamRecord ] ) ;
1247+ }
1248+ break ;
1249+ }
12491250
1250- addIncrementalDataRecords ( graphqlWrappedResult , [ syncStreamRecord ] ) ;
1251- break ;
1252- }
1251+ const iteration = iterator . next ( ) ;
1252+ if ( iteration . done ) {
1253+ break ;
1254+ }
12531255
1254- // No need to modify the info object containing the path,
1255- // since from here on it is not ever accessed by resolver functions.
1256- const itemPath = addPath ( path , index , undefined ) ;
1256+ const item = iteration . value ;
12571257
1258- if ( isPromise ( item ) ) {
1259- completedResults . push (
1260- completePromisedListItemValue (
1258+ // No need to modify the info object containing the path,
1259+ // since from here on it is not ever accessed by resolver functions.
1260+ const itemPath = addPath ( path , index , undefined ) ;
1261+
1262+ if ( isPromise ( item ) ) {
1263+ completedResults . push (
1264+ completePromisedListItemValue (
1265+ item ,
1266+ graphqlWrappedResult ,
1267+ exeContext ,
1268+ itemType ,
1269+ fieldDetailsList ,
1270+ info ,
1271+ itemPath ,
1272+ incrementalContext ,
1273+ deferMap ,
1274+ ) ,
1275+ ) ;
1276+ containsPromise = true ;
1277+ } else if (
1278+ completeListItemValue (
12611279 item ,
1280+ completedResults ,
12621281 graphqlWrappedResult ,
12631282 exeContext ,
12641283 itemType ,
@@ -1267,28 +1286,15 @@ function completeIterableValue(
12671286 itemPath ,
12681287 incrementalContext ,
12691288 deferMap ,
1270- ) ,
1271- ) ;
1272- containsPromise = true ;
1273- } else if (
1274- completeListItemValue (
1275- item ,
1276- completedResults ,
1277- graphqlWrappedResult ,
1278- exeContext ,
1279- itemType ,
1280- fieldDetailsList ,
1281- info ,
1282- itemPath ,
1283- incrementalContext ,
1284- deferMap ,
1285- )
1286- ) {
1287- containsPromise = true ;
1289+ )
1290+ ) {
1291+ containsPromise = true ;
1292+ }
1293+ index ++ ;
12881294 }
1289- index ++ ;
1290-
1291- iteration = iterator . next ( ) ;
1295+ } catch ( error ) {
1296+ returnIteratorIgnoringErrors ( iterator ) ;
1297+ throw error ;
12921298 }
12931299
12941300 return containsPromise
@@ -2442,3 +2448,18 @@ function buildStreamItemResult(
24422448 incrementalDataRecords,
24432449 } ;
24442450}
2451+
2452+ function returnIteratorIgnoringErrors (
2453+ iterator : Iterator < unknown > | AsyncIterator < unknown > ,
2454+ ) {
2455+ try {
2456+ const result = iterator . return ?.( ) ;
2457+ if ( isPromise ( result ) ) {
2458+ result . catch ( ( ) => {
2459+ // ignore errors
2460+ } ) ;
2461+ }
2462+ } catch {
2463+ // ignore errors
2464+ }
2465+ }
0 commit comments