From e758f467b61eab65dcc15b4f950af5b107f7a5a3 Mon Sep 17 00:00:00 2001 From: Yaacov Rydzinski Date: Tue, 27 Dec 2022 16:57:39 +0200 Subject: [PATCH] remove extra ticks from executeStreamField by using custom completePromise helpers --- src/execution/__tests__/stream-test.ts | 10 -- src/execution/execute.ts | 132 ++++++++++++++++++------- 2 files changed, 94 insertions(+), 48 deletions(-) diff --git a/src/execution/__tests__/stream-test.ts b/src/execution/__tests__/stream-test.ts index aed5211ae1..f9dec10d72 100644 --- a/src/execution/__tests__/stream-test.ts +++ b/src/execution/__tests__/stream-test.ts @@ -531,11 +531,6 @@ describe('Execute: stream directive', () => { }, ], }, - ], - hasNext: true, - }, - { - incremental: [ { items: [{ name: 'Leia', id: '3' }], path: ['friendList', 2], @@ -984,11 +979,6 @@ describe('Execute: stream directive', () => { }, ], }, - ], - hasNext: true, - }, - { - incremental: [ { items: [{ nonNullName: 'Han' }], path: ['friendList', 2], diff --git a/src/execution/execute.ts b/src/execution/execute.ts index 052cb8da25..99e8ec6c9c 100644 --- a/src/execution/execute.ts +++ b/src/execution/execute.ts @@ -1798,6 +1798,78 @@ function executeDeferredFragment( asyncPayloadRecord.addData(promiseOrData); } +async function completedItemsFromPromisedItem( + exeContext: ExecutionContext, + itemType: GraphQLOutputType, + fieldNodes: ReadonlyArray, + info: GraphQLResolveInfo, + path: Path, + itemPath: Path, + item: Promise, + asyncPayloadRecord: AsyncPayloadRecord, +): Promise<[unknown] | null> { + try { + try { + const resolved = await item; + let completedItem = completeValue( + exeContext, + itemType, + fieldNodes, + info, + itemPath, + resolved, + asyncPayloadRecord, + ); + if (isPromise(completedItem)) { + completedItem = await completedItem; + } + return [completedItem]; + } catch (rawError) { + const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); + const handledError = handleFieldError( + error, + itemType, + asyncPayloadRecord.errors, + ); + filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); + return [handledError]; + } + } catch (error) { + asyncPayloadRecord.errors.push(error); + filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); + return null; + } +} + +async function completedItemsFromPromisedCompletedItem( + exeContext: ExecutionContext, + itemType: GraphQLOutputType, + fieldNodes: ReadonlyArray, + path: Path, + itemPath: Path, + completedItem: Promise, + asyncPayloadRecord: AsyncPayloadRecord, +): Promise<[unknown] | null> { + try { + try { + return [await completedItem]; + } catch (rawError) { + const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); + const handledError = handleFieldError( + error, + itemType, + asyncPayloadRecord.errors, + ); + filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); + return [handledError]; + } + } catch (error) { + asyncPayloadRecord.errors.push(error); + filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); + return null; + } +} + function executeStreamField( path: Path, itemPath: Path, @@ -1816,24 +1888,18 @@ function executeStreamField( exeContext, }); if (isPromise(item)) { - const completedItems = completePromisedValue( - exeContext, - itemType, - fieldNodes, - info, - itemPath, - item, - asyncPayloadRecord, - ).then( - (value) => [value], - (error) => { - asyncPayloadRecord.errors.push(error); - filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); - return null; - }, + asyncPayloadRecord.addItems( + completedItemsFromPromisedItem( + exeContext, + itemType, + fieldNodes, + info, + path, + itemPath, + item, + asyncPayloadRecord, + ), ); - - asyncPayloadRecord.addItems(completedItems); return asyncPayloadRecord; } @@ -1866,27 +1932,17 @@ function executeStreamField( } if (isPromise(completedItem)) { - const completedItems = completedItem - .then(undefined, (rawError) => { - const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); - const handledError = handleFieldError( - error, - itemType, - asyncPayloadRecord.errors, - ); - filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); - return handledError; - }) - .then( - (value) => [value], - (error) => { - asyncPayloadRecord.errors.push(error); - filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); - return null; - }, - ); - - asyncPayloadRecord.addItems(completedItems); + asyncPayloadRecord.addItems( + completedItemsFromPromisedCompletedItem( + exeContext, + itemType, + fieldNodes, + path, + itemPath, + completedItem, + asyncPayloadRecord, + ), + ); return asyncPayloadRecord; }