@apollo/query-graphs
Advanced tools
Comparing version 2.0.0-alpha.1 to 2.0.0-alpha.2
@@ -40,2 +40,3 @@ import { NamedType, OperationElement, Schema, SchemaRootKind, SelectionSet, ObjectType } from "@apollo/federation-internals"; | ||
isOnTopLevelQueryRoot(): boolean; | ||
truncateTrailingDowncasts(): GraphPath<TTrigger, RV, TNullEdge>; | ||
toString(): string; | ||
@@ -52,2 +53,3 @@ } | ||
export declare function isRootPath(path: OpGraphPath<any>): path is OpRootPath; | ||
export declare function terminateWithNonRequestedTypenameField<V extends Vertex>(path: OpGraphPath<V>): OpGraphPath<V>; | ||
export declare function traversePath(path: GraphPath<any>, onEdges: (edge: Edge) => void): void; | ||
@@ -54,0 +56,0 @@ export declare type ConditionResolver = (edge: Edge, context: PathContext, excludedEdges: ExcludedEdges, excludedConditions: ExcludedConditions) => ConditionResolution; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.advanceSimultaneousPathsWithOperation = exports.advanceOptionsToString = exports.simultaneousPathsToString = exports.SimultaneousPathsWithLazyIndirectPaths = exports.additionalKeyEdgeForRequireEdge = exports.addConditionExclusion = exports.sameExcludedEdges = exports.advancePathWithTransition = exports.isUnadvanceable = exports.Unadvanceables = exports.UnadvanceableReason = exports.unsatisfiedConditionsResolution = exports.noConditionsResolution = exports.traversePath = exports.isRootPath = exports.GraphPath = void 0; | ||
exports.advanceSimultaneousPathsWithOperation = exports.advanceOptionsToString = exports.simultaneousPathsToString = exports.SimultaneousPathsWithLazyIndirectPaths = exports.additionalKeyEdgeForRequireEdge = exports.addConditionExclusion = exports.sameExcludedEdges = exports.advancePathWithTransition = exports.isUnadvanceable = exports.Unadvanceables = exports.UnadvanceableReason = exports.unsatisfiedConditionsResolution = exports.noConditionsResolution = exports.traversePath = exports.terminateWithNonRequestedTypenameField = exports.isRootPath = exports.GraphPath = void 0; | ||
const federation_internals_1 = require("@apollo/federation-internals"); | ||
@@ -39,3 +39,3 @@ const pathTree_1 = require("./pathTree"); | ||
return (0, federation_internals_1.possibleRuntimeTypes)(currentType); | ||
case 'QueryResolution': | ||
case 'RootTypeResolution': | ||
case 'SubgraphEnteringTransition': | ||
@@ -89,3 +89,3 @@ (0, federation_internals_1.assert)((0, federation_internals_1.isObjectType)(edge.tail.type), () => `Query edge should be between object type but got ${edge}`); | ||
} | ||
if (edge.transition.kind === 'KeyResolution' || edge.transition.kind === 'QueryResolution') { | ||
if (edge.transition.kind === 'KeyResolution' || edge.transition.kind === 'RootTypeResolution') { | ||
++jumps; | ||
@@ -260,2 +260,28 @@ } | ||
} | ||
truncateTrailingDowncasts() { | ||
let lastNonDowncastIdx = -1; | ||
let v = this.root; | ||
let lastNonDowncastVertex = v; | ||
let lastNonDowncastEdge; | ||
let runtimeTypes = (0, querygraph_1.isFederatedGraphRootType)(this.root.type) ? [] : (0, federation_internals_1.possibleRuntimeTypes)(this.root.type); | ||
let runtimeTypesAtLastNonDowncastEdge = runtimeTypes; | ||
for (let i = 0; i < this.size; i++) { | ||
const edge = this.edgeAt(i, v); | ||
runtimeTypes = updateRuntimeTypes(runtimeTypes, edge); | ||
if (edge) { | ||
v = edge.tail; | ||
if (edge.transition.kind !== 'DownCast') { | ||
lastNonDowncastIdx = i; | ||
lastNonDowncastVertex = v; | ||
lastNonDowncastEdge = edge; | ||
runtimeTypesAtLastNonDowncastEdge = runtimeTypes; | ||
} | ||
} | ||
} | ||
if (lastNonDowncastIdx < 0 || lastNonDowncastIdx === this.size - 1) { | ||
return this; | ||
} | ||
const newSize = lastNonDowncastIdx + 1; | ||
return new GraphPath(this.graph, this.root, lastNonDowncastVertex, this.edgeTriggers.slice(0, newSize), this.edgeIndexes.slice(0, newSize), this.edgeConditions.slice(0, newSize), this.subgraphEnteringEdgeIndex, this.subgraphEnteringEdge, this.subgraphEnteringEdgeCost, lastNonDowncastEdge, runtimeTypesAtLastNonDowncastEdge); | ||
} | ||
toString() { | ||
@@ -284,2 +310,13 @@ const isRoot = (0, querygraph_1.isRootVertex)(this.root); | ||
exports.isRootPath = isRootPath; | ||
function terminateWithNonRequestedTypenameField(path) { | ||
path = path.truncateTrailingDowncasts(); | ||
if (!(0, federation_internals_1.isCompositeType)(path.tail.type)) { | ||
return path; | ||
} | ||
const typenameField = new federation_internals_1.Field(path.tail.type.typenameField()); | ||
const edge = edgeForField(path.graph, path.tail, typenameField); | ||
(0, federation_internals_1.assert)(edge, () => `We should have an edge from ${path.tail} for ${typenameField}`); | ||
return path.add(typenameField, edge, exports.noConditionsResolution); | ||
} | ||
exports.terminateWithNonRequestedTypenameField = terminateWithNonRequestedTypenameField; | ||
function traversePath(path, onEdges) { | ||
@@ -483,4 +520,4 @@ for (const [edge, _, conditions] of path) { | ||
} | ||
if (isTopLevelPath && edge.transition.kind === 'QueryResolution') { | ||
debug.groupEnd(`Ignored: edge is a top-level "QueryResolution"`); | ||
if (isTopLevelPath && edge.transition.kind === 'RootTypeResolution') { | ||
debug.groupEnd(`Ignored: edge is a top-level "RootTypeResolution"`); | ||
continue; | ||
@@ -648,4 +685,4 @@ } | ||
const printedFields = keyFieldMarkedExternal.map(f => `"${f}"`).join(', '); | ||
const fieldWithPlurar = keyFieldMarkedExternal.length === 1 ? 'field' : 'fields'; | ||
return ` (please ensure that this is not due to key ${fieldWithPlurar} ${printedFields} being accidentally marked @external)`; | ||
const fieldWithPlural = keyFieldMarkedExternal.length === 1 ? 'field' : 'fields'; | ||
return ` (please ensure that this is not due to key ${fieldWithPlural} ${printedFields} being accidentally marked @external)`; | ||
} | ||
@@ -715,3 +752,2 @@ function additionalKeyEdgeForRequireEdge(graph, requireEdge) { | ||
exports.SimultaneousPathsWithLazyIndirectPaths = SimultaneousPathsWithLazyIndirectPaths; | ||
; | ||
function simultaneousPathsToString(simultaneousPaths, indentOnNewLine = "") { | ||
@@ -748,3 +784,3 @@ const paths = Array.isArray(simultaneousPaths) ? simultaneousPaths : simultaneousPaths.paths; | ||
debug.group(() => `Direct options`); | ||
let options = advanceOneWithOperation(supergraphSchema, path, operation, updatedContext, subgraphSimultaneousPaths.conditionResolver); | ||
let options = advanceWithOperation(supergraphSchema, path, operation, updatedContext, subgraphSimultaneousPaths.conditionResolver); | ||
debug.groupEnd(() => advanceOptionsToString(options)); | ||
@@ -766,3 +802,3 @@ if (options && (options.length === 0 || isTerminalOperation(operation) || operation.kind === 'FragmentElement')) { | ||
debug.group(() => `For indirect path ${pathWithNonCollecting}:`); | ||
const pathWithOperation = advanceOneWithOperation(supergraphSchema, pathWithNonCollecting, operation, updatedContext, subgraphSimultaneousPaths.conditionResolver); | ||
const pathWithOperation = advanceWithOperation(supergraphSchema, pathWithNonCollecting, operation, updatedContext, subgraphSimultaneousPaths.conditionResolver); | ||
if (!pathWithOperation) { | ||
@@ -826,3 +862,3 @@ debug.groupEnd(() => `Ignoring: cannot be advanced with ${operation}`); | ||
let itemSize = 0; | ||
for (var j = 0; j < size; ++j) { | ||
for (let j = 0; j < size; ++j) { | ||
itemSize += arr[j][eltIndexes[j]].length; | ||
@@ -832,3 +868,3 @@ } | ||
let k = 0; | ||
for (var j = 0; j < size; ++j) { | ||
for (let j = 0; j < size; ++j) { | ||
for (const v of arr[j][eltIndexes[j]]) { | ||
@@ -860,3 +896,6 @@ item[k++] = v; | ||
} | ||
function advanceOneWithOperation(supergraphSchema, path, operation, context, conditionResolver) { | ||
function isProvidedEdge(edge) { | ||
return edge.transition.kind === 'FieldCollection' && edge.transition.isPartOfProvide; | ||
} | ||
function advanceWithOperation(supergraphSchema, path, operation, context, conditionResolver) { | ||
debug.group(() => `Trying to advance ${path} directly with ${operation}`); | ||
@@ -878,5 +917,5 @@ const currentType = path.tail.type; | ||
const fieldOptions = addFieldEdge(path, operation, edge, conditionResolver, context); | ||
debug.groupEnd(() => fieldOptions.length === 0 | ||
? `Cannot satisfy @requires on field ${field} for object type ${currentType}` | ||
: `Collected field ${field} on object type ${currentType}`); | ||
debug.groupEnd(() => fieldOptions | ||
? `Collected field ${field} on object type ${currentType}` | ||
: `Cannot satisfy @requires on field ${field} for object type ${currentType}`); | ||
return fieldOptions; | ||
@@ -888,3 +927,4 @@ case 'InterfaceType': | ||
itfOptions = addFieldEdge(path, operation, itfEdge, conditionResolver, context); | ||
if (field.name === federation_internals_1.typenameFieldName || !anImplementationHasAProvides(field.name, currentType)) { | ||
(0, federation_internals_1.assert)(itfOptions, () => `Interface edge ${itfEdge} shouldn't have conditions`); | ||
if (field.name === federation_internals_1.typenameFieldName || (!isProvidedEdge(itfEdge) && !anImplementationHasAProvides(field.name, currentType))) { | ||
debug.groupEnd(() => `Collecting field ${field} on interface ${currentType} without type-exploding`); | ||
@@ -1011,3 +1051,3 @@ return itfOptions; | ||
const conditionResolution = canSatisfyConditions(path, edge, conditionResolver, context, [], []); | ||
return conditionResolution.satisfied ? [[path.add(fieldOperation, edge, conditionResolution)]] : []; | ||
return conditionResolution.satisfied ? [[path.add(fieldOperation, edge, conditionResolution)]] : undefined; | ||
} | ||
@@ -1014,0 +1054,0 @@ function nextEdgeForField(path, field) { |
@@ -95,3 +95,3 @@ "use strict"; | ||
}; | ||
(0, querygraph_1.simpleTraversal)(graph, _ => { }, onEdge); | ||
(0, querygraph_1.simpleTraversal)(graph, _ => undefined, onEdge); | ||
return state; | ||
@@ -98,0 +98,0 @@ } |
@@ -61,3 +61,3 @@ "use strict"; | ||
} | ||
let forIndex = forEdgeIndex[idx]; | ||
const forIndex = forEdgeIndex[idx]; | ||
if (forIndex) { | ||
@@ -91,3 +91,3 @@ const triggerIdx = findTriggerIdx(triggerEquality, forIndex, trigger); | ||
const values = forEdgeIndex[edgeIndex]; | ||
for (let [trigger, conditions, subPaths] of values) { | ||
for (const [trigger, conditions, subPaths] of values) { | ||
childs[idx++] = { | ||
@@ -120,3 +120,3 @@ index, | ||
} | ||
let forIndex = forEdgeIndex[idx]; | ||
const forIndex = forEdgeIndex[idx]; | ||
if (forIndex) { | ||
@@ -151,3 +151,3 @@ const triggerIdx = findTriggerIdx(triggerEquality, forIndex, child.trigger); | ||
const values = forEdgeIndex[edgeIndex]; | ||
for (let [trigger, conditions, subTrees] of values) { | ||
for (const [trigger, conditions, subTrees] of values) { | ||
childs[idx++] = { | ||
@@ -258,3 +258,3 @@ index, | ||
(0, federation_internals_1.assert)(other.graph === this.graph, 'Cannot concat path tree build on another graph'); | ||
(0, federation_internals_1.assert)(other.vertex.index === this.vertex.index, () => `Cannot contat path tree rooted at vertex ${other.vertex} into tree rooted at other vertex ${this.vertex}`); | ||
(0, federation_internals_1.assert)(other.vertex.index === this.vertex.index, () => `Cannot concat path tree rooted at vertex ${other.vertex} into tree rooted at other vertex ${this.vertex}`); | ||
if (!other.childs.length) { | ||
@@ -261,0 +261,0 @@ return this; |
@@ -26,3 +26,3 @@ import { MultiMap, NamedType, Schema, SchemaRootKind, SelectionSet, MapWithCachedArrays } from '@apollo/federation-internals'; | ||
get conditions(): SelectionSet | undefined; | ||
isEdgeForField(name: String): boolean; | ||
isEdgeForField(name: string): boolean; | ||
matchesSupergraphTransition(supergraph: Schema, otherTransition: Transition): boolean; | ||
@@ -29,0 +29,0 @@ label(): string; |
@@ -190,6 +190,5 @@ "use strict"; | ||
const subgraphs = (0, federation_internals_1.extractSubgraphsFromSupergraph)(supergraph); | ||
let graphs = []; | ||
for (let subgraph of subgraphs) { | ||
const graphs = []; | ||
for (const subgraph of subgraphs) { | ||
graphs.push(buildGraphInternal(subgraph.name, subgraph.schema, forQueryPlanning, supergraph)); | ||
; | ||
} | ||
@@ -203,3 +202,3 @@ return federateSubgraphs(graphs); | ||
const schemas = []; | ||
for (let subgraph of subgraphs) { | ||
for (const subgraph of subgraphs) { | ||
vertices += subgraph.verticesCount(); | ||
@@ -217,18 +216,18 @@ subgraph.rootKinds().forEach(k => rootKinds.add(k)); | ||
const copyPointers = new Array(subgraphs.length); | ||
for (let [i, subgraph] of subgraphs.entries()) { | ||
for (const [i, subgraph] of subgraphs.entries()) { | ||
copyPointers[i] = builder.copyGraph(subgraph); | ||
} | ||
for (let [i, subgraph] of subgraphs.entries()) { | ||
for (const [i, subgraph] of subgraphs.entries()) { | ||
const copyPointer = copyPointers[i]; | ||
subgraph.rootKinds().forEach(k => builder.addEdge(builder.root(k), copyPointer.copiedVertex(subgraph.root(k)), transition_1.subgraphEnteringTransition)); | ||
const queryRoot = subgraph.root("query"); | ||
if (queryRoot) { | ||
for (let [j, otherSubgraph] of subgraphs.entries()) { | ||
for (const rootKind of subgraph.rootKinds()) { | ||
const rootVertex = copyPointer.copiedVertex(subgraph.root(rootKind)); | ||
builder.addEdge(builder.root(rootKind), rootVertex, transition_1.subgraphEnteringTransition); | ||
for (const [j, otherSubgraph] of subgraphs.entries()) { | ||
if (i === j) { | ||
continue; | ||
} | ||
const otherQueryRoot = otherSubgraph.root("query"); | ||
if (otherQueryRoot) { | ||
const otherRootVertex = otherSubgraph.root(rootKind); | ||
if (otherRootVertex) { | ||
const otherCopyPointer = copyPointers[j]; | ||
builder.addEdge(copyPointer.copiedVertex(queryRoot), otherCopyPointer.copiedVertex(otherQueryRoot), new transition_1.QueryResolution()); | ||
builder.addEdge(rootVertex, otherCopyPointer.copiedVertex(otherRootVertex), new transition_1.RootTypeResolution(rootKind)); | ||
} | ||
@@ -238,3 +237,3 @@ } | ||
} | ||
for (let [i, subgraph] of subgraphs.entries()) { | ||
for (const [i, subgraph] of subgraphs.entries()) { | ||
const subgraphSchema = schemas[i]; | ||
@@ -248,3 +247,3 @@ const keyDirective = federation_internals_1.federationBuiltIns.keyDirective(subgraphSchema); | ||
const conditions = (0, federation_internals_1.parseFieldSetArgument)(type, keyApplication); | ||
for (let [j, otherSubgraph] of subgraphs.entries()) { | ||
for (const [j, otherSubgraph] of subgraphs.entries()) { | ||
if (i == j) { | ||
@@ -278,6 +277,6 @@ continue; | ||
} | ||
for (let [i, subgraph] of subgraphs.entries()) { | ||
for (const [i, subgraph] of subgraphs.entries()) { | ||
const subgraphSchema = schemas[i]; | ||
const providesDirective = federation_internals_1.federationBuiltIns.providesDirective(subgraphSchema); | ||
simpleTraversal(subgraph, _ => { }, e => { | ||
simpleTraversal(subgraph, _ => undefined, e => { | ||
if (e.transition.kind === 'FieldCollection') { | ||
@@ -289,3 +288,3 @@ const type = e.head.type; | ||
const fieldType = (0, federation_internals_1.baseType)(field.type); | ||
(0, federation_internals_1.assert)((0, federation_internals_1.isInterfaceType)(fieldType) || (0, federation_internals_1.isObjectType)(fieldType), () => `Invalid @provide on field "${field}" whose type "${fieldType}" is not an object or interface`); | ||
(0, federation_internals_1.assert)((0, federation_internals_1.isCompositeType)(fieldType), () => `Invalid @provide on field "${field}" whose type "${fieldType}" is not a composite type`); | ||
const provided = (0, federation_internals_1.parseFieldSetArgument)(fieldType, providesApplication); | ||
@@ -314,15 +313,22 @@ const head = copyPointers[i].copiedVertex(e.head); | ||
const fieldDef = element.definition; | ||
if (!fieldDef.hasAppliedDirective(federation_internals_1.externalDirectiveName)) { | ||
continue; | ||
const existingEdge = builder.edges(v).find(e => e.transition.kind === 'FieldCollection' && e.transition.definition.name === fieldDef.name); | ||
if (existingEdge) { | ||
if (selection.selectionSet) { | ||
const copiedTail = builder.makeCopy(existingEdge.tail); | ||
builder.updateEdgeTail(existingEdge, copiedTail); | ||
stack.push([copiedTail, selection.selectionSet]); | ||
} | ||
} | ||
const fieldType = (0, federation_internals_1.baseType)(fieldDef.type); | ||
if (selection.selectionSet) { | ||
const newVertex = builder.createNewVertex(fieldType, source, schema); | ||
builder.addEdge(v, newVertex, new transition_1.FieldCollection(fieldDef)); | ||
stack.push([newVertex, selection.selectionSet]); | ||
} | ||
else { | ||
const existing = builder.verticesForType(fieldType.name).find(v => v.source === source); | ||
const vertex = existing ? existing : builder.createNewVertex(fieldType, v.source, schema); | ||
builder.addEdge(v, vertex, new transition_1.FieldCollection(fieldDef)); | ||
const fieldType = (0, federation_internals_1.baseType)(fieldDef.type); | ||
const existingTail = builder.verticesForType(fieldType.name).find(v => v.source === source); | ||
const newTail = existingTail ? existingTail : builder.createNewVertex(fieldType, v.source, schema); | ||
if (selection.selectionSet) { | ||
const copiedTail = existingTail ? builder.makeCopy(existingTail) : newTail; | ||
builder.addEdge(v, copiedTail, new transition_1.FieldCollection(fieldDef, true)); | ||
stack.push([copiedTail, selection.selectionSet]); | ||
} | ||
else { | ||
builder.addEdge(v, newTail, new transition_1.FieldCollection(fieldDef, true)); | ||
} | ||
} | ||
@@ -332,8 +338,12 @@ } | ||
const typeCondition = element.typeCondition; | ||
let newVertex = v; | ||
if (typeCondition) { | ||
newVertex = builder.createNewVertex(typeCondition, source, schema); | ||
builder.addEdge(v, newVertex, new transition_1.DownCast(element.parentType, typeCondition)); | ||
const existingEdge = builder.edges(v).find(e => e.transition.kind === 'DownCast' && e.transition.castedType.name === typeCondition.name); | ||
(0, federation_internals_1.assert)(existingEdge, () => `Shouldn't have ${selection} with no corresponding edge on ${v}`); | ||
const copiedTail = builder.makeCopy(existingEdge.tail); | ||
builder.updateEdgeTail(existingEdge, copiedTail); | ||
stack.push([copiedTail, selection.selectionSet]); | ||
} | ||
stack.push([newVertex, selection.selectionSet]); | ||
else { | ||
stack.push([v, selection.selectionSet]); | ||
} | ||
} | ||
@@ -421,2 +431,5 @@ } | ||
} | ||
edges(head) { | ||
return this.adjacencies[head.index]; | ||
} | ||
makeCopy(vertex) { | ||
@@ -423,0 +436,0 @@ const newVertex = this.createNewVertex(vertex.type, vertex.source, this.sources.get(vertex.source)); |
@@ -1,13 +0,13 @@ | ||
import { FieldDefinition, CompositeType } from "@apollo/federation-internals"; | ||
export declare type Transition = FieldCollection | DownCast | KeyResolution | QueryResolution | SubgraphEnteringTransition; | ||
import { FieldDefinition, CompositeType, SchemaRootKind } from "@apollo/federation-internals"; | ||
export declare type Transition = FieldCollection | DownCast | KeyResolution | RootTypeResolution | SubgraphEnteringTransition; | ||
export declare class KeyResolution { | ||
readonly kind: "KeyResolution"; | ||
readonly collectOperationElements: false; | ||
constructor(); | ||
toString(): string; | ||
} | ||
export declare class QueryResolution { | ||
readonly kind: "QueryResolution"; | ||
export declare class RootTypeResolution { | ||
readonly rootKind: SchemaRootKind; | ||
readonly kind: "RootTypeResolution"; | ||
readonly collectOperationElements: false; | ||
constructor(); | ||
constructor(rootKind: SchemaRootKind); | ||
toString(): string; | ||
@@ -17,5 +17,6 @@ } | ||
readonly definition: FieldDefinition<CompositeType>; | ||
readonly isPartOfProvide: boolean; | ||
readonly kind: "FieldCollection"; | ||
readonly collectOperationElements: true; | ||
constructor(definition: FieldDefinition<CompositeType>); | ||
constructor(definition: FieldDefinition<CompositeType>, isPartOfProvide?: boolean); | ||
toString(): string; | ||
@@ -22,0 +23,0 @@ } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.subgraphEnteringTransition = exports.SubgraphEnteringTransition = exports.DownCast = exports.FieldCollection = exports.QueryResolution = exports.KeyResolution = void 0; | ||
exports.subgraphEnteringTransition = exports.SubgraphEnteringTransition = exports.DownCast = exports.FieldCollection = exports.RootTypeResolution = exports.KeyResolution = void 0; | ||
class KeyResolution { | ||
@@ -14,15 +14,17 @@ constructor() { | ||
exports.KeyResolution = KeyResolution; | ||
class QueryResolution { | ||
constructor() { | ||
this.kind = 'QueryResolution'; | ||
class RootTypeResolution { | ||
constructor(rootKind) { | ||
this.rootKind = rootKind; | ||
this.kind = 'RootTypeResolution'; | ||
this.collectOperationElements = false; | ||
} | ||
toString() { | ||
return 'query()'; | ||
return this.rootKind + '()'; | ||
} | ||
} | ||
exports.QueryResolution = QueryResolution; | ||
exports.RootTypeResolution = RootTypeResolution; | ||
class FieldCollection { | ||
constructor(definition) { | ||
constructor(definition, isPartOfProvide = false) { | ||
this.definition = definition; | ||
this.isPartOfProvide = isPartOfProvide; | ||
this.kind = 'FieldCollection'; | ||
@@ -29,0 +31,0 @@ this.collectOperationElements = true; |
{ | ||
"name": "@apollo/query-graphs", | ||
"version": "2.0.0-alpha.1", | ||
"version": "2.0.0-alpha.2", | ||
"description": "Apollo Federation library to work with 'query graphs'", | ||
@@ -26,8 +26,5 @@ "main": "dist/index.js", | ||
"dependencies": { | ||
"@apollo/federation-internals": "^2.0.0-alpha.1", | ||
"ts-graphviz": "^0.15.1" | ||
"@apollo/federation-internals": "^2.0.0-alpha.2", | ||
"ts-graphviz": "^0.16.0" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^26.0.23" | ||
}, | ||
"publishConfig": { | ||
@@ -37,5 +34,5 @@ "access": "public" | ||
"peerDependencies": { | ||
"graphql": "^14.5.0 || ^15.0.0" | ||
"graphql": "^15.7.0" | ||
}, | ||
"gitHead": "5f7184829607024343fb8b8ad0ac4e122407cd3a" | ||
"gitHead": "9265ba09ec5620b931861a44603d7d5f7d4688f2" | ||
} |
@@ -8,3 +8,3 @@ import { assert } from "@apollo/federation-internals"; | ||
// For every edge having a condition, we cache the resolution its conditions when possible. | ||
// We save resolution with the set of exclded edges that were used to compute it: the reason we do this is | ||
// We save resolution with the set of excluded edges that were used to compute it: the reason we do this is | ||
// that excluded edges impact the resolution, so we should only used a cached value if we know the excluded | ||
@@ -11,0 +11,0 @@ // edges are the same as when caching, and while we could decide to cache only when we have no excluded edges |
@@ -112,3 +112,3 @@ /* Functions used to output query graphs as [graphviz dot](https://graphviz.org/doc/info/lang.html) outputs. */ | ||
const tailNode = getNode(tail); | ||
const attributes = { | ||
const attributes = { | ||
[attribute.label]: edge.label(), | ||
@@ -119,3 +119,3 @@ }; | ||
} | ||
simpleTraversal(graph, _ => { }, onEdge); | ||
simpleTraversal(graph, _ => undefined, onEdge); | ||
return state; | ||
@@ -122,0 +122,0 @@ } |
@@ -94,3 +94,3 @@ import { arrayEquals, assert, copyWitNewLength } from "@apollo/federation-internals"; | ||
} | ||
let forIndex = forEdgeIndex[idx]; | ||
const forIndex = forEdgeIndex[idx]; | ||
if (forIndex) { | ||
@@ -125,3 +125,3 @@ const triggerIdx = findTriggerIdx(triggerEquality, forIndex, trigger); | ||
const values = forEdgeIndex[edgeIndex]; | ||
for (let [trigger, conditions, subPaths] of values) { | ||
for (const [trigger, conditions, subPaths] of values) { | ||
childs[idx++] = { | ||
@@ -163,3 +163,3 @@ index, | ||
} | ||
let forIndex = forEdgeIndex[idx]; | ||
const forIndex = forEdgeIndex[idx]; | ||
if (forIndex) { | ||
@@ -195,3 +195,3 @@ const triggerIdx = findTriggerIdx(triggerEquality, forIndex, child.trigger); | ||
const values = forEdgeIndex[edgeIndex]; | ||
for (let [trigger, conditions, subTrees] of values) { | ||
for (const [trigger, conditions, subTrees] of values) { | ||
childs[idx++] = { | ||
@@ -305,3 +305,3 @@ index, | ||
// Note that we use '===' for trigger instead of `triggerEquality`: this method is all about avoid unecessary merging | ||
// Note that we use '===' for trigger instead of `triggerEquality`: this method is all about avoid unnecessary merging | ||
// when we suspect conditions trees have been build from the exact same inputs and `===` is faster and good enough for this. | ||
@@ -316,7 +316,7 @@ return arrayEquals(this.childs, that.childs, (c1, c2) => { | ||
// Like merge(), this create a new tree that contains the content of both `this` and `other` to this pathTree, but contrarily | ||
// Like merge(), this create a new tree that contains the content of both `this` and `other` to this pathTree, but contrarily | ||
// to merge() this never merge childs together, even if they are equal. This is only for the special case of mutations. | ||
concat(other: PathTree<TTrigger, RV, TNullEdge>): PathTree<TTrigger, RV, TNullEdge> { | ||
assert(other.graph === this.graph, 'Cannot concat path tree build on another graph'); | ||
assert(other.vertex.index === this.vertex.index, () => `Cannot contat path tree rooted at vertex ${other.vertex} into tree rooted at other vertex ${this.vertex}`); | ||
assert(other.vertex.index === this.vertex.index, () => `Cannot concat path tree rooted at vertex ${other.vertex} into tree rooted at other vertex ${this.vertex}`); | ||
if (!other.childs.length) { | ||
@@ -323,0 +323,0 @@ return this; |
@@ -36,3 +36,3 @@ import { | ||
import { inspect } from 'util'; | ||
import { DownCast, FieldCollection, subgraphEnteringTransition, SubgraphEnteringTransition, Transition, KeyResolution, QueryResolution } from './transition'; | ||
import { DownCast, FieldCollection, subgraphEnteringTransition, SubgraphEnteringTransition, Transition, KeyResolution, RootTypeResolution } from './transition'; | ||
import { isStructuralFieldSubtype } from './structuralSubtyping'; | ||
@@ -68,3 +68,3 @@ | ||
* An identifier of the underlying schema containing the `type` this vertex points to. | ||
* This is mainly used in "federated" query graphs, where the `souce` is a subgraph name. | ||
* This is mainly used in "federated" query graphs, where the `source` is a subgraph name. | ||
*/ | ||
@@ -139,3 +139,3 @@ readonly source : string | ||
* @see Transition | ||
*/ | ||
*/ | ||
public readonly transition: Transition, | ||
@@ -164,3 +164,3 @@ /** | ||
isEdgeForField(name: String): boolean { | ||
isEdgeForField(name: string): boolean { | ||
return this.transition.kind === 'FieldCollection' && this.transition.definition.name === name; | ||
@@ -223,3 +223,3 @@ } | ||
/** | ||
* An immutable directed graph data structure (built of vertices and edges) that is layered over one or multiple | ||
* An immutable directed graph data structure (built of vertices and edges) that is layered over one or multiple | ||
* graphQL schema, that aims to facilitate reasoning about queries expressed on the underlying schema. | ||
@@ -238,3 +238,3 @@ * | ||
* 2. a "federated" query graph, which is a single graph built on top of a) a number of subgraph | ||
* API schema and b) the additional federation directives on those subgraphs (@see buildFederatedQueryGraph()). | ||
* API schema and b) the additional federation directives on those subgraphs (@see buildFederatedQueryGraph()). | ||
* This query graph is used both for validating composition and for query planning. | ||
@@ -267,3 +267,3 @@ * | ||
/** | ||
* A map that associate type names of the underlying schema on which this query graph was built to each of the vertex | ||
* A map that associate type names of the underlying schema on which this query graph was built to each of the vertex | ||
* (vertex index) that points to a type of that name. Note that in a "supergraph query graph", each type name will only | ||
@@ -277,3 +277,3 @@ * map to a single vertex, | ||
* The sources on which the query graph was built, that is a set (which can be of size 1) of graphQL schema keyed by | ||
* the name identifying them. Note that the `source` string in the `Vertex` of a query graph is guaranteed to be | ||
* the name identifying them. Note that the `source` string in the `Vertex` of a query graph is guaranteed to be | ||
* valid key in this map. | ||
@@ -298,3 +298,3 @@ */ | ||
/** | ||
* The set of `SchemaRootKind` for which this query graph has a root vertex (for | ||
* The set of `SchemaRootKind` for which this query graph has a root vertex (for | ||
* which `root(SchemaRootKind)` will _not_ return `undefined`). | ||
@@ -372,3 +372,3 @@ */ | ||
* @param EdgeState - the type of the state associated to edges. Defaults to `undefined`, which | ||
* means that state is only associated to vertices. | ||
* means that state is only associated to vertices. | ||
*/ | ||
@@ -391,4 +391,4 @@ export class QueryGraphState<VertexState, EdgeState = undefined> { | ||
* | ||
* @param vertex - the vertex to which state should be associated. This method _assumes_ | ||
* that the provided vertex is a vertex of the query graph against which this | ||
* @param vertex - the vertex to which state should be associated. This method _assumes_ | ||
* that the provided vertex is a vertex of the query graph against which this | ||
* `QueryGraphState` was created (and its behavior is undefined if it isn't). | ||
@@ -404,4 +404,4 @@ * @param state - the state/value to associate to `vertex`. | ||
* | ||
* @param vertex - the vertex for which state should be removed. This method _assumes_ | ||
* that the provided vertex is a vertex of the query graph against which this | ||
* @param vertex - the vertex for which state should be removed. This method _assumes_ | ||
* that the provided vertex is a vertex of the query graph against which this | ||
* `QueryGraphState` was created (and its behavior is undefined if it isn't). | ||
@@ -416,4 +416,4 @@ */ | ||
* | ||
* @param vertex - the vertex for which state should be retrieved. This method _assumes_ | ||
* that the provided vertex is a vertex of the query graph against which this | ||
* @param vertex - the vertex for which state should be retrieved. This method _assumes_ | ||
* that the provided vertex is a vertex of the query graph against which this | ||
* `QueryGraphState` was created (and its behavior is undefined if it isn't). | ||
@@ -429,4 +429,4 @@ * @return the state associated to `vertex`, if any. | ||
* | ||
* @param edge - the edge to which state should be associated. This method _assumes_ | ||
* that the provided edge is an edge of the query graph against which this | ||
* @param edge - the edge to which state should be associated. This method _assumes_ | ||
* that the provided edge is an edge of the query graph against which this | ||
* `QueryGraphState` was created (and its behavior is undefined if it isn't). | ||
@@ -445,4 +445,4 @@ * @param state - the state/value to associate to `edge`. | ||
* | ||
* @param edge - the edge for which state should be removed. This method _assumes_ | ||
* that the provided edge is an edge of the query graph against which this | ||
* @param edge - the edge for which state should be removed. This method _assumes_ | ||
* that the provided edge is an edge of the query graph against which this | ||
* `QueryGraphState` was created (and its behavior is undefined if it isn't). | ||
@@ -457,4 +457,4 @@ */ | ||
* | ||
* @param edge - the edge for which state should be retrieved. This method _assumes_ | ||
* that the provided vertex is an edge of the query graph against which this | ||
* @param edge - the edge for which state should be retrieved. This method _assumes_ | ||
* that the provided vertex is an edge of the query graph against which this | ||
* `QueryGraphState` was created (and its behavior is undefined if it isn't). | ||
@@ -482,7 +482,7 @@ * @return the state associated to `edge`, if any. | ||
* Note that this method and mainly exported for the sake of testing but should rarely, if | ||
* ever, be used otherwise. Instead use either `buildSupergraphAPIQueryGraph` or | ||
* ever, be used otherwise. Instead use either `buildSupergraphAPIQueryGraph` or | ||
* `buildFederatedQueryGraph` which are more explicit. | ||
* | ||
* @param name - the name to use for the created graph and as "source" name for the schema. | ||
* @param shema - the schema for which to build the query graph. | ||
* @param schema - the schema for which to build the query graph. | ||
* @returns the query graph corresponding to `schema` "API" (in the sense that no federation | ||
@@ -509,3 +509,3 @@ * directives are taken into account by this method in the building of the query graph). | ||
* | ||
* A "supergraph API" query graph is one that is used to reason about queries against said | ||
* A "supergraph API" query graph is one that is used to reason about queries against said | ||
* supergraph API, but @see QueryGraph for more details. | ||
@@ -527,3 +527,3 @@ * | ||
* | ||
* A "federated" query graph is one that is used to reason about queries made by a | ||
* A "federated" query graph is one that is used to reason about queries made by a | ||
* gateway/router against a set of federated subgraph services. | ||
@@ -533,3 +533,3 @@ * | ||
* | ||
* @param supergraph - the schema of the supergraph for which to build the query graph. | ||
* @param supergraph - the schema of the supergraph for which to build the query graph. | ||
* The provided schema _must_ be a "supergraph" as generated by composition merging, | ||
@@ -544,5 +544,5 @@ * one that includes join spec directives in particular. | ||
const subgraphs = extractSubgraphsFromSupergraph(supergraph); | ||
let graphs = []; | ||
for (let subgraph of subgraphs) { | ||
graphs.push(buildGraphInternal(subgraph.name, subgraph.schema, forQueryPlanning, supergraph));; | ||
const graphs = []; | ||
for (const subgraph of subgraphs) { | ||
graphs.push(buildGraphInternal(subgraph.name, subgraph.schema, forQueryPlanning, supergraph)); | ||
} | ||
@@ -556,3 +556,3 @@ return federateSubgraphs(graphs); | ||
const schemas: Schema[] = []; | ||
for (let subgraph of subgraphs) { | ||
for (const subgraph of subgraphs) { | ||
vertices += subgraph.verticesCount(); | ||
@@ -578,3 +578,3 @@ subgraph.rootKinds().forEach(k => rootKinds.add(k)); | ||
const copyPointers: SubgraphCopyPointer[] = new Array(subgraphs.length); | ||
for (let [i, subgraph] of subgraphs.entries()) { | ||
for (const [i, subgraph] of subgraphs.entries()) { | ||
copyPointers[i] = builder.copyGraph(subgraph); | ||
@@ -584,19 +584,18 @@ } | ||
// We then add the edges from supergraph roots to the subgraph ones. | ||
// For the query root, we also add edges from each the query root of each subgraph to the query root of each other. | ||
// This essentially encode the fact that if a field return the "query" type, we can always query any subgraph from | ||
// that point. | ||
for (let [i, subgraph] of subgraphs.entries()) { | ||
// Also, for each root kind, we also add edges from the corresponding root type of each subgraph to the root type of other subgraphs. | ||
// This essentially encode the fact that if a field return a root type, we can always query any subgraph from that point. | ||
for (const [i, subgraph] of subgraphs.entries()) { | ||
const copyPointer = copyPointers[i]; | ||
subgraph.rootKinds().forEach(k => builder.addEdge(builder.root(k)!, copyPointer.copiedVertex(subgraph.root(k)!), subgraphEnteringTransition)); | ||
for (const rootKind of subgraph.rootKinds()) { | ||
const rootVertex = copyPointer.copiedVertex(subgraph.root(rootKind)!); | ||
builder.addEdge(builder.root(rootKind)!, rootVertex, subgraphEnteringTransition) | ||
const queryRoot = subgraph.root("query"); | ||
if (queryRoot) { | ||
for (let [j, otherSubgraph] of subgraphs.entries()) { | ||
for (const [j, otherSubgraph] of subgraphs.entries()) { | ||
if (i === j) { | ||
continue; | ||
} | ||
const otherQueryRoot = otherSubgraph.root("query"); | ||
if (otherQueryRoot) { | ||
const otherRootVertex = otherSubgraph.root(rootKind); | ||
if (otherRootVertex) { | ||
const otherCopyPointer = copyPointers[j]; | ||
builder.addEdge(copyPointer.copiedVertex(queryRoot), otherCopyPointer.copiedVertex(otherQueryRoot), new QueryResolution()); | ||
builder.addEdge(rootVertex, otherCopyPointer.copiedVertex(otherRootVertex), new RootTypeResolution(rootKind)); | ||
} | ||
@@ -609,3 +608,3 @@ } | ||
// copying vertex and their edges, and it's easier to reason about this if we know all keys have already been created. | ||
for (let [i, subgraph] of subgraphs.entries()) { | ||
for (const [i, subgraph] of subgraphs.entries()) { | ||
const subgraphSchema = schemas[i]; | ||
@@ -621,3 +620,3 @@ const keyDirective = federationBuiltIns.keyDirective(subgraphSchema); | ||
// to the current subgraph. In other words, the fact this subgraph has a @key means | ||
// that the service of the current sugraph can be queried for the entity (through | ||
// that the service of the current subgraph can be queried for the entity (through | ||
// _entities) as long as "the other side" can provide the proper field values. | ||
@@ -633,3 +632,3 @@ // Note that we only require that "the other side" can gather the key fields (through | ||
const conditions = parseFieldSetArgument(type, keyApplication); | ||
for (let [j, otherSubgraph] of subgraphs.entries()) { | ||
for (const [j, otherSubgraph] of subgraphs.entries()) { | ||
if (i == j) { | ||
@@ -675,3 +674,3 @@ continue; | ||
// Now we handle @provides | ||
for (let [i, subgraph] of subgraphs.entries()) { | ||
for (const [i, subgraph] of subgraphs.entries()) { | ||
const subgraphSchema = schemas[i]; | ||
@@ -681,3 +680,3 @@ const providesDirective = federationBuiltIns.providesDirective(subgraphSchema); | ||
subgraph, | ||
_ => {}, | ||
_ => undefined, | ||
e => { | ||
@@ -691,3 +690,3 @@ // Handling @provides | ||
const fieldType = baseType(field.type!); | ||
assert(isInterfaceType(fieldType) || isObjectType(fieldType), () => `Invalid @provide on field "${field}" whose type "${fieldType}" is not an object or interface`) | ||
assert(isCompositeType(fieldType), () => `Invalid @provide on field "${field}" whose type "${fieldType}" is not a composite type`) | ||
const provided = parseFieldSetArgument(fieldType, providesApplication); | ||
@@ -723,32 +722,42 @@ const head = copyPointers[i].copiedVertex(e.head); | ||
const fieldDef = element.definition; | ||
if (!fieldDef.hasAppliedDirective(externalDirectiveName)) { | ||
// Because key fields used to be marked @external, someone my have put a provide for a key field | ||
// which is effectively already provided by the subgraph. In that case, just ignore that field | ||
// (otherwise, future code will get confused by the fact that there is more than 1 edge to | ||
// resolve a field locally and would have to make a choice while lacking context). | ||
continue; | ||
} | ||
const fieldType = baseType(fieldDef.type!); | ||
if (selection.selectionSet) { | ||
// We should create a brand new vertex, not reuse the existing one because we're still in | ||
// the middle of the provide and only a subset of `fieldType` (and in fact, even if all | ||
// of the fields `fieldType` are provided, maybe only a subset of _those_ field is | ||
// provided.. | ||
const newVertex = builder.createNewVertex(fieldType, source, schema); | ||
builder.addEdge(v, newVertex, new FieldCollection(fieldDef)); | ||
stack.push([newVertex, selection.selectionSet]); | ||
const existingEdge = builder.edges(v).find(e => e.transition.kind === 'FieldCollection' && e.transition.definition.name === fieldDef.name); | ||
if (existingEdge) { | ||
// If this is a leaf field, then we don't really have anything to do. Otherwise, we need to copy | ||
// the tail and continue propagating the provides from there. | ||
if (selection.selectionSet) { | ||
const copiedTail = builder.makeCopy(existingEdge.tail); | ||
builder.updateEdgeTail(existingEdge, copiedTail); | ||
stack.push([copiedTail, selection.selectionSet]); | ||
} | ||
} else { | ||
// this is a leaf type, we can just reuse the (probably) existing vertex for that leaf type. | ||
const existing = builder.verticesForType(fieldType.name).find(v => v.source === source); | ||
const vertex = existing ? existing : builder.createNewVertex(fieldType, v.source, schema); | ||
builder.addEdge(v, vertex, new FieldCollection(fieldDef)); | ||
// There is no exisiting edges, which means that it's an edge added by the provide. | ||
// We find the existing vertex it leads to, if it exists and create a new one otherwise. | ||
const fieldType = baseType(fieldDef.type!); | ||
const existingTail = builder.verticesForType(fieldType.name).find(v => v.source === source); | ||
const newTail = existingTail ? existingTail : builder.createNewVertex(fieldType, v.source, schema); | ||
// If the field is a leaf, then just create the new edge and we're done. Othewise, we | ||
// should copy the vertex (unless we just created it), add the edge and continue. | ||
if (selection.selectionSet) { | ||
const copiedTail = existingTail ? builder.makeCopy(existingTail) : newTail; | ||
builder.addEdge(v, copiedTail, new FieldCollection(fieldDef, true)); | ||
stack.push([copiedTail, selection.selectionSet]); | ||
} else { | ||
builder.addEdge(v, newTail, new FieldCollection(fieldDef, true)); | ||
} | ||
} | ||
} else { | ||
const typeCondition = element.typeCondition; | ||
let newVertex = v; | ||
if (typeCondition) { | ||
newVertex = builder.createNewVertex(typeCondition, source, schema); | ||
builder.addEdge(v, newVertex, new DownCast(element.parentType, typeCondition)); | ||
const existingEdge = builder.edges(v).find(e => e.transition.kind === 'DownCast' && e.transition.castedType.name === typeCondition.name); | ||
// We always should have an edge: otherwise it would mean we list a type condition for a type that isn't in the subgraph, but the | ||
// @provides shouldn't have validated in the first place (another way to put it is, contrary to fields, there is no way currently | ||
// to mark a full type as @external). | ||
assert(existingEdge, () => `Shouldn't have ${selection} with no corresponding edge on ${v}`); | ||
const copiedTail = builder.makeCopy(existingEdge.tail); | ||
builder.updateEdgeTail(existingEdge, copiedTail); | ||
stack.push([copiedTail, selection.selectionSet!]); | ||
} else { | ||
// Essentially ignore the condition, it's useless | ||
stack.push([v, selection.selectionSet!]); | ||
} | ||
stack.push([newVertex, selection.selectionSet!]); | ||
} | ||
@@ -861,2 +870,6 @@ } | ||
edges(head: Vertex): Edge[] { | ||
return this.adjacencies[head.index]; | ||
} | ||
/** | ||
@@ -877,3 +890,3 @@ * Creates a new vertex that is a full copy of the provided one, including having the same out-edge, but with no incoming edges. | ||
/** | ||
* Replaces the provided edge by an exact copy except for the tail that is said to the provide `newTail` vertex. | ||
* Replaces the provided edge by an exact copy except for the tail that is said to the provide `newTail` vertex. | ||
* | ||
@@ -925,3 +938,3 @@ * @param edge - the edge to replace. | ||
super(); | ||
this.isFederatedSubgraph = isFederationSubgraphSchema(schema); | ||
this.isFederatedSubgraph = isFederationSubgraphSchema(schema); | ||
assert(!this.isFederatedSubgraph || supergraphSchema, `Missing supergraph schema for building the federated subgraph graph`); | ||
@@ -946,3 +959,3 @@ // The join spec 0.1 used by "fed1" does not preserve the information on where (in which subgraphs) | ||
/** | ||
* Adds in a vertex for the provided type in the in-building query graph, and recursively | ||
* Adds in a vertex for the provided type in the in-building query graph, and recursively | ||
* adds edges and vertices corresponding to the type definition (so for object types, it | ||
@@ -964,5 +977,5 @@ * will add edges for each fields and recursively add vertices for each field type, etc...). | ||
// field can be fetched from may depend on the runtime implementation. However, if the subgraph we're currently including | ||
// "provides" a particular interface field locally *for all the supergraph interfaces implementations* (in other words, we | ||
// know we can always ask the field to that subgraph directly on the interface and will never miss anything), then we can | ||
// add a direct edge to the field for the interface in that subgraph (which avoids unecessary type explosing in practice). | ||
// "provides" a particular interface field locally *for all the supergraph interfaces implementations* (in other words, we | ||
// know we can always ask the field to that subgraph directly on the interface and will never miss anything), then we can | ||
// add a direct edge to the field for the interface in that subgraph (which avoids unnecessary type exploding in practice). | ||
if (this.isFederatedSubgraph && !this.forceTypeExplosion) { | ||
@@ -1110,3 +1123,3 @@ this.maybeAddInterfaceFieldsEdges(namedType, vertex); | ||
* Do not that in practice we only add those edges when we build a query graph for query planning | ||
* purposes, because not type-exploding is only an optimization but type-expoding will always "work" | ||
* purposes, because not type-exploding is only an optimization but type-exploding will always "work" | ||
* and for composition validation, we don't care about being optimal, while limiting edges make | ||
@@ -1180,3 +1193,3 @@ * validation faster by limiting the choices to explore. Also, query planning is careful, as | ||
* `onVertex` may or may not have been called for it). | ||
*/ | ||
*/ | ||
export function simpleTraversal( | ||
@@ -1183,0 +1196,0 @@ graph: QueryGraph, |
@@ -41,3 +41,3 @@ import { | ||
// The enum string values, with any values marked by @inacessible filtered out. | ||
// The enum string values, with any values marked by @inaccessible filtered out. | ||
// TODO: should we move this and related to a different place? It's more of a composition specific | ||
@@ -79,6 +79,6 @@ // type of subtyping. | ||
if (isNonNullType(inputType)) { | ||
// A nullable type cannot be a sutype of a non-nullable on. | ||
// A nullable type cannot be a subtype of a non-nullable on. | ||
return isNonNullType(maybeSubType) ? isStructuralInputSubType(inputType.ofType, maybeSubType.ofType) : false; | ||
} | ||
/// A non-nullable type is a subtype of a nullable one if it is a stubtype of that other type. | ||
// A non-nullable type is a subtype of a nullable one if it is a subtype of that other type. | ||
if (isNonNullType(maybeSubType)) { | ||
@@ -85,0 +85,0 @@ return isStructuralInputSubType(inputType, maybeSubType.ofType); |
@@ -1,2 +0,2 @@ | ||
import { FieldDefinition, CompositeType } from "@apollo/federation-internals"; | ||
import { FieldDefinition, CompositeType, SchemaRootKind } from "@apollo/federation-internals"; | ||
@@ -8,4 +8,4 @@ /** | ||
* schema. Edges may correspond to: | ||
* - a field (`FieldCollection`): the edge goes from (a vertex for) the field parent type, to the | ||
* field (base) type. | ||
* - a field (`FieldCollection`): the edge goes from (a vertex for) the field parent type, to the | ||
* field (base) type. | ||
* - a "downcast" (`DownCast`): the edges goes from an abstract type (interface or union) to a type | ||
@@ -27,3 +27,3 @@ * that implements that abstract type (for interfaces) or is a member of that abstract type (for | ||
*/ | ||
export type Transition = FieldCollection | DownCast | KeyResolution | QueryResolution | SubgraphEnteringTransition; | ||
export type Transition = FieldCollection | DownCast | KeyResolution | RootTypeResolution | SubgraphEnteringTransition; | ||
@@ -34,5 +34,2 @@ export class KeyResolution { | ||
constructor() { | ||
} | ||
toString() { | ||
@@ -43,11 +40,11 @@ return 'key()'; | ||
export class QueryResolution { | ||
readonly kind = 'QueryResolution' as const; | ||
export class RootTypeResolution { | ||
readonly kind = 'RootTypeResolution' as const; | ||
readonly collectOperationElements = false as const; | ||
constructor() { | ||
constructor(readonly rootKind: SchemaRootKind) { | ||
} | ||
toString() { | ||
return 'query()'; | ||
return this.rootKind + '()'; | ||
} | ||
@@ -60,3 +57,6 @@ } | ||
constructor(readonly definition: FieldDefinition<CompositeType>) {} | ||
constructor( | ||
readonly definition: FieldDefinition<CompositeType>, | ||
readonly isPartOfProvide: boolean = false | ||
) {} | ||
@@ -63,0 +63,0 @@ toString() { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
485772
0
56
6322
+ Addedts-graphviz@0.16.0(transitive)
- Removedts-graphviz@0.15.1(transitive)
- Removedtslib@2.8.1(transitive)
Updatedts-graphviz@^0.16.0