Skip to content

Commit d59c725

Browse files
authored
use object for GraphQLWrappedResult instead of tuple (#4265)
for readability. benchmarks suggest similar or even better performance ![image](https://github.com/user-attachments/assets/c4f900a4-f3b3-4d68-9d6a-c8505c9f56b7)
1 parent 12a5ec9 commit d59c725

File tree

1 file changed

+83
-65
lines changed

1 file changed

+83
-65
lines changed

src/execution/execute.ts

+83-65
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,10 @@ export interface StreamUsage {
197197
fieldDetailsList: FieldDetailsList;
198198
}
199199

200-
type GraphQLWrappedResult<T> = [T, Array<IncrementalDataRecord> | undefined];
200+
interface GraphQLWrappedResult<T> {
201+
rawResult: T;
202+
incrementalDataRecords: Array<IncrementalDataRecord> | undefined;
203+
}
201204

202205
const UNEXPECTED_EXPERIMENTAL_DIRECTIVES =
203206
'The provided schema unexpectedly contains experimental directives (@defer or @stream). These directives may only be utilized if experimental execution features are explicitly enabled.';
@@ -360,18 +363,14 @@ export function experimentalExecuteQueryOrMutationOrSubscriptionEvent(
360363

361364
if (isPromise(graphqlWrappedResult)) {
362365
return graphqlWrappedResult.then(
363-
(resolved) => buildDataResponse(exeContext, resolved[0], resolved[1]),
366+
(resolved) => buildDataResponse(exeContext, resolved),
364367
(error: unknown) => ({
365368
data: null,
366369
errors: withError(exeContext.errors, error as GraphQLError),
367370
}),
368371
);
369372
}
370-
return buildDataResponse(
371-
exeContext,
372-
graphqlWrappedResult[0],
373-
graphqlWrappedResult[1],
374-
);
373+
return buildDataResponse(exeContext, graphqlWrappedResult);
375374
} catch (error) {
376375
return { data: null, errors: withError(exeContext.errors, error) };
377376
}
@@ -442,10 +441,10 @@ function addIncrementalDataRecords(
442441
if (incrementalDataRecords === undefined) {
443442
return;
444443
}
445-
if (graphqlWrappedResult[1] === undefined) {
446-
graphqlWrappedResult[1] = [...incrementalDataRecords];
444+
if (graphqlWrappedResult.incrementalDataRecords === undefined) {
445+
graphqlWrappedResult.incrementalDataRecords = [...incrementalDataRecords];
447446
} else {
448-
graphqlWrappedResult[1].push(...incrementalDataRecords);
447+
graphqlWrappedResult.incrementalDataRecords.push(...incrementalDataRecords);
449448
}
450449
}
451450

@@ -458,9 +457,9 @@ function withError(
458457

459458
function buildDataResponse(
460459
exeContext: ExecutionContext,
461-
data: ObjMap<unknown>,
462-
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord> | undefined,
460+
graphqlWrappedResult: GraphQLWrappedResult<ObjMap<unknown>>,
463461
): ExecutionResult | ExperimentalIncrementalExecutionResults {
462+
const { rawResult: data, incrementalDataRecords } = graphqlWrappedResult;
464463
const errors = exeContext.errors;
465464
if (incrementalDataRecords === undefined) {
466465
return errors !== undefined ? { errors, data } : { data };
@@ -675,7 +674,7 @@ function executeFieldsSerially(
675674
fieldPath,
676675
incrementalContext,
677676
);
678-
graphqlWrappedResult[0][responseName] = null;
677+
graphqlWrappedResult.rawResult[responseName] = null;
679678
return graphqlWrappedResult;
680679
}
681680

@@ -693,16 +692,25 @@ function executeFieldsSerially(
693692
}
694693
if (isPromise(result)) {
695694
return result.then((resolved) => {
696-
graphqlWrappedResult[0][responseName] = resolved[0];
697-
addIncrementalDataRecords(graphqlWrappedResult, resolved[1]);
695+
graphqlWrappedResult.rawResult[responseName] = resolved.rawResult;
696+
addIncrementalDataRecords(
697+
graphqlWrappedResult,
698+
resolved.incrementalDataRecords,
699+
);
698700
return graphqlWrappedResult;
699701
});
700702
}
701-
graphqlWrappedResult[0][responseName] = result[0];
702-
addIncrementalDataRecords(graphqlWrappedResult, result[1]);
703+
graphqlWrappedResult.rawResult[responseName] = result.rawResult;
704+
addIncrementalDataRecords(
705+
graphqlWrappedResult,
706+
result.incrementalDataRecords,
707+
);
703708
return graphqlWrappedResult;
704709
},
705-
[Object.create(null), undefined] as GraphQLWrappedResult<ObjMap<unknown>>,
710+
{
711+
rawResult: Object.create(null),
712+
incrementalDataRecords: undefined,
713+
},
706714
);
707715
}
708716

@@ -720,10 +728,10 @@ function executeFields(
720728
deferMap: ReadonlyMap<DeferUsage, DeferredFragmentRecord> | undefined,
721729
): PromiseOrValue<GraphQLWrappedResult<ObjMap<unknown>>> {
722730
const results = Object.create(null);
723-
const graphqlWrappedResult: GraphQLWrappedResult<ObjMap<unknown>> = [
724-
results,
725-
undefined,
726-
];
731+
const graphqlWrappedResult: GraphQLWrappedResult<ObjMap<unknown>> = {
732+
rawResult: results,
733+
incrementalDataRecords: undefined,
734+
};
727735
let containsPromise = false;
728736

729737
try {
@@ -742,13 +750,19 @@ function executeFields(
742750
if (result !== undefined) {
743751
if (isPromise(result)) {
744752
results[responseName] = result.then((resolved) => {
745-
addIncrementalDataRecords(graphqlWrappedResult, resolved[1]);
746-
return resolved[0];
753+
addIncrementalDataRecords(
754+
graphqlWrappedResult,
755+
resolved.incrementalDataRecords,
756+
);
757+
return resolved.rawResult;
747758
});
748759
containsPromise = true;
749760
} else {
750-
results[responseName] = result[0];
751-
addIncrementalDataRecords(graphqlWrappedResult, result[1]);
761+
results[responseName] = result.rawResult;
762+
addIncrementalDataRecords(
763+
graphqlWrappedResult,
764+
result.incrementalDataRecords,
765+
);
752766
}
753767
}
754768
}
@@ -772,10 +786,10 @@ function executeFields(
772786
// Otherwise, results is a map from field name to the result of resolving that
773787
// field, which is possibly a promise. Return a promise that will return this
774788
// same map, but with any promises replaced with the values they resolved to.
775-
return promiseForObject(results, (resolved) => [
776-
resolved,
777-
graphqlWrappedResult[1],
778-
]);
789+
return promiseForObject(results, (resolved) => ({
790+
rawResult: resolved,
791+
incrementalDataRecords: graphqlWrappedResult.incrementalDataRecords,
792+
}));
779793
}
780794

781795
function toNodes(fieldDetailsList: FieldDetailsList): ReadonlyArray<FieldNode> {
@@ -871,7 +885,7 @@ function executeField(
871885
path,
872886
incrementalContext,
873887
);
874-
return [null, undefined];
888+
return { rawResult: null, incrementalDataRecords: undefined };
875889
});
876890
}
877891
return completed;
@@ -884,7 +898,7 @@ function executeField(
884898
path,
885899
incrementalContext,
886900
);
887-
return [null, undefined];
901+
return { rawResult: null, incrementalDataRecords: undefined };
888902
}
889903
}
890904

@@ -997,7 +1011,7 @@ function completeValue(
9971011
incrementalContext,
9981012
deferMap,
9991013
);
1000-
if ((completed as GraphQLWrappedResult<unknown>)[0] === null) {
1014+
if ((completed as GraphQLWrappedResult<unknown>).rawResult === null) {
10011015
throw new Error(
10021016
`Cannot return null for non-nullable field ${info.parentType}.${info.fieldName}.`,
10031017
);
@@ -1007,7 +1021,7 @@ function completeValue(
10071021

10081022
// If result value is null or undefined then return null.
10091023
if (result == null) {
1010-
return [null, undefined];
1024+
return { rawResult: null, incrementalDataRecords: undefined };
10111025
}
10121026

10131027
// If field type is List, complete each item in the list with the inner type
@@ -1027,7 +1041,10 @@ function completeValue(
10271041
// If field type is a leaf type, Scalar or Enum, coerce to a valid value,
10281042
// returning null if coercion is not possible.
10291043
if (isLeafType(returnType)) {
1030-
return [completeLeafValue(returnType, result), undefined];
1044+
return {
1045+
rawResult: completeLeafValue(returnType, result),
1046+
incrementalDataRecords: undefined,
1047+
};
10311048
}
10321049

10331050
// If field type is an abstract type, Interface or Union, determine the
@@ -1103,7 +1120,7 @@ async function completePromisedValue(
11031120
path,
11041121
incrementalContext,
11051122
);
1106-
return [null, undefined];
1123+
return { rawResult: null, incrementalDataRecords: undefined };
11071124
}
11081125
}
11091126

@@ -1201,10 +1218,10 @@ async function completeAsyncIteratorValue(
12011218
): Promise<GraphQLWrappedResult<ReadonlyArray<unknown>>> {
12021219
let containsPromise = false;
12031220
const completedResults: Array<unknown> = [];
1204-
const graphqlWrappedResult: GraphQLWrappedResult<Array<unknown>> = [
1205-
completedResults,
1206-
undefined,
1207-
];
1221+
const graphqlWrappedResult: GraphQLWrappedResult<Array<unknown>> = {
1222+
rawResult: completedResults,
1223+
incrementalDataRecords: undefined,
1224+
};
12081225
let index = 0;
12091226
const streamUsage = getStreamUsage(
12101227
exeContext.validatedExecutionArgs,
@@ -1323,10 +1340,10 @@ async function completeAsyncIteratorValue(
13231340
}
13241341

13251342
return containsPromise
1326-
? /* c8 ignore start */ Promise.all(completedResults).then((resolved) => [
1327-
resolved,
1328-
graphqlWrappedResult[1],
1329-
])
1343+
? /* c8 ignore start */ Promise.all(completedResults).then((resolved) => ({
1344+
rawResult: resolved,
1345+
incrementalDataRecords: graphqlWrappedResult.incrementalDataRecords,
1346+
}))
13301347
: /* c8 ignore stop */ graphqlWrappedResult;
13311348
}
13321349

@@ -1393,10 +1410,10 @@ function completeIterableValue(
13931410
// where the list contains no Promises by avoiding creating another Promise.
13941411
let containsPromise = false;
13951412
const completedResults: Array<unknown> = [];
1396-
const graphqlWrappedResult: GraphQLWrappedResult<Array<unknown>> = [
1397-
completedResults,
1398-
undefined,
1399-
];
1413+
const graphqlWrappedResult: GraphQLWrappedResult<Array<unknown>> = {
1414+
rawResult: completedResults,
1415+
incrementalDataRecords: undefined,
1416+
};
14001417
let index = 0;
14011418
const streamUsage = getStreamUsage(
14021419
exeContext.validatedExecutionArgs,
@@ -1469,10 +1486,10 @@ function completeIterableValue(
14691486
}
14701487

14711488
return containsPromise
1472-
? Promise.all(completedResults).then((resolved) => [
1473-
resolved,
1474-
graphqlWrappedResult[1],
1475-
])
1489+
? Promise.all(completedResults).then((resolved) => ({
1490+
rawResult: resolved,
1491+
incrementalDataRecords: graphqlWrappedResult.incrementalDataRecords,
1492+
}))
14761493
: graphqlWrappedResult;
14771494
}
14781495

@@ -1511,8 +1528,8 @@ function completeListItemValue(
15111528
completedResults.push(
15121529
completedItem.then(
15131530
(resolved) => {
1514-
addIncrementalDataRecords(parent, resolved[1]);
1515-
return resolved[0];
1531+
addIncrementalDataRecords(parent, resolved.incrementalDataRecords);
1532+
return resolved.rawResult;
15161533
},
15171534
(rawError: unknown) => {
15181535
handleFieldError(
@@ -1530,8 +1547,8 @@ function completeListItemValue(
15301547
return true;
15311548
}
15321549

1533-
completedResults.push(completedItem[0]);
1534-
addIncrementalDataRecords(parent, completedItem[1]);
1550+
completedResults.push(completedItem.rawResult);
1551+
addIncrementalDataRecords(parent, completedItem.incrementalDataRecords);
15351552
} catch (rawError) {
15361553
handleFieldError(
15371554
rawError,
@@ -1572,8 +1589,8 @@ async function completePromisedListItemValue(
15721589
if (isPromise(completed)) {
15731590
completed = await completed;
15741591
}
1575-
addIncrementalDataRecords(parent, completed[1]);
1576-
return completed[0];
1592+
addIncrementalDataRecords(parent, completed.incrementalDataRecords);
1593+
return completed.rawResult;
15771594
} catch (rawError) {
15781595
handleFieldError(
15791596
rawError,
@@ -2343,12 +2360,12 @@ function buildCompletedExecutionGroup(
23432360
path: Path | undefined,
23442361
result: GraphQLWrappedResult<ObjMap<unknown>>,
23452362
): CompletedExecutionGroup {
2363+
const { rawResult: data, incrementalDataRecords } = result;
23462364
return {
23472365
pendingExecutionGroup,
23482366
path: pathToArray(path),
2349-
result:
2350-
errors === undefined ? { data: result[0] } : { data: result[0], errors },
2351-
incrementalDataRecords: result[1],
2367+
result: errors === undefined ? { data } : { data, errors },
2368+
incrementalDataRecords,
23522369
};
23532370
}
23542371

@@ -2583,7 +2600,7 @@ function completeStreamItem(
25832600
itemPath,
25842601
incrementalContext,
25852602
);
2586-
result = [null, undefined];
2603+
result = { rawResult: null, incrementalDataRecords: undefined };
25872604
}
25882605
} catch (error) {
25892606
return {
@@ -2602,7 +2619,7 @@ function completeStreamItem(
26022619
itemPath,
26032620
incrementalContext,
26042621
);
2605-
return [null, undefined] as GraphQLWrappedResult<unknown>;
2622+
return { rawResult: null, incrementalDataRecords: undefined };
26062623
})
26072624
.then(
26082625
(resolvedItem) =>
@@ -2620,9 +2637,10 @@ function buildStreamItemResult(
26202637
errors: ReadonlyArray<GraphQLError> | undefined,
26212638
result: GraphQLWrappedResult<unknown>,
26222639
): StreamItemResult {
2640+
const { rawResult: item, incrementalDataRecords } = result;
26232641
return {
2624-
item: result[0],
2642+
item,
26252643
errors,
2626-
incrementalDataRecords: result[1],
2644+
incrementalDataRecords,
26272645
};
26282646
}

0 commit comments

Comments
 (0)