Skip to content

Commit

Permalink
remove additional tick from executeStreamIterator
Browse files Browse the repository at this point in the history
  • Loading branch information
yaacovCR committed Dec 13, 2022
1 parent 0e9a32f commit dc58257
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 93 deletions.
42 changes: 13 additions & 29 deletions src/execution/__tests__/stream-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -628,9 +628,6 @@ describe('Execute: stream directive', () => {
path: ['friendList', 2],
},
],
hasNext: true,
},
{
hasNext: false,
},
]);
Expand Down Expand Up @@ -670,7 +667,7 @@ describe('Execute: stream directive', () => {
}
}
`);
const result = await completeAsync(document, 3, {
const result = await completeAsync(document, 2, {
async *friendList() {
yield await Promise.resolve(friends[0]);
yield await Promise.resolve(friends[1]);
Expand Down Expand Up @@ -699,10 +696,9 @@ describe('Execute: stream directive', () => {
path: ['friendList', 2],
},
],
hasNext: true,
hasNext: false,
},
},
{ done: false, value: { hasNext: false } },
{ done: true, value: undefined },
]);
});
Expand Down Expand Up @@ -1164,9 +1160,6 @@ describe('Execute: stream directive', () => {
],
},
],
hasNext: true,
},
{
hasNext: false,
},
]);
Expand All @@ -1190,25 +1183,19 @@ describe('Execute: stream directive', () => {
} /* c8 ignore stop */,
},
});
expectJSON(result).toDeepEqual([
{
errors: [
{
message:
'Cannot return null for non-nullable field NestedObject.nonNullScalarField.',
locations: [{ line: 4, column: 11 }],
path: ['nestedObject', 'nonNullScalarField'],
},
],
data: {
nestedObject: null,
expectJSON(result).toDeepEqual({
errors: [
{
message:
'Cannot return null for non-nullable field NestedObject.nonNullScalarField.',
locations: [{ line: 4, column: 11 }],
path: ['nestedObject', 'nonNullScalarField'],
},
hasNext: true,
},
{
hasNext: false,
],
data: {
nestedObject: null,
},
]);
});
});
it('Filters payloads that are nulled by a later synchronous error', async () => {
const document = parse(`
Expand Down Expand Up @@ -1349,9 +1336,6 @@ describe('Execute: stream directive', () => {
],
},
],
hasNext: true,
},
{
hasNext: false,
},
]);
Expand Down
119 changes: 55 additions & 64 deletions src/execution/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2081,16 +2081,61 @@ async function executeStreamIterator(

let iteration;
try {
// eslint-disable-next-line no-await-in-loop
iteration = await executeStreamIteratorItem(
iterator,
exeContext,
fieldNodes,
info,
itemType,
asyncPayloadRecord,
itemPath,
);
try {
// eslint-disable-next-line no-await-in-loop
const { value, done } = await iterator.next();
if (done) {
asyncPayloadRecord.setIsCompletedIterator();
iteration = { done, value: undefined };
} else {
let completedItem;
try {
completedItem = completeValue(
exeContext,
itemType,
fieldNodes,
info,
itemPath,
value,
asyncPayloadRecord,
);

if (isPromise(completedItem)) {
completedItem = handleAsyncCompletionError(
completedItem,
exeContext,
itemType,
fieldNodes,
itemPath,
asyncPayloadRecord,
);
}
iteration = { done: false, value: completedItem };
} catch (rawError) {
const error = locatedError(
rawError,
fieldNodes,
pathToArray(itemPath),
);
const handledError = handleFieldError(
error,
itemType,
asyncPayloadRecord.errors,
);
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
iteration = { done: false, value: handledError };
}
}
} catch (rawError) {
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath));
const handledError = handleFieldError(
error,
itemType,
asyncPayloadRecord.errors,
);
// don't continue if iterator throws
iteration = { done: true, value: handledError };
}
} catch (error) {
asyncPayloadRecord.errors.push(error);
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord);
Expand Down Expand Up @@ -2132,60 +2177,6 @@ async function executeStreamIterator(
}
}

async function executeStreamIteratorItem(
iterator: AsyncIterator<unknown>,
exeContext: ExecutionContext,
fieldNodes: ReadonlyArray<FieldNode>,
info: GraphQLResolveInfo,
itemType: GraphQLOutputType,
asyncPayloadRecord: StreamRecord,
itemPath: Path,
): Promise<IteratorResult<unknown>> {
let item;
try {
const { value, done } = await iterator.next();
if (done) {
asyncPayloadRecord.setIsCompletedIterator();
return { done, value: undefined };
}
item = value;
} catch (rawError) {
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath));
const value = handleFieldError(error, itemType, asyncPayloadRecord.errors);
// don't continue if iterator throws
return { done: true, value };
}
let completedItem;
try {
completedItem = completeValue(
exeContext,
itemType,
fieldNodes,
info,
itemPath,
item,
asyncPayloadRecord,
);

if (isPromise(completedItem)) {
completedItem = handleAsyncCompletionError(
completedItem,
exeContext,
itemType,
fieldNodes,
itemPath,
asyncPayloadRecord,
);
}
return { done: false, value: completedItem };
} catch (rawError) {
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath));
const value = handleFieldError(error, itemType, asyncPayloadRecord.errors);
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
return { done: false, value };
}
}

function filterSubsequentPayloads(
exeContext: ExecutionContext,
nullPath: Path,
Expand Down

0 comments on commit dc58257

Please sign in to comment.