Skip to content

Commit 06e3645

Browse files
committed
return async iterables in the non incremental delivery case (#4144)
catching errors
1 parent c690f41 commit 06e3645

File tree

2 files changed

+73
-34
lines changed

2 files changed

+73
-34
lines changed

src/execution/__tests__/lists-test.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { expect } from 'chai';
1+
import { assert, expect } from 'chai';
22
import { describe, it } from 'mocha';
33

44
import { expectJSON } from '../../__testUtils__/expectJSON.js';
@@ -273,6 +273,34 @@ describe('Execute: Accepts async iterables as list value', () => {
273273
errors,
274274
});
275275
});
276+
277+
it('Returns async iterable when list nulls', async () => {
278+
const values = [1, null, 2];
279+
let i = 0;
280+
let returned = false;
281+
const listField = {
282+
[Symbol.asyncIterator]: () => ({
283+
next: () => Promise.resolve({ value: values[i++], done: false }),
284+
return: () => {
285+
returned = true;
286+
return Promise.resolve({ value: undefined, done: true });
287+
},
288+
}),
289+
};
290+
const errors = [
291+
{
292+
message: 'Cannot return null for non-nullable field Query.listField.',
293+
locations: [{ line: 1, column: 3 }],
294+
path: ['listField', 1],
295+
},
296+
];
297+
298+
expectJSON(await complete({ listField }, '[Int!]')).toDeepEqual({
299+
data: { listField: null },
300+
errors,
301+
});
302+
assert(returned);
303+
});
276304
});
277305

278306
describe('Execute: Handles list nullability', () => {

src/execution/execute.ts

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -818,48 +818,59 @@ async function completeAsyncIteratorValue(
818818
let containsPromise = false;
819819
const completedResults: Array<unknown> = [];
820820
let index = 0;
821-
// eslint-disable-next-line no-constant-condition
822-
while (true) {
823-
const itemPath = addPath(path, index, undefined);
824-
let iteration;
825-
try {
826-
// eslint-disable-next-line no-await-in-loop
827-
iteration = await asyncIterator.next();
828-
} catch (rawError) {
829-
throw locatedError(rawError, fieldGroup, pathToArray(path));
830-
}
821+
const earlyReturn = asyncIterator.return?.bind(asyncIterator);
822+
try {
823+
// eslint-disable-next-line no-constant-condition
824+
while (true) {
825+
const itemPath = addPath(path, index, undefined);
826+
let iteration;
827+
try {
828+
// eslint-disable-next-line no-await-in-loop
829+
iteration = await asyncIterator.next();
830+
} catch (rawError) {
831+
throw locatedError(rawError, fieldGroup, pathToArray(path));
832+
}
831833

832-
if (iteration.done) {
833-
break;
834-
}
834+
if (iteration.done) {
835+
break;
836+
}
835837

836-
const item = iteration.value;
837-
if (isPromise(item)) {
838-
completedResults.push(
839-
completePromisedListItemValue(
838+
const item = iteration.value;
839+
if (isPromise(item)) {
840+
completedResults.push(
841+
completePromisedListItemValue(
842+
item,
843+
exeContext,
844+
itemType,
845+
fieldGroup,
846+
info,
847+
itemPath,
848+
),
849+
);
850+
containsPromise = true;
851+
} else if (
852+
completeListItemValue(
840853
item,
854+
completedResults,
841855
exeContext,
842856
itemType,
843857
fieldGroup,
844858
info,
845859
itemPath,
846-
),
847-
);
848-
containsPromise = true;
849-
} else if (
850-
completeListItemValue(
851-
item,
852-
completedResults,
853-
exeContext,
854-
itemType,
855-
fieldGroup,
856-
info,
857-
itemPath,
858-
)
859-
) {
860-
containsPromise = true;
860+
)
861+
) {
862+
containsPromise = true;
863+
}
864+
index++;
861865
}
862-
index += 1;
866+
} catch (error) {
867+
if (earlyReturn !== undefined) {
868+
earlyReturn().catch(() => {
869+
/* c8 ignore next 1 */
870+
// ignore error
871+
});
872+
}
873+
throw error;
863874
}
864875
return containsPromise ? Promise.all(completedResults) : completedResults;
865876
}

0 commit comments

Comments
 (0)