Skip to content

Commit

Permalink
polish: revamp plan nomenclature (#129)
Browse files Browse the repository at this point in the history
Naming! It's difficult.

With these changes, hopefully the mental model of our plans is better represented. A RootPlan contains a set of  SubschemaPlans for each individual subschema, which in turn have a FieldTree, a map of fields to type-dependent  SubschemaPlans necessary to patch a subschema response with the data from the other subschemas necessary to complete the request as well as a nested fieldTree to do the same for subfields from the original subschema.

Another advantage is less overloading of the stitch term!
  • Loading branch information
yaacovCR authored Sep 19, 2023
1 parent 7c07238 commit 167d86c
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 112 deletions.
89 changes: 43 additions & 46 deletions src/stitch/Planner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,35 @@ import { memoize3 } from '../utilities/memoize3.js';

import type { Subschema, SuperSchema } from './SuperSchema.js';

export interface FieldPlan {
export interface RootPlan {
superSchema: SuperSchema;
subschemaPlans: ReadonlyArray<SubschemaPlan>;
stitchPlans: ObjMap<StitchPlan>;
}

export interface MutableFieldPlan {
superSchema: SuperSchema;
subschemaPlans: Map<Subschema, SubschemaPlan>;
stitchPlans: ObjMap<StitchPlan>;
}

export interface SubschemaPlan {
toSubschema: Subschema;
fromSubschema: Subschema | undefined;
fieldNodes: Array<FieldNode>;
stitchPlans: ObjMap<StitchPlan>;
fieldTree: ObjMap<Map<GraphQLObjectType, FieldPlan>>;
}

export interface FieldPlan {
superSchema: SuperSchema;
subschemaPlans: ReadonlyArray<SubschemaPlan>;
fieldTree: ObjMap<Map<GraphQLObjectType, FieldPlan>>;
}

interface MutableFieldPlan {
superSchema: SuperSchema;
subschemaPlans: Map<Subschema, SubschemaPlan>;
fieldTree: ObjMap<Map<GraphQLObjectType, FieldPlan>>;
}

interface SelectionSplit {
ownSelections: ReadonlyArray<SelectionNode>;
otherSelections: ReadonlyArray<SelectionNode>;
}

export type StitchPlan = Map<GraphQLObjectType, FieldPlan>;

const emptyObject = {};

export const createPlanner = memoize2(
Expand All @@ -70,10 +73,8 @@ export class Planner {
operation: OperationDefinitionNode;
variableDefinitions: ReadonlyArray<VariableDefinitionNode>;

_createFieldPlan = memoize2(this._createFieldPlanImpl.bind(this));
_createSupplementalFieldPlan = memoize3(
this._createSupplementalFieldPlanImpl.bind(this),
);
_createRootPlan = memoize2(this._createRootPlanImpl.bind(this));
_createFieldPlan = memoize3(this._createFieldPlanImpl.bind(this));

_collectSubFields = memoize2(this._collectSubFieldsImpl.bind(this));

Expand All @@ -83,11 +84,11 @@ export class Planner {
this.variableDefinitions = operation.variableDefinitions ?? [];
}

createRootFieldPlan(
createRootPlan(
variableValues: {
[key: string]: unknown;
} = emptyObject,
): FieldPlan | GraphQLError {
): RootPlan | GraphQLError {
const rootType = this.superSchema.getRootType(this.operation.operation);

if (rootType === undefined) {
Expand All @@ -107,7 +108,7 @@ export class Planner {
filteredOperation.selectionSet.selections,
);

return this._createFieldPlan(rootType, fieldNodes);
return this._createRootPlan(rootType, fieldNodes);
}

_collectSubFieldsImpl(
Expand Down Expand Up @@ -172,14 +173,14 @@ export class Planner {
return false;
}

_createFieldPlanImpl(
_createRootPlanImpl(
parentType: GraphQLCompositeType,
fieldNodes: ReadonlyArray<FieldNode>,
): FieldPlan {
const fieldPlan: MutableFieldPlan = {
superSchema: this.superSchema,
subschemaPlans: new Map<Subschema, SubschemaPlan>(),
stitchPlans: Object.create(null),
fieldTree: Object.create(null),
};

for (const fieldNode of fieldNodes) {
Expand All @@ -189,19 +190,19 @@ export class Planner {
return {
superSchema: fieldPlan.superSchema,
subschemaPlans: [...fieldPlan.subschemaPlans.values()],
stitchPlans: fieldPlan.stitchPlans,
fieldTree: fieldPlan.fieldTree,
};
}

_createSupplementalFieldPlanImpl(
_createFieldPlanImpl(
parentType: GraphQLCompositeType,
fieldNodes: ReadonlyArray<FieldNode>,
fromSubschema: Subschema,
): FieldPlan {
const fieldPlan: MutableFieldPlan = {
superSchema: this.superSchema,
subschemaPlans: new Map<Subschema, SubschemaPlan>(),
stitchPlans: Object.create(null),
fieldTree: Object.create(null),
};

for (const fieldNode of fieldNodes) {
Expand All @@ -216,7 +217,7 @@ export class Planner {
return {
superSchema: fieldPlan.superSchema,
subschemaPlans: [...fieldPlan.subschemaPlans.values()],
stitchPlans: fieldPlan.stitchPlans,
fieldTree: fieldPlan.fieldTree,
};
}

Expand Down Expand Up @@ -264,7 +265,7 @@ export class Planner {
fromSubschema,
);

const stitchPlan = this._createStitchPlan(
const fieldPlansByType = this._createStitchPlan(
namedFieldType,
selectionSplit.otherSelections,
subschema,
Expand All @@ -288,28 +289,28 @@ export class Planner {
splitField,
);

if (stitchPlan.size > 0) {
if (fieldPlansByType.size > 0) {
const responseKey = field.alias?.value ?? field.name.value;

if (subschema === fromSubschema) {
fieldPlan.stitchPlans[responseKey] = stitchPlan;
fieldPlan.fieldTree[responseKey] = fieldPlansByType;
} else {
subschemaPlan.stitchPlans[responseKey] = stitchPlan;
subschemaPlan.fieldTree[responseKey] = fieldPlansByType;
}
}
} else if (stitchPlan.size > 0) {
} else if (fieldPlansByType.size > 0) {
const responseKey = field.alias?.value ?? field.name.value;

if (subschema !== undefined && subschema === fromSubschema) {
fieldPlan.stitchPlans[responseKey] = stitchPlan;
if (subschema === fromSubschema) {
fieldPlan.fieldTree[responseKey] = fieldPlansByType;
} else {
const { subschemaPlan } = this._getSubschemaAndPlan(
subschemas,
subschemaPlans,
fromSubschema,
);

subschemaPlan.stitchPlans[responseKey] = stitchPlan;
subschemaPlan.fieldTree[responseKey] = fieldPlansByType;
}
}
}
Expand All @@ -330,9 +331,9 @@ export class Planner {

const subschemaPlan: SubschemaPlan = {
toSubschema: subschema,
fromSubschema,
fromSubschema: fromSubschema as Subschema,
fieldNodes: emptyArray as Array<FieldNode>,
stitchPlans: Object.create(null),
fieldTree: Object.create(null),
};
subschemaPlans.set(subschema, subschemaPlan);

Expand Down Expand Up @@ -364,9 +365,9 @@ export class Planner {
}
subschemaPlan = {
toSubschema: subschema,
fromSubschema,
fromSubschema: fromSubschema as Subschema,
fieldNodes: emptyArray as Array<FieldNode>,
stitchPlans: Object.create(null),
fieldTree: Object.create(null),
};
subschemaPlans.set(subschema, subschemaPlan);

Expand All @@ -377,8 +378,8 @@ export class Planner {
parentType: GraphQLCompositeType,
otherSelections: ReadonlyArray<SelectionNode>,
subschema: Subschema,
): StitchPlan {
const stitchPlan = new Map<GraphQLObjectType, FieldPlan>();
): Map<GraphQLObjectType, FieldPlan> {
const fieldPlansByType = new Map<GraphQLObjectType, FieldPlan>();

let possibleTypes: ReadonlyArray<GraphQLObjectType>;
if (isAbstractType(parentType)) {
Expand All @@ -390,21 +391,17 @@ export class Planner {
for (const type of possibleTypes) {
const fieldNodes = this._collectSubFields(type, otherSelections);

const fieldPlan = this._createSupplementalFieldPlan(
type,
fieldNodes,
subschema,
);
const fieldPlan = this._createFieldPlan(type, fieldNodes, subschema);

if (
fieldPlan.subschemaPlans.length > 0 ||
Object.values(fieldPlan.stitchPlans).length > 0
Object.values(fieldPlan.fieldTree).length > 0
) {
stitchPlan.set(type, fieldPlan);
fieldPlansByType.set(type, fieldPlan);
}
}

return stitchPlan;
return fieldPlansByType;
}

_createSelectionSplit(
Expand Down
32 changes: 16 additions & 16 deletions src/stitch/__tests__/Planner-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { dedent } from '../../__testUtils__/dedent.js';

import { invariant } from '../../utilities/invariant.js';

import type { FieldPlan } from '../Planner.js';
import type { RootPlan } from '../Planner.js';
import { Planner } from '../Planner.js';
import { printPlan } from '../printPlan.js';
import type { Subschema } from '../SuperSchema.js';
Expand All @@ -30,21 +30,21 @@ function getSubschema(schema: GraphQLSchema): Subschema {
};
}

function createFieldPlan(
function createRootPlan(
superSchema: SuperSchema,
operation: OperationDefinitionNode,
): FieldPlan {
): RootPlan {
const queryType = superSchema.getRootType(OperationTypeNode.QUERY);

invariant(queryType !== undefined);

const planner = new Planner(superSchema, operation);

const fieldPlan = planner.createRootFieldPlan();
const rootPlan = planner.createRootPlan();

invariant(!(fieldPlan instanceof GraphQLError));
invariant(!(rootPlan instanceof GraphQLError));

return fieldPlan;
return rootPlan;
}

describe('FieldPlan', () => {
Expand Down Expand Up @@ -83,9 +83,9 @@ describe('FieldPlan', () => {
{ noLocation: true },
).definitions[0] as OperationDefinitionNode;

const fieldPlan = createFieldPlan(superSchema, operation);
const plan = createRootPlan(superSchema, operation);

expect(printPlan(fieldPlan)).to.equal(dedent`
expect(printPlan(plan)).to.equal(dedent`
Plan:
For Subschema: [0]
FieldNodes:
Expand Down Expand Up @@ -148,9 +148,9 @@ describe('FieldPlan', () => {
{ noLocation: true },
).definitions[0] as OperationDefinitionNode;

const fieldPlan = createFieldPlan(superSchema, operation);
const plan = createRootPlan(superSchema, operation);

expect(printPlan(fieldPlan)).to.equal(dedent`
expect(printPlan(plan)).to.equal(dedent`
Plan:
For Subschema: [0]
FieldNodes:
Expand Down Expand Up @@ -211,9 +211,9 @@ describe('FieldPlan', () => {
{ noLocation: true },
).definitions[0] as OperationDefinitionNode;

const fieldPlan = createFieldPlan(superSchema, operation);
const plan = createRootPlan(superSchema, operation);

expect(printPlan(fieldPlan)).to.equal(dedent`
expect(printPlan(plan)).to.equal(dedent`
Plan:
For Subschema: [0]
FieldNodes:
Expand Down Expand Up @@ -294,9 +294,9 @@ describe('FieldPlan', () => {
{ noLocation: true },
).definitions[0] as OperationDefinitionNode;

const fieldPlan = createFieldPlan(superSchema, operation);
const plan = createRootPlan(superSchema, operation);

expect(printPlan(fieldPlan)).to.equal(dedent`
expect(printPlan(plan)).to.equal(dedent`
Plan:
For Subschema: [0]
FieldNodes:
Expand Down Expand Up @@ -371,9 +371,9 @@ describe('FieldPlan', () => {
{ noLocation: true },
).definitions[0] as OperationDefinitionNode;

const fieldPlan = createFieldPlan(superSchema, operation);
const plan = createRootPlan(superSchema, operation);

expect(printPlan(fieldPlan)).to.equal(dedent`
expect(printPlan(plan)).to.equal(dedent`
Plan:
For Subschema: [0]
FieldNodes:
Expand Down
8 changes: 4 additions & 4 deletions src/stitch/__tests__/compose-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ function executeWithComposer(

invariant(queryType !== undefined);

const fieldPlan = new Planner(superSchema, operation).createRootFieldPlan();
const plan = new Planner(superSchema, operation).createRootPlan();

invariant(!(fieldPlan instanceof GraphQLError));
invariant(!(plan instanceof GraphQLError));

const subschemaPlanResults: Array<SubschemaPlanResult> = [];

for (const subschemaPlan of fieldPlan.subschemaPlans) {
for (const subschemaPlan of plan.subschemaPlans) {
const document: DocumentNode = {
kind: Kind.DOCUMENT,
definitions: [
Expand All @@ -72,7 +72,7 @@ function executeWithComposer(
});
}

return compose(subschemaPlanResults, fieldPlan.superSchema, undefined);
return compose(subschemaPlanResults, plan.superSchema, undefined);
}

describe('Composer', () => {
Expand Down
Loading

0 comments on commit 167d86c

Please sign in to comment.