Skip to content

Commit 9301237

Browse files
committed
perf: introduce completePromisedListItemValue (#4051)
depends on #4050
1 parent 98b15bc commit 9301237

2 files changed

Lines changed: 88 additions & 21 deletions

File tree

src/execution/__tests__/lists-test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,34 @@ describe('Execute: Accepts async iterables as list value', () => {
152152
});
153153
});
154154

155+
it('Accepts an AsyncIterable yielding promises', async () => {
156+
const listField = {
157+
[Symbol.asyncIterator]() {
158+
let index = 0;
159+
const values = [
160+
Promise.resolve('two'),
161+
Promise.resolve(4),
162+
Promise.resolve(false),
163+
];
164+
165+
return {
166+
next() {
167+
const value = values[index];
168+
if (value === undefined) {
169+
return Promise.resolve({ value: undefined, done: true });
170+
}
171+
index += 1;
172+
return Promise.resolve({ value, done: false });
173+
},
174+
};
175+
},
176+
};
177+
178+
expectJSON(await complete({ listField })).toDeepEqual({
179+
data: { listField: ['two', '4', 'false'] },
180+
});
181+
});
182+
155183
it('Handles an AsyncGenerator function where an intermediate value triggers an error', async () => {
156184
async function* listField() {
157185
yield await Promise.resolve('two');

src/execution/execute.ts

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -825,16 +825,30 @@ async function completeAsyncIteratorValue(
825825
try {
826826
// eslint-disable-next-line no-await-in-loop
827827
iteration = await asyncIterator.next();
828-
if (iteration.done) {
829-
break;
830-
}
831828
} catch (rawError) {
832829
throw locatedError(rawError, fieldGroup, pathToArray(path));
833830
}
834831

835-
if (
832+
if (iteration.done) {
833+
break;
834+
}
835+
836+
const item = iteration.value;
837+
if (isPromise(item)) {
838+
completedResults.push(
839+
completePromisedListItemValue(
840+
item,
841+
exeContext,
842+
itemType,
843+
fieldGroup,
844+
info,
845+
itemPath,
846+
),
847+
);
848+
containsPromise = true;
849+
} else if (
836850
completeListItemValue(
837-
iteration.value,
851+
item,
838852
completedResults,
839853
exeContext,
840854
itemType,
@@ -893,7 +907,19 @@ function completeListValue(
893907
// since from here on it is not ever accessed by resolver functions.
894908
const itemPath = addPath(path, index, undefined);
895909

896-
if (
910+
if (isPromise(item)) {
911+
completedResults.push(
912+
completePromisedListItemValue(
913+
item,
914+
exeContext,
915+
itemType,
916+
fieldGroup,
917+
info,
918+
itemPath,
919+
),
920+
);
921+
containsPromise = true;
922+
} else if (
897923
completeListItemValue(
898924
item,
899925
completedResults,
@@ -927,21 +953,6 @@ function completeListItemValue(
927953
info: GraphQLResolveInfo,
928954
itemPath: Path,
929955
): boolean {
930-
if (isPromise(item)) {
931-
completedResults.push(
932-
completePromisedValue(
933-
exeContext,
934-
itemType,
935-
fieldGroup,
936-
info,
937-
itemPath,
938-
item,
939-
),
940-
);
941-
942-
return true;
943-
}
944-
945956
try {
946957
const completedItem = completeValue(
947958
exeContext,
@@ -980,6 +991,34 @@ function completeListItemValue(
980991
return false;
981992
}
982993

994+
async function completePromisedListItemValue(
995+
item: unknown,
996+
exeContext: ExecutionContext,
997+
itemType: GraphQLOutputType,
998+
fieldGroup: FieldGroup,
999+
info: GraphQLResolveInfo,
1000+
itemPath: Path,
1001+
): Promise<unknown> {
1002+
try {
1003+
const resolved = await item;
1004+
let completed = completeValue(
1005+
exeContext,
1006+
itemType,
1007+
fieldGroup,
1008+
info,
1009+
itemPath,
1010+
resolved,
1011+
);
1012+
if (isPromise(completed)) {
1013+
completed = await completed;
1014+
}
1015+
return completed;
1016+
} catch (rawError) {
1017+
handleFieldError(rawError, exeContext, itemType, fieldGroup, itemPath);
1018+
return null;
1019+
}
1020+
}
1021+
9831022
/**
9841023
* Complete a Scalar or Enum by serializing to a valid value, returning
9851024
* null if serialization is not possible.

0 commit comments

Comments
 (0)