Skip to content

polish(incremental): rename terms to match spec #4148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 52 additions & 55 deletions src/execution/IncrementalGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,21 @@ import type { GraphQLError } from '../error/GraphQLError.js';

import type {
DeferredFragmentRecord,
DeferredGroupedFieldSetRecord,
DeliveryGroup,
IncrementalDataRecord,
IncrementalDataRecordResult,
ReconcilableDeferredGroupedFieldSetResult,
PendingExecutionGroup,
StreamItemRecord,
StreamRecord,
SubsequentResultRecord,
} from './types.js';
import {
isDeferredFragmentRecord,
isDeferredGroupedFieldSetRecord,
SuccessfulExecutionGroup,
} from './types.js';
import { isDeferredFragmentRecord, isPendingExecutionGroup } from './types.js';

/**
* @internal
*/
export class IncrementalGraph {
private _rootNodes: Set<SubsequentResultRecord>;
private _rootNodes: Set<DeliveryGroup>;

private _completedQueue: Array<IncrementalDataRecordResult>;
private _nextQueue: Array<
Expand All @@ -39,8 +36,8 @@ export class IncrementalGraph {

getNewRootNodes(
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>,
): ReadonlyArray<SubsequentResultRecord> {
const initialResultChildren = new Set<SubsequentResultRecord>();
): ReadonlyArray<DeliveryGroup> {
const initialResultChildren = new Set<DeliveryGroup>();
this._addIncrementalDataRecords(
incrementalDataRecords,
undefined,
Expand All @@ -49,23 +46,25 @@ export class IncrementalGraph {
return this._promoteNonEmptyToRoot(initialResultChildren);
}

addCompletedReconcilableDeferredGroupedFieldSet(
reconcilableResult: ReconcilableDeferredGroupedFieldSetResult,
addCompletedSuccessfulExecutionGroup(
successfulExecutionGroup: SuccessfulExecutionGroup,
): void {
for (const deferredFragmentRecord of reconcilableResult
.deferredGroupedFieldSetRecord.deferredFragmentRecords) {
deferredFragmentRecord.deferredGroupedFieldSetRecords.delete(
reconcilableResult.deferredGroupedFieldSetRecord,
for (const deferredFragmentRecord of successfulExecutionGroup
.pendingExecutionGroup.deferredFragmentRecords) {
deferredFragmentRecord.pendingExecutionGroups.delete(
successfulExecutionGroup.pendingExecutionGroup,
);
deferredFragmentRecord.successfulExecutionGroups.add(
successfulExecutionGroup,
);
deferredFragmentRecord.reconcilableResults.add(reconcilableResult);
}

const incrementalDataRecords = reconcilableResult.incrementalDataRecords;
const incrementalDataRecords =
successfulExecutionGroup.incrementalDataRecords;
if (incrementalDataRecords !== undefined) {
this._addIncrementalDataRecords(
incrementalDataRecords,
reconcilableResult.deferredGroupedFieldSetRecord
.deferredFragmentRecords,
successfulExecutionGroup.pendingExecutionGroup.deferredFragmentRecords,
);
}
}
Expand Down Expand Up @@ -104,32 +103,32 @@ export class IncrementalGraph {

completeDeferredFragment(deferredFragmentRecord: DeferredFragmentRecord):
| {
newRootNodes: ReadonlyArray<SubsequentResultRecord>;
reconcilableResults: ReadonlyArray<ReconcilableDeferredGroupedFieldSetResult>;
newRootNodes: ReadonlyArray<DeliveryGroup>;
successfulExecutionGroups: ReadonlyArray<SuccessfulExecutionGroup>;
}
| undefined {
if (
!this._rootNodes.has(deferredFragmentRecord) ||
deferredFragmentRecord.deferredGroupedFieldSetRecords.size > 0
deferredFragmentRecord.pendingExecutionGroups.size > 0
) {
return;
}
const reconcilableResults = Array.from(
deferredFragmentRecord.reconcilableResults,
const successfulExecutionGroups = Array.from(
deferredFragmentRecord.successfulExecutionGroups,
);
this._removeRootNode(deferredFragmentRecord);
for (const reconcilableResult of reconcilableResults) {
for (const otherDeferredFragmentRecord of reconcilableResult
.deferredGroupedFieldSetRecord.deferredFragmentRecords) {
otherDeferredFragmentRecord.reconcilableResults.delete(
reconcilableResult,
for (const successfulExecutionGroup of successfulExecutionGroups) {
for (const otherDeferredFragmentRecord of successfulExecutionGroup
.pendingExecutionGroup.deferredFragmentRecords) {
otherDeferredFragmentRecord.successfulExecutionGroups.delete(
successfulExecutionGroup,
);
}
}
const newRootNodes = this._promoteNonEmptyToRoot(
deferredFragmentRecord.children,
);
return { newRootNodes, reconcilableResults };
return { newRootNodes, successfulExecutionGroups };
}

removeDeferredFragment(
Expand All @@ -146,30 +145,28 @@ export class IncrementalGraph {
this._removeRootNode(streamRecord);
}

private _removeRootNode(
subsequentResultRecord: SubsequentResultRecord,
): void {
this._rootNodes.delete(subsequentResultRecord);
private _removeRootNode(deliveryGroup: DeliveryGroup): void {
this._rootNodes.delete(deliveryGroup);
}

private _addIncrementalDataRecords(
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>,
parents: ReadonlyArray<DeferredFragmentRecord> | undefined,
initialResultChildren?: Set<SubsequentResultRecord> | undefined,
initialResultChildren?: Set<DeliveryGroup> | undefined,
): void {
for (const incrementalDataRecord of incrementalDataRecords) {
if (isDeferredGroupedFieldSetRecord(incrementalDataRecord)) {
if (isPendingExecutionGroup(incrementalDataRecord)) {
for (const deferredFragmentRecord of incrementalDataRecord.deferredFragmentRecords) {
this._addDeferredFragment(
deferredFragmentRecord,
initialResultChildren,
);
deferredFragmentRecord.deferredGroupedFieldSetRecords.add(
deferredFragmentRecord.pendingExecutionGroups.add(
incrementalDataRecord,
);
}
if (this._completesRootNode(incrementalDataRecord)) {
this._onDeferredGroupedFieldSet(incrementalDataRecord);
this._onExecutionGroup(incrementalDataRecord);
}
} else if (parents === undefined) {
invariant(initialResultChildren !== undefined);
Expand All @@ -184,15 +181,15 @@ export class IncrementalGraph {
}

private _promoteNonEmptyToRoot(
maybeEmptyNewRootNodes: Set<SubsequentResultRecord>,
): ReadonlyArray<SubsequentResultRecord> {
const newRootNodes: Array<SubsequentResultRecord> = [];
maybeEmptyNewRootNodes: Set<DeliveryGroup>,
): ReadonlyArray<DeliveryGroup> {
const newRootNodes: Array<DeliveryGroup> = [];
for (const node of maybeEmptyNewRootNodes) {
if (isDeferredFragmentRecord(node)) {
if (node.deferredGroupedFieldSetRecords.size > 0) {
for (const deferredGroupedFieldSetRecord of node.deferredGroupedFieldSetRecords) {
if (!this._completesRootNode(deferredGroupedFieldSetRecord)) {
this._onDeferredGroupedFieldSet(deferredGroupedFieldSetRecord);
if (node.pendingExecutionGroups.size > 0) {
for (const pendingExecutionGroup of node.pendingExecutionGroups) {
if (!this._completesRootNode(pendingExecutionGroup)) {
this._onExecutionGroup(pendingExecutionGroup);
}
}
this._rootNodes.add(node);
Expand All @@ -214,16 +211,16 @@ export class IncrementalGraph {
}

private _completesRootNode(
deferredGroupedFieldSetRecord: DeferredGroupedFieldSetRecord,
pendingExecutionGroup: PendingExecutionGroup,
): boolean {
return deferredGroupedFieldSetRecord.deferredFragmentRecords.some(
return pendingExecutionGroup.deferredFragmentRecords.some(
(deferredFragmentRecord) => this._rootNodes.has(deferredFragmentRecord),
);
}

private _addDeferredFragment(
deferredFragmentRecord: DeferredFragmentRecord,
initialResultChildren: Set<SubsequentResultRecord> | undefined,
initialResultChildren: Set<DeliveryGroup> | undefined,
): void {
if (this._rootNodes.has(deferredFragmentRecord)) {
return;
Expand All @@ -238,14 +235,14 @@ export class IncrementalGraph {
this._addDeferredFragment(parent, initialResultChildren);
}

private _onDeferredGroupedFieldSet(
deferredGroupedFieldSetRecord: DeferredGroupedFieldSetRecord,
private _onExecutionGroup(
pendingExecutionGroup: PendingExecutionGroup,
): void {
let deferredGroupedFieldSetResult = deferredGroupedFieldSetRecord.result;
if (!(deferredGroupedFieldSetResult instanceof BoxedPromiseOrValue)) {
deferredGroupedFieldSetResult = deferredGroupedFieldSetResult();
let completedExecutionGroup = pendingExecutionGroup.result;
if (!(completedExecutionGroup instanceof BoxedPromiseOrValue)) {
completedExecutionGroup = completedExecutionGroup();
}
const value = deferredGroupedFieldSetResult.value;
const value = completedExecutionGroup.value;
if (isPromise(value)) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
value.then((resolved) => this._enqueue(resolved));
Expand Down
57 changes: 25 additions & 32 deletions src/execution/IncrementalPublisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import type { GraphQLError } from '../error/GraphQLError.js';
import { IncrementalGraph } from './IncrementalGraph.js';
import type {
CancellableStreamRecord,
CompletedExecutionGroup,
CompletedResult,
DeferredFragmentRecord,
DeferredGroupedFieldSetResult,
DeliveryGroup,
ExperimentalIncrementalExecutionResults,
IncrementalDataRecord,
IncrementalDataRecordResult,
Expand All @@ -20,12 +21,11 @@ import type {
PendingResult,
StreamItemsResult,
SubsequentIncrementalExecutionResult,
SubsequentResultRecord,
} from './types.js';
import {
isCancellableStreamRecord,
isDeferredGroupedFieldSetResult,
isNonReconcilableDeferredGroupedFieldSetResult,
isCompletedExecutionGroup,
isFailedExecutionGroup,
} from './types.js';

export function buildIncrementalResponse(
Expand Down Expand Up @@ -92,7 +92,7 @@ class IncrementalPublisher {
}

private _toPendingResults(
newRootNodes: ReadonlyArray<SubsequentResultRecord>,
newRootNodes: ReadonlyArray<DeliveryGroup>,
): Array<PendingResult> {
const pendingResults: Array<PendingResult> = [];
for (const node of newRootNodes) {
Expand Down Expand Up @@ -207,27 +207,20 @@ class IncrementalPublisher {
completedIncrementalData: IncrementalDataRecordResult,
context: SubsequentIncrementalExecutionResultContext,
): void {
if (isDeferredGroupedFieldSetResult(completedIncrementalData)) {
this._handleCompletedDeferredGroupedFieldSet(
completedIncrementalData,
context,
);
if (isCompletedExecutionGroup(completedIncrementalData)) {
this._handleCompletedExecutionGroup(completedIncrementalData, context);
} else {
this._handleCompletedStreamItems(completedIncrementalData, context);
}
}

private _handleCompletedDeferredGroupedFieldSet(
deferredGroupedFieldSetResult: DeferredGroupedFieldSetResult,
private _handleCompletedExecutionGroup(
completedExecutionGroup: CompletedExecutionGroup,
context: SubsequentIncrementalExecutionResultContext,
): void {
if (
isNonReconcilableDeferredGroupedFieldSetResult(
deferredGroupedFieldSetResult,
)
) {
for (const deferredFragmentRecord of deferredGroupedFieldSetResult
.deferredGroupedFieldSetRecord.deferredFragmentRecords) {
if (isFailedExecutionGroup(completedExecutionGroup)) {
for (const deferredFragmentRecord of completedExecutionGroup
.pendingExecutionGroup.deferredFragmentRecords) {
const id = deferredFragmentRecord.id;
if (
!this._incrementalGraph.removeDeferredFragment(deferredFragmentRecord)
Expand All @@ -238,18 +231,18 @@ class IncrementalPublisher {
invariant(id !== undefined);
context.completed.push({
id,
errors: deferredGroupedFieldSetResult.errors,
errors: completedExecutionGroup.errors,
});
}
return;
}

this._incrementalGraph.addCompletedReconcilableDeferredGroupedFieldSet(
deferredGroupedFieldSetResult,
this._incrementalGraph.addCompletedSuccessfulExecutionGroup(
completedExecutionGroup,
);

for (const deferredFragmentRecord of deferredGroupedFieldSetResult
.deferredGroupedFieldSetRecord.deferredFragmentRecords) {
for (const deferredFragmentRecord of completedExecutionGroup
.pendingExecutionGroup.deferredFragmentRecords) {
const completion = this._incrementalGraph.completeDeferredFragment(
deferredFragmentRecord,
);
Expand All @@ -259,16 +252,16 @@ class IncrementalPublisher {
const id = deferredFragmentRecord.id;
invariant(id !== undefined);
const incremental = context.incremental;
const { newRootNodes, reconcilableResults } = completion;
const { newRootNodes, successfulExecutionGroups } = completion;
context.pending.push(...this._toPendingResults(newRootNodes));
for (const reconcilableResult of reconcilableResults) {
for (const successfulExecutionGroup of successfulExecutionGroups) {
const { bestId, subPath } = this._getBestIdAndSubPath(
id,
deferredFragmentRecord,
reconcilableResult,
successfulExecutionGroup,
);
const incrementalEntry: IncrementalDeferResult = {
...reconcilableResult.result,
...successfulExecutionGroup.result,
id: bestId,
};
if (subPath !== undefined) {
Expand Down Expand Up @@ -329,13 +322,13 @@ class IncrementalPublisher {
private _getBestIdAndSubPath(
initialId: string,
initialDeferredFragmentRecord: DeferredFragmentRecord,
deferredGroupedFieldSetResult: DeferredGroupedFieldSetResult,
completedExecutionGroup: CompletedExecutionGroup,
): { bestId: string; subPath: ReadonlyArray<string | number> | undefined } {
let maxLength = pathToArray(initialDeferredFragmentRecord.path).length;
let bestId = initialId;

for (const deferredFragmentRecord of deferredGroupedFieldSetResult
.deferredGroupedFieldSetRecord.deferredFragmentRecords) {
for (const deferredFragmentRecord of completedExecutionGroup
.pendingExecutionGroup.deferredFragmentRecords) {
if (deferredFragmentRecord === initialDeferredFragmentRecord) {
continue;
}
Expand All @@ -352,7 +345,7 @@ class IncrementalPublisher {
bestId = id;
}
}
const subPath = deferredGroupedFieldSetResult.path.slice(maxLength);
const subPath = completedExecutionGroup.path.slice(maxLength);
return {
bestId,
subPath: subPath.length > 0 ? subPath : undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import type {

export type DeferUsageSet = ReadonlySet<DeferUsage>;

export interface FieldPlan {
export interface ExecutionPlan {
groupedFieldSet: GroupedFieldSet;
newGroupedFieldSets: Map<DeferUsageSet, GroupedFieldSet>;
}

export function buildFieldPlan(
export function buildExecutionPlan(
originalGroupedFieldSet: GroupedFieldSet,
parentDeferUsages: DeferUsageSet = new Set<DeferUsage>(),
): FieldPlan {
): ExecutionPlan {
const groupedFieldSet = new Map<string, FieldGroup>();
const newGroupedFieldSets = new Map<DeferUsageSet, Map<string, FieldGroup>>();
for (const [responseKey, fieldGroup] of originalGroupedFieldSet) {
Expand Down
Loading
Loading