Skip to content

Commit 308647b

Browse files
authored
polish: refactor execution plan functions to match spec (#4273)
moves simplest case inside the execute[Root|Sub]ExecutionPlan() functions to better match proposed spec edits orders function in call order, moving executeSubExecutionPlan down closer to where it is used no significant change in performance ![image](https://github.com/user-attachments/assets/221a2696-fd0b-4b53-8519-eb2376327639)
1 parent e4d7e85 commit 308647b

File tree

1 file changed

+158
-114
lines changed

1 file changed

+158
-114
lines changed

src/execution/execute.ts

Lines changed: 158 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ export function experimentalExecuteQueryOrMutationOrSubscriptionEvent(
339339
);
340340
}
341341

342-
const collectedFields = collectFields(
342+
const { groupedFieldSet, newDeferUsages } = collectFields(
343343
schema,
344344
fragments,
345345
variableValues,
@@ -348,24 +348,14 @@ export function experimentalExecuteQueryOrMutationOrSubscriptionEvent(
348348
hideSuggestions,
349349
);
350350

351-
const { groupedFieldSet, newDeferUsages } = collectedFields;
352-
const graphqlWrappedResult =
353-
newDeferUsages.length === 0
354-
? executeRootGroupedFieldSet(
355-
exeContext,
356-
operation.operation,
357-
rootType,
358-
rootValue,
359-
groupedFieldSet,
360-
undefined,
361-
)
362-
: executeExecutionPlan(
363-
exeContext,
364-
rootType,
365-
rootValue,
366-
newDeferUsages,
367-
buildExecutionPlan(groupedFieldSet),
368-
);
351+
const graphqlWrappedResult = executeRootExecutionPlan(
352+
exeContext,
353+
operation.operation,
354+
rootType,
355+
rootValue,
356+
groupedFieldSet,
357+
newDeferUsages,
358+
);
369359

370360
if (isPromise(graphqlWrappedResult)) {
371361
return graphqlWrappedResult.then(
@@ -388,78 +378,6 @@ export function experimentalExecuteQueryOrMutationOrSubscriptionEvent(
388378
}
389379
}
390380

391-
function executeExecutionPlan(
392-
exeContext: ExecutionContext,
393-
returnType: GraphQLObjectType,
394-
sourceValue: unknown,
395-
newDeferUsages: ReadonlyArray<DeferUsage>,
396-
executionPlan: ExecutionPlan,
397-
path?: Path | undefined,
398-
incrementalContext?: IncrementalContext | undefined,
399-
deferMap?: ReadonlyMap<DeferUsage, DeferredFragmentRecord> | undefined,
400-
): PromiseOrValue<GraphQLWrappedResult<ObjMap<unknown>>> {
401-
const newDeferMap = getNewDeferMap(newDeferUsages, deferMap, path);
402-
403-
const { groupedFieldSet, newGroupedFieldSets } = executionPlan;
404-
405-
const graphqlWrappedResult = executeFields(
406-
exeContext,
407-
returnType,
408-
sourceValue,
409-
path,
410-
groupedFieldSet,
411-
incrementalContext,
412-
newDeferMap,
413-
);
414-
415-
if (newGroupedFieldSets.size > 0) {
416-
const newPendingExecutionGroups = collectExecutionGroups(
417-
exeContext,
418-
returnType,
419-
sourceValue,
420-
path,
421-
incrementalContext?.deferUsageSet,
422-
newGroupedFieldSets,
423-
newDeferMap,
424-
);
425-
426-
return withNewExecutionGroups(
427-
graphqlWrappedResult,
428-
newPendingExecutionGroups,
429-
);
430-
}
431-
return graphqlWrappedResult;
432-
}
433-
434-
function withNewExecutionGroups(
435-
result: PromiseOrValue<GraphQLWrappedResult<ObjMap<unknown>>>,
436-
newPendingExecutionGroups: ReadonlyArray<PendingExecutionGroup>,
437-
): PromiseOrValue<GraphQLWrappedResult<ObjMap<unknown>>> {
438-
if (isPromise(result)) {
439-
return result.then((resolved) => {
440-
addIncrementalDataRecords(resolved, newPendingExecutionGroups);
441-
return resolved;
442-
});
443-
}
444-
445-
addIncrementalDataRecords(result, newPendingExecutionGroups);
446-
return result;
447-
}
448-
449-
function addIncrementalDataRecords(
450-
graphqlWrappedResult: GraphQLWrappedResult<unknown>,
451-
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord> | undefined,
452-
): void {
453-
if (incrementalDataRecords === undefined) {
454-
return;
455-
}
456-
if (graphqlWrappedResult.incrementalDataRecords === undefined) {
457-
graphqlWrappedResult.incrementalDataRecords = [...incrementalDataRecords];
458-
} else {
459-
graphqlWrappedResult.incrementalDataRecords.push(...incrementalDataRecords);
460-
}
461-
}
462-
463381
function withError(
464382
errors: Array<GraphQLError> | undefined,
465383
error: GraphQLError,
@@ -616,6 +534,73 @@ export function validateExecutionArgs(
616534
};
617535
}
618536

537+
function executeRootExecutionPlan(
538+
exeContext: ExecutionContext,
539+
operation: OperationTypeNode,
540+
rootType: GraphQLObjectType,
541+
rootValue: unknown,
542+
originalGroupedFieldSet: GroupedFieldSet,
543+
newDeferUsages: ReadonlyArray<DeferUsage>,
544+
): PromiseOrValue<GraphQLWrappedResult<ObjMap<unknown>>> {
545+
if (newDeferUsages.length === 0) {
546+
return executeRootGroupedFieldSet(
547+
exeContext,
548+
operation,
549+
rootType,
550+
rootValue,
551+
originalGroupedFieldSet,
552+
undefined,
553+
);
554+
}
555+
const newDeferMap = getNewDeferMap(newDeferUsages, undefined, undefined);
556+
557+
const { groupedFieldSet, newGroupedFieldSets } = buildExecutionPlan(
558+
originalGroupedFieldSet,
559+
);
560+
561+
const graphqlWrappedResult = executeRootGroupedFieldSet(
562+
exeContext,
563+
operation,
564+
rootType,
565+
rootValue,
566+
groupedFieldSet,
567+
newDeferMap,
568+
);
569+
570+
if (newGroupedFieldSets.size > 0) {
571+
const newPendingExecutionGroups = collectExecutionGroups(
572+
exeContext,
573+
rootType,
574+
rootValue,
575+
undefined,
576+
undefined,
577+
newGroupedFieldSets,
578+
newDeferMap,
579+
);
580+
581+
return withNewExecutionGroups(
582+
graphqlWrappedResult,
583+
newPendingExecutionGroups,
584+
);
585+
}
586+
return graphqlWrappedResult;
587+
}
588+
589+
function withNewExecutionGroups(
590+
result: PromiseOrValue<GraphQLWrappedResult<ObjMap<unknown>>>,
591+
newPendingExecutionGroups: ReadonlyArray<PendingExecutionGroup>,
592+
): PromiseOrValue<GraphQLWrappedResult<ObjMap<unknown>>> {
593+
if (isPromise(result)) {
594+
return result.then((resolved) => {
595+
addIncrementalDataRecords(resolved, newPendingExecutionGroups);
596+
return resolved;
597+
});
598+
}
599+
600+
addIncrementalDataRecords(result, newPendingExecutionGroups);
601+
return result;
602+
}
603+
619604
function executeRootGroupedFieldSet(
620605
exeContext: ExecutionContext,
621606
operation: OperationTypeNode,
@@ -728,6 +713,20 @@ function executeFieldsSerially(
728713
);
729714
}
730715

716+
function addIncrementalDataRecords(
717+
graphqlWrappedResult: GraphQLWrappedResult<unknown>,
718+
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord> | undefined,
719+
): void {
720+
if (incrementalDataRecords === undefined) {
721+
return;
722+
}
723+
if (graphqlWrappedResult.incrementalDataRecords === undefined) {
724+
graphqlWrappedResult.incrementalDataRecords = [...incrementalDataRecords];
725+
} else {
726+
graphqlWrappedResult.incrementalDataRecords.push(...incrementalDataRecords);
727+
}
728+
}
729+
731730
/**
732731
* Implements the "Executing selection sets" section of the spec
733732
* for fields that may be executed in parallel.
@@ -1877,29 +1876,74 @@ function collectAndExecuteSubfields(
18771876
fieldDetailsList,
18781877
);
18791878
const { groupedFieldSet, newDeferUsages } = collectedSubfields;
1880-
return deferMap === undefined && newDeferUsages.length === 0
1881-
? executeFields(
1882-
exeContext,
1883-
returnType,
1884-
result,
1885-
path,
1886-
groupedFieldSet,
1887-
incrementalContext,
1888-
undefined,
1889-
)
1890-
: executeExecutionPlan(
1891-
exeContext,
1892-
returnType,
1893-
result,
1894-
newDeferUsages,
1895-
buildSubExecutionPlan(
1896-
groupedFieldSet,
1897-
incrementalContext?.deferUsageSet,
1898-
),
1899-
path,
1900-
incrementalContext,
1901-
deferMap,
1902-
);
1879+
return executeSubExecutionPlan(
1880+
exeContext,
1881+
returnType,
1882+
result,
1883+
groupedFieldSet,
1884+
newDeferUsages,
1885+
path,
1886+
incrementalContext,
1887+
deferMap,
1888+
);
1889+
}
1890+
1891+
function executeSubExecutionPlan(
1892+
exeContext: ExecutionContext,
1893+
returnType: GraphQLObjectType,
1894+
sourceValue: unknown,
1895+
originalGroupedFieldSet: GroupedFieldSet,
1896+
newDeferUsages: ReadonlyArray<DeferUsage>,
1897+
path?: Path | undefined,
1898+
incrementalContext?: IncrementalContext | undefined,
1899+
deferMap?: ReadonlyMap<DeferUsage, DeferredFragmentRecord> | undefined,
1900+
): PromiseOrValue<GraphQLWrappedResult<ObjMap<unknown>>> {
1901+
if (deferMap === undefined && newDeferUsages.length === 0) {
1902+
return executeFields(
1903+
exeContext,
1904+
returnType,
1905+
sourceValue,
1906+
path,
1907+
originalGroupedFieldSet,
1908+
incrementalContext,
1909+
deferMap,
1910+
);
1911+
}
1912+
1913+
const newDeferMap = getNewDeferMap(newDeferUsages, deferMap, path);
1914+
1915+
const { groupedFieldSet, newGroupedFieldSets } = buildSubExecutionPlan(
1916+
originalGroupedFieldSet,
1917+
incrementalContext?.deferUsageSet,
1918+
);
1919+
1920+
const graphqlWrappedResult = executeFields(
1921+
exeContext,
1922+
returnType,
1923+
sourceValue,
1924+
path,
1925+
groupedFieldSet,
1926+
incrementalContext,
1927+
newDeferMap,
1928+
);
1929+
1930+
if (newGroupedFieldSets.size > 0) {
1931+
const newPendingExecutionGroups = collectExecutionGroups(
1932+
exeContext,
1933+
returnType,
1934+
sourceValue,
1935+
path,
1936+
incrementalContext?.deferUsageSet,
1937+
newGroupedFieldSets,
1938+
newDeferMap,
1939+
);
1940+
1941+
return withNewExecutionGroups(
1942+
graphqlWrappedResult,
1943+
newPendingExecutionGroups,
1944+
);
1945+
}
1946+
return graphqlWrappedResult;
19031947
}
19041948

19051949
function buildSubExecutionPlan(

0 commit comments

Comments
 (0)