@theguild/federation-composition 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/cjs/specifications/link.js +40 -5
- package/cjs/subgraph/helpers.js +2 -2
- package/cjs/subgraph/state.js +8 -0
- package/cjs/subgraph/validation/rules/elements/provides.js +8 -6
- package/cjs/subgraph/validation/rules/elements/requires.js +9 -7
- package/cjs/subgraph/validation/validate-state.js +9 -3
- package/cjs/subgraph/validation/validate-subgraph.js +4 -2
- package/cjs/subgraph/validation/validation-context.js +10 -0
- package/cjs/supergraph/composition/directive.js +3 -0
- package/cjs/supergraph/composition/enum-type.js +3 -0
- package/cjs/supergraph/composition/input-object-type.js +3 -0
- package/cjs/supergraph/composition/interface-type.js +4 -0
- package/cjs/supergraph/composition/object-type.js +18 -20
- package/cjs/supergraph/composition/scalar-type.js +2 -0
- package/cjs/supergraph/composition/union-type.js +2 -0
- package/cjs/supergraph/state.js +24 -26
- package/cjs/supergraph/validation/rules/fields-of-the-same-type-rule.js +35 -0
- package/cjs/supergraph/validation/rules/invalid-field-sharing-rule.js +4 -1
- package/cjs/supergraph/validation/rules/satisfiablity/constants.js +4 -0
- package/cjs/supergraph/validation/rules/satisfiablity/edge.js +64 -0
- package/cjs/supergraph/validation/rules/satisfiablity/errors.js +44 -0
- package/cjs/supergraph/validation/rules/satisfiablity/fields.js +147 -0
- package/cjs/supergraph/validation/rules/satisfiablity/finder.js +267 -0
- package/cjs/supergraph/validation/rules/satisfiablity/graph.js +675 -0
- package/cjs/supergraph/validation/rules/satisfiablity/helpers.js +41 -0
- package/cjs/supergraph/validation/rules/satisfiablity/move-validator.js +337 -0
- package/cjs/supergraph/validation/rules/satisfiablity/moves.js +52 -0
- package/cjs/supergraph/validation/rules/satisfiablity/node.js +89 -0
- package/cjs/supergraph/validation/rules/satisfiablity/operation-path.js +70 -0
- package/cjs/supergraph/validation/rules/satisfiablity/supergraph.js +37 -0
- package/cjs/supergraph/validation/rules/satisfiablity/walker.js +306 -0
- package/cjs/supergraph/validation/rules/satisfiablity-rule.js +45 -1081
- package/cjs/supergraph/validation/validate-supergraph.js +1 -1
- package/cjs/utils/logger.js +127 -0
- package/esm/specifications/link.js +40 -5
- package/esm/subgraph/helpers.js +2 -2
- package/esm/subgraph/state.js +8 -0
- package/esm/subgraph/validation/rules/elements/provides.js +8 -6
- package/esm/subgraph/validation/rules/elements/requires.js +9 -7
- package/esm/subgraph/validation/validate-state.js +9 -3
- package/esm/subgraph/validation/validate-subgraph.js +4 -2
- package/esm/subgraph/validation/validation-context.js +11 -1
- package/esm/supergraph/composition/directive.js +3 -0
- package/esm/supergraph/composition/enum-type.js +3 -0
- package/esm/supergraph/composition/input-object-type.js +3 -0
- package/esm/supergraph/composition/interface-type.js +4 -0
- package/esm/supergraph/composition/object-type.js +18 -20
- package/esm/supergraph/composition/scalar-type.js +2 -0
- package/esm/supergraph/composition/union-type.js +2 -0
- package/esm/supergraph/state.js +24 -26
- package/esm/supergraph/validation/rules/fields-of-the-same-type-rule.js +35 -0
- package/esm/supergraph/validation/rules/invalid-field-sharing-rule.js +4 -1
- package/esm/supergraph/validation/rules/satisfiablity/constants.js +1 -0
- package/esm/supergraph/validation/rules/satisfiablity/edge.js +54 -0
- package/esm/supergraph/validation/rules/satisfiablity/errors.js +40 -0
- package/esm/supergraph/validation/rules/satisfiablity/fields.js +142 -0
- package/esm/supergraph/validation/rules/satisfiablity/finder.js +261 -0
- package/esm/supergraph/validation/rules/satisfiablity/graph.js +671 -0
- package/esm/supergraph/validation/rules/satisfiablity/helpers.js +35 -0
- package/esm/supergraph/validation/rules/satisfiablity/move-validator.js +333 -0
- package/esm/supergraph/validation/rules/satisfiablity/moves.js +46 -0
- package/esm/supergraph/validation/rules/satisfiablity/node.js +85 -0
- package/esm/supergraph/validation/rules/satisfiablity/operation-path.js +66 -0
- package/esm/supergraph/validation/rules/satisfiablity/supergraph.js +33 -0
- package/esm/supergraph/validation/rules/satisfiablity/walker.js +301 -0
- package/esm/supergraph/validation/rules/satisfiablity-rule.js +40 -1076
- package/esm/supergraph/validation/validate-supergraph.js +1 -1
- package/esm/utils/logger.js +119 -0
- package/package.json +2 -1
- package/typings/subgraph/state.d.cts +2 -0
- package/typings/subgraph/state.d.ts +2 -0
- package/typings/subgraph/validation/validate-state.d.cts +2 -1
- package/typings/subgraph/validation/validate-state.d.ts +2 -1
- package/typings/subgraph/validation/validation-context.d.cts +3 -0
- package/typings/subgraph/validation/validation-context.d.ts +3 -0
- package/typings/supergraph/composition/common.d.cts +2 -1
- package/typings/supergraph/composition/common.d.ts +2 -1
- package/typings/supergraph/composition/directive.d.cts +4 -0
- package/typings/supergraph/composition/directive.d.ts +4 -0
- package/typings/supergraph/composition/enum-type.d.cts +4 -0
- package/typings/supergraph/composition/enum-type.d.ts +4 -0
- package/typings/supergraph/composition/input-object-type.d.cts +4 -0
- package/typings/supergraph/composition/input-object-type.d.ts +4 -0
- package/typings/supergraph/composition/interface-type.d.cts +5 -0
- package/typings/supergraph/composition/interface-type.d.ts +5 -0
- package/typings/supergraph/composition/object-type.d.cts +5 -0
- package/typings/supergraph/composition/object-type.d.ts +5 -0
- package/typings/supergraph/composition/scalar-type.d.cts +3 -0
- package/typings/supergraph/composition/scalar-type.d.ts +3 -0
- package/typings/supergraph/composition/union-type.d.cts +3 -0
- package/typings/supergraph/composition/union-type.d.ts +3 -0
- package/typings/supergraph/state.d.cts +4 -4
- package/typings/supergraph/state.d.ts +4 -4
- package/typings/supergraph/validation/rules/satisfiablity/constants.d.cts +2 -0
- package/typings/supergraph/validation/rules/satisfiablity/constants.d.ts +2 -0
- package/typings/supergraph/validation/rules/satisfiablity/edge.d.cts +31 -0
- package/typings/supergraph/validation/rules/satisfiablity/edge.d.ts +31 -0
- package/typings/supergraph/validation/rules/satisfiablity/errors.d.cts +17 -0
- package/typings/supergraph/validation/rules/satisfiablity/errors.d.ts +17 -0
- package/typings/supergraph/validation/rules/satisfiablity/fields.d.cts +33 -0
- package/typings/supergraph/validation/rules/satisfiablity/fields.d.ts +33 -0
- package/typings/supergraph/validation/rules/satisfiablity/finder.d.cts +28 -0
- package/typings/supergraph/validation/rules/satisfiablity/finder.d.ts +28 -0
- package/typings/supergraph/validation/rules/satisfiablity/graph.d.cts +63 -0
- package/typings/supergraph/validation/rules/satisfiablity/graph.d.ts +63 -0
- package/typings/supergraph/validation/rules/satisfiablity/helpers.d.cts +7 -0
- package/typings/supergraph/validation/rules/satisfiablity/helpers.d.ts +7 -0
- package/typings/supergraph/validation/rules/satisfiablity/move-validator.d.cts +25 -0
- package/typings/supergraph/validation/rules/satisfiablity/move-validator.d.ts +25 -0
- package/typings/supergraph/validation/rules/satisfiablity/moves.d.cts +24 -0
- package/typings/supergraph/validation/rules/satisfiablity/moves.d.ts +24 -0
- package/typings/supergraph/validation/rules/satisfiablity/node.d.cts +31 -0
- package/typings/supergraph/validation/rules/satisfiablity/node.d.ts +31 -0
- package/typings/supergraph/validation/rules/satisfiablity/operation-path.d.cts +29 -0
- package/typings/supergraph/validation/rules/satisfiablity/operation-path.d.ts +29 -0
- package/typings/supergraph/validation/rules/satisfiablity/supergraph.d.cts +14 -0
- package/typings/supergraph/validation/rules/satisfiablity/supergraph.d.ts +14 -0
- package/typings/supergraph/validation/rules/satisfiablity/walker.d.cts +35 -0
- package/typings/supergraph/validation/rules/satisfiablity/walker.d.ts +35 -0
- package/typings/utils/logger.d.cts +33 -0
- package/typings/utils/logger.d.ts +33 -0
- package/cjs/utils/dependency-graph.js +0 -227
- package/esm/utils/dependency-graph.js +0 -222
- package/typings/utils/dependency-graph.d.cts +0 -31
- package/typings/utils/dependency-graph.d.ts +0 -31
|
@@ -2,780 +2,63 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SatisfiabilityRule = void 0;
|
|
4
4
|
const graphql_1 = require("graphql");
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const helpers_js_2 = require("../../../utils/helpers.js");
|
|
9
|
-
const state_js_2 = require("../../../utils/state.js");
|
|
10
|
-
function isSatisfiableQueryPath(supergraphState, queryPath) {
|
|
11
|
-
const root = queryPath[0];
|
|
12
|
-
const leaf = queryPath[queryPath.length - 1];
|
|
13
|
-
if ('fieldName' in root) {
|
|
14
|
-
const rootType = supergraphState.objectTypes.get(root.typeName);
|
|
15
|
-
if (!rootType) {
|
|
16
|
-
throw new Error(`Type "${root.typeName}" not found in Supergraph state`);
|
|
17
|
-
}
|
|
18
|
-
const rootField = rootType.fields.get(root.fieldName);
|
|
19
|
-
if (!rootField) {
|
|
20
|
-
throw new Error(`Field "${root.typeName}.${root.fieldName}" not found in Supergraph state`);
|
|
21
|
-
}
|
|
22
|
-
const graphsWithRootField = Array.from(rootField.byGraph)
|
|
23
|
-
.filter(([_, f]) => f.external === false)
|
|
24
|
-
.map(([g, _]) => g);
|
|
25
|
-
if (!('fieldName' in leaf)) {
|
|
26
|
-
throw new Error('Leaf field is missing in the query path');
|
|
27
|
-
}
|
|
28
|
-
const leafType = supergraphState.objectTypes.get(leaf.typeName);
|
|
29
|
-
if (!leafType) {
|
|
30
|
-
throw new Error(`Type "${leaf.typeName}" not found in Supergraph state`);
|
|
31
|
-
}
|
|
32
|
-
const leafField = leafType.fields.get(leaf.fieldName);
|
|
33
|
-
if (!leafField) {
|
|
34
|
-
throw new Error(`Field "${leaf.typeName}.${leaf.fieldName}" not found in Supergraph state`);
|
|
35
|
-
}
|
|
36
|
-
if (graphsWithRootField.some(graphWithRootField => canTraverseToField(leafField.name, supergraphState, leafType, graphWithRootField))) {
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
function canAdvance(stepIndex, fromGraphId) {
|
|
40
|
-
const step = queryPath[stepIndex];
|
|
41
|
-
if (!('fieldName' in step)) {
|
|
42
|
-
return canAdvance(stepIndex + 1, fromGraphId);
|
|
43
|
-
}
|
|
44
|
-
const typeState = supergraphState.objectTypes.get(step.typeName);
|
|
45
|
-
if (!typeState) {
|
|
46
|
-
throw new Error(`Type "${step.typeName}" not found in Supergraph state`);
|
|
47
|
-
}
|
|
48
|
-
const fieldState = typeState.fields.get(step.fieldName);
|
|
49
|
-
if (!fieldState) {
|
|
50
|
-
throw new Error(`Field "${step.typeName}.${step.fieldName}" not found in Supergraph state`);
|
|
51
|
-
}
|
|
52
|
-
const accessibleTargetGraphs = new Set();
|
|
53
|
-
if (!canTraverseToField(fieldState.name, supergraphState, typeState, fromGraphId, accessibleTargetGraphs)) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
if (step === leaf) {
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
return Array.from(accessibleTargetGraphs).some(graphId => canAdvance(stepIndex + 1, graphId));
|
|
60
|
-
}
|
|
61
|
-
const canResolveStepByStep = graphsWithRootField.some(graphId => {
|
|
62
|
-
return canAdvance(0, graphId);
|
|
63
|
-
});
|
|
64
|
-
if (canResolveStepByStep) {
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
throw new Error('Root field is missing in the query path');
|
|
70
|
-
}
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
function canTraverseToField(fieldName, supergraphState, entityState, sourceGraphId, accessibleTargetGraphs = new Set(), visitedGraphs = new Set(), collectedFieldPaths = new Set()) {
|
|
74
|
-
const objectTypeStateInSourceGraph = entityState.byGraph.get(sourceGraphId);
|
|
75
|
-
const sourceGraphKeys = objectTypeStateInSourceGraph?.keys || [];
|
|
76
|
-
const fieldState = entityState.fields.get(fieldName);
|
|
77
|
-
if (!fieldState) {
|
|
78
|
-
throw new Error(`Field "${entityState.name}.${fieldName}" not found in Supergraph state`);
|
|
79
|
-
}
|
|
80
|
-
const fieldStateInSourceGraph = fieldState.byGraph.get(sourceGraphId);
|
|
81
|
-
if (fieldStateInSourceGraph && fieldStateInSourceGraph.external === false) {
|
|
82
|
-
accessibleTargetGraphs.add(sourceGraphId);
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
for (const targetGraphId of entityState.byGraph.keys()) {
|
|
86
|
-
if (targetGraphId === sourceGraphId) {
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
if (visitedGraphs.has(targetGraphId)) {
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
const fieldState = entityState.fields.get(fieldName);
|
|
93
|
-
if (!fieldState) {
|
|
94
|
-
throw new Error(`Field "${entityState.name}.${fieldName}" not found in Supergraph state`);
|
|
95
|
-
}
|
|
96
|
-
const objectTypeStateInTargetGraph = entityState.byGraph.get(targetGraphId);
|
|
97
|
-
const targetGraphKeys = objectTypeStateInTargetGraph?.keys || [];
|
|
98
|
-
if (sourceGraphKeys.length === 0 && targetGraphKeys.length === 0) {
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
for (const targetKey of targetGraphKeys) {
|
|
102
|
-
if (!targetKey.resolvable) {
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
const targetKeyFields = resolveFieldsFromFieldSet(targetKey.fields, entityState.name, targetGraphId, supergraphState);
|
|
106
|
-
let resolvableFieldPaths = new Set();
|
|
107
|
-
for (const [requiredFieldPath, { typeName, fieldName }] of targetKeyFields.pairs) {
|
|
108
|
-
if (collectedFieldPaths.has(requiredFieldPath)) {
|
|
109
|
-
resolvableFieldPaths.add(requiredFieldPath);
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
const objectType = supergraphState.objectTypes.get(typeName);
|
|
113
|
-
if (!objectType) {
|
|
114
|
-
throw new Error(`Type "${typeName}" not found in Supergraph state`);
|
|
115
|
-
}
|
|
116
|
-
const field = objectType.fields.get(fieldName);
|
|
117
|
-
if (!field) {
|
|
118
|
-
throw new Error(`Field "${typeName}.${fieldName}" not found in Supergraph state`);
|
|
119
|
-
}
|
|
120
|
-
const fieldInGraph = field.byGraph.get(sourceGraphId);
|
|
121
|
-
if (!fieldInGraph) {
|
|
122
|
-
break;
|
|
123
|
-
}
|
|
124
|
-
const fieldInGraphIsExternal = fieldInGraph.external === true;
|
|
125
|
-
const fieldIsDirectlyAccessed = requiredFieldPath.indexOf('.') === requiredFieldPath.lastIndexOf('.');
|
|
126
|
-
if (fieldInGraphIsExternal && fieldIsDirectlyAccessed) {
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
resolvableFieldPaths.add(requiredFieldPath);
|
|
130
|
-
}
|
|
131
|
-
if (resolvableFieldPaths.size !== targetKeyFields.paths.size) {
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
if (fieldState.byGraph.has(targetGraphId)) {
|
|
135
|
-
accessibleTargetGraphs.add(targetGraphId);
|
|
136
|
-
return true;
|
|
137
|
-
}
|
|
138
|
-
const canResolve = canTraverseToField(fieldName, supergraphState, entityState, targetGraphId, accessibleTargetGraphs, new Set([...visitedGraphs, targetGraphId]), new Set([...collectedFieldPaths, ...resolvableFieldPaths]));
|
|
139
|
-
if (canResolve) {
|
|
140
|
-
accessibleTargetGraphs.add(targetGraphId);
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
function canGraphMoveToGraphByEntity(supergraphState, entityName, sourceGraphId, targetGraphId) {
|
|
148
|
-
const objectTypeState = supergraphState.objectTypes.get(entityName);
|
|
149
|
-
if (!objectTypeState) {
|
|
150
|
-
throw new Error(`Type "${entityName}" not found in supergraph state`);
|
|
151
|
-
}
|
|
152
|
-
const objectTypeStateInSourceGraph = objectTypeState.byGraph.get(sourceGraphId);
|
|
153
|
-
const objectTypeStateInTargetGraph = objectTypeState.byGraph.get(targetGraphId);
|
|
154
|
-
const sourceGraphKeys = objectTypeStateInSourceGraph?.keys || [];
|
|
155
|
-
const targetGraphKeys = objectTypeStateInTargetGraph?.keys || [];
|
|
156
|
-
if (sourceGraphKeys.length === 0 && targetGraphKeys.length === 0) {
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
if (sourceGraphKeys.length === 0) {
|
|
160
|
-
return targetGraphKeys
|
|
161
|
-
.filter(k => k.resolvable === true)
|
|
162
|
-
.some(k => {
|
|
163
|
-
const targetKeyFields = resolveFieldsFromFieldSet(k.fields, objectTypeState.name, targetGraphId, supergraphState);
|
|
164
|
-
return Array.from(targetKeyFields.coordinates).every(fieldPath => {
|
|
165
|
-
const [typeName, fieldName] = fieldPath.split('.');
|
|
166
|
-
if (typeName === objectTypeState.name) {
|
|
167
|
-
const fieldState = objectTypeState.fields.get(fieldName);
|
|
168
|
-
if (!fieldState) {
|
|
169
|
-
throw new Error(`Field "${fieldPath}" not found in object type "${typeName}"`);
|
|
170
|
-
}
|
|
171
|
-
const fieldStateByGraph = fieldState.byGraph.get(targetGraphId);
|
|
172
|
-
if (!fieldStateByGraph) {
|
|
173
|
-
throw new Error(`Field "${fieldPath}" not found in object type "${typeName}" in graph "${targetGraphId}"`);
|
|
174
|
-
}
|
|
175
|
-
return fieldStateByGraph.external === false;
|
|
176
|
-
}
|
|
177
|
-
const currentTypeState = supergraphState.objectTypes.get(typeName) ??
|
|
178
|
-
supergraphState.interfaceTypes.get(typeName);
|
|
179
|
-
if (!currentTypeState) {
|
|
180
|
-
throw new Error(`Type "${typeName}" not found`);
|
|
181
|
-
}
|
|
182
|
-
const fieldState = currentTypeState.fields.get(fieldName);
|
|
183
|
-
if (!fieldState) {
|
|
184
|
-
throw new Error(`Field "${fieldPath}" not found in object type "${typeName}"`);
|
|
185
|
-
}
|
|
186
|
-
const fieldStateByGraph = fieldState.byGraph.get(targetGraphId);
|
|
187
|
-
if (!fieldStateByGraph) {
|
|
188
|
-
throw new Error(`Field "${fieldPath}" not found in object type "${typeName}" in graph "${targetGraphId}"`);
|
|
189
|
-
}
|
|
190
|
-
if ('external' in fieldStateByGraph) {
|
|
191
|
-
return fieldStateByGraph.external === false;
|
|
192
|
-
}
|
|
193
|
-
return true;
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
return sourceGraphKeys.some(sourceGraphKey => {
|
|
198
|
-
const sourceKeyFields = resolveFieldsFromFieldSet(sourceGraphKey.fields, objectTypeState.name, sourceGraphId, supergraphState);
|
|
199
|
-
const hasNonKeyFields = Array.from(objectTypeState.fields).some(([_, fState]) => {
|
|
200
|
-
const f = fState.byGraph.get(sourceGraphId);
|
|
201
|
-
if (f && f.usedAsKey === false) {
|
|
202
|
-
return true;
|
|
203
|
-
}
|
|
204
|
-
return false;
|
|
205
|
-
});
|
|
206
|
-
if (Array.from(sourceKeyFields.coordinates).every(fieldPath => {
|
|
207
|
-
const [typeName, fieldName] = fieldPath.split('.');
|
|
208
|
-
const objectTypeState = supergraphState.objectTypes.get(typeName);
|
|
209
|
-
if (!objectTypeState) {
|
|
210
|
-
throw new Error(`Type "${typeName}" not found`);
|
|
211
|
-
}
|
|
212
|
-
const fieldState = objectTypeState.fields.get(fieldName);
|
|
213
|
-
if (!fieldState) {
|
|
214
|
-
throw new Error(`Field "${fieldPath}" not found in object type "${typeName}"`);
|
|
215
|
-
}
|
|
216
|
-
const fieldStateByGraph = fieldState.byGraph.get(sourceGraphId);
|
|
217
|
-
if (!fieldStateByGraph) {
|
|
218
|
-
throw new Error(`Field "${fieldPath}" not found in object type "${typeName}" in graph "${sourceGraphId}"`);
|
|
219
|
-
}
|
|
220
|
-
return (!hasNonKeyFields &&
|
|
221
|
-
objectTypeState.byGraph.get(sourceGraphId).extension !== true &&
|
|
222
|
-
fieldStateByGraph.external === true &&
|
|
223
|
-
fieldStateByGraph.usedAsKey);
|
|
224
|
-
})) {
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
return (targetGraphKeys
|
|
228
|
-
.filter(k => k.resolvable === true)
|
|
229
|
-
.some(k => {
|
|
230
|
-
const targetKeyFields = resolveFieldsFromFieldSet(k.fields, objectTypeState.name, targetGraphId, supergraphState);
|
|
231
|
-
for (const fieldPath of targetKeyFields.paths) {
|
|
232
|
-
if (!sourceKeyFields.paths.has(fieldPath)) {
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return true;
|
|
237
|
-
}));
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
function canGraphResolveFieldDirectly(objectTypeSuperState, fieldSuperState, graphId, supergraphState) {
|
|
241
|
-
const objectTypeInGraph = objectTypeSuperState.byGraph.get(graphId);
|
|
242
|
-
if (!objectTypeInGraph) {
|
|
243
|
-
throw new Error(`Object type "${objectTypeSuperState.name}" not found in graph "${graphId}"`);
|
|
244
|
-
}
|
|
245
|
-
const fieldInGraph = fieldSuperState.byGraph.get(graphId);
|
|
246
|
-
if (!fieldInGraph) {
|
|
247
|
-
return false;
|
|
248
|
-
}
|
|
249
|
-
if ((fieldInGraph.shareable === true ||
|
|
250
|
-
objectTypeSuperState.byGraph.get(graphId).shareable === true) &&
|
|
251
|
-
supergraphState.graphs.get(graphId).version !== 'v1.0') {
|
|
252
|
-
return true;
|
|
253
|
-
}
|
|
254
|
-
if (fieldInGraph.external === true) {
|
|
255
|
-
if (fieldInGraph.usedAsKey === true) {
|
|
256
|
-
const graphHasAtLeastOneResolvableField = Array.from(objectTypeSuperState.fields.values()).some(f => {
|
|
257
|
-
if (f.name === fieldSuperState.name) {
|
|
258
|
-
return false;
|
|
259
|
-
}
|
|
260
|
-
const fInGraph = f.byGraph.get(graphId);
|
|
261
|
-
if (!fInGraph) {
|
|
262
|
-
return false;
|
|
263
|
-
}
|
|
264
|
-
if (fInGraph.external === true) {
|
|
265
|
-
return false;
|
|
266
|
-
}
|
|
267
|
-
if (fInGraph.inaccessible === true) {
|
|
268
|
-
return false;
|
|
269
|
-
}
|
|
270
|
-
if (typeof fInGraph.override === 'string') {
|
|
271
|
-
return false;
|
|
272
|
-
}
|
|
273
|
-
return true;
|
|
274
|
-
});
|
|
275
|
-
if (graphHasAtLeastOneResolvableField) {
|
|
276
|
-
return true;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
return false;
|
|
280
|
-
}
|
|
281
|
-
return true;
|
|
282
|
-
}
|
|
283
|
-
function canGraphResolveField(objectTypeSuperState, fieldSuperState, graphId, supergraphState, movabilityGraph) {
|
|
284
|
-
const objectTypeInGraph = objectTypeSuperState.byGraph.get(graphId);
|
|
285
|
-
if (!objectTypeInGraph) {
|
|
286
|
-
throw new Error(`Object type "${objectTypeSuperState.name}" not found in graph "${graphId}"`);
|
|
287
|
-
}
|
|
288
|
-
const fieldInGraph = fieldSuperState.byGraph.get(graphId);
|
|
289
|
-
if (fieldInGraph &&
|
|
290
|
-
fieldInGraph.external === false &&
|
|
291
|
-
canGraphResolveFieldDirectly(objectTypeSuperState, fieldSuperState, graphId, supergraphState)) {
|
|
292
|
-
return true;
|
|
293
|
-
}
|
|
294
|
-
const graphsWithField = Array.from(fieldSuperState.byGraph).filter(([g, _]) => {
|
|
295
|
-
if (g === graphId) {
|
|
296
|
-
return false;
|
|
297
|
-
}
|
|
298
|
-
const fieldInGraph = fieldSuperState.byGraph.get(g);
|
|
299
|
-
if (!fieldInGraph || fieldInGraph.external === true) {
|
|
300
|
-
return false;
|
|
301
|
-
}
|
|
302
|
-
return true;
|
|
303
|
-
});
|
|
304
|
-
const canMoveToGraphWithField = graphsWithField.some(([g, _]) => {
|
|
305
|
-
return canGraphMoveToGraphBasedOnMovabilityGraph(movabilityGraph, graphId, g);
|
|
306
|
-
});
|
|
307
|
-
return canMoveToGraphWithField;
|
|
308
|
-
}
|
|
309
|
-
function canGraphMoveToGraphBasedOnMovabilityGraph(movabilityGraph, sourceId, destinationId, visited = new Set()) {
|
|
310
|
-
const key = `${sourceId} => ${destinationId}`;
|
|
311
|
-
if (visited.has(key)) {
|
|
312
|
-
return false;
|
|
313
|
-
}
|
|
314
|
-
else {
|
|
315
|
-
visited.add(key);
|
|
316
|
-
}
|
|
317
|
-
const deps = movabilityGraph.directDependenciesOf(sourceId);
|
|
318
|
-
if (deps.includes(destinationId)) {
|
|
319
|
-
return true;
|
|
320
|
-
}
|
|
321
|
-
return deps.some(depId => canGraphMoveToGraphBasedOnMovabilityGraph(movabilityGraph, depId, destinationId, visited));
|
|
322
|
-
}
|
|
323
|
-
function findLeafs(movabilityGraph, sourceId, destinationId, leafs, visited = new Set()) {
|
|
324
|
-
const key = `${sourceId} => ${destinationId}`;
|
|
325
|
-
if (leafs === undefined) {
|
|
326
|
-
leafs = new Set();
|
|
327
|
-
}
|
|
328
|
-
const deps = movabilityGraph.directDependenciesOf(sourceId);
|
|
329
|
-
if (visited.has(key)) {
|
|
330
|
-
return Array.from(leafs);
|
|
331
|
-
}
|
|
332
|
-
else {
|
|
333
|
-
visited.add(key);
|
|
334
|
-
}
|
|
335
|
-
for (const depId of deps) {
|
|
336
|
-
if (!canGraphMoveToGraphBasedOnMovabilityGraph(movabilityGraph, depId, destinationId)) {
|
|
337
|
-
leafs.add(depId);
|
|
338
|
-
findLeafs(movabilityGraph, depId, destinationId, leafs, visited);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
return Array.from(leafs);
|
|
342
|
-
}
|
|
343
|
-
function createMemoizedQueryPathFinder() {
|
|
344
|
-
const memoizedQueryPaths = new Map();
|
|
345
|
-
return function findQueryPathsMemoized(supergraphState, rootTypeName, rootTypeFieldsToStartWith, leafTypeName, leafFieldName, typesInBetweenRootAndLeaf = []) {
|
|
346
|
-
const rootType = supergraphState.objectTypes.get(rootTypeName);
|
|
347
|
-
const paths = [];
|
|
348
|
-
for (const rootFieldName of rootTypeFieldsToStartWith) {
|
|
349
|
-
const key = JSON.stringify({
|
|
350
|
-
rootFieldName,
|
|
351
|
-
rootTypeName,
|
|
352
|
-
leafTypeName,
|
|
353
|
-
leafFieldName,
|
|
354
|
-
typesInBetweenRootAndLeaf,
|
|
355
|
-
});
|
|
356
|
-
const memoized = memoizedQueryPaths.get(key);
|
|
357
|
-
if (memoized) {
|
|
358
|
-
return memoized;
|
|
359
|
-
}
|
|
360
|
-
const rootFieldState = rootType.fields.get(rootFieldName);
|
|
361
|
-
if (rootFieldState) {
|
|
362
|
-
const fieldOutputTypeName = (0, state_js_2.stripTypeModifiers)(rootFieldState.type);
|
|
363
|
-
const referencedType = supergraphState.objectTypes.get(fieldOutputTypeName) ??
|
|
364
|
-
supergraphState.unionTypes.get(fieldOutputTypeName) ??
|
|
365
|
-
supergraphState.interfaceTypes.get(fieldOutputTypeName);
|
|
366
|
-
if (!referencedType) {
|
|
367
|
-
continue;
|
|
368
|
-
}
|
|
369
|
-
findQueryPathInType(new Set(), supergraphState, referencedType, leafTypeName, leafFieldName, path => {
|
|
370
|
-
const memoized = memoizedQueryPaths.get(key);
|
|
371
|
-
if (memoized) {
|
|
372
|
-
memoized.push(path);
|
|
373
|
-
}
|
|
374
|
-
else {
|
|
375
|
-
memoizedQueryPaths.set(key, [path]);
|
|
376
|
-
}
|
|
377
|
-
paths.push(path);
|
|
378
|
-
}, typesInBetweenRootAndLeaf, [
|
|
379
|
-
{
|
|
380
|
-
typeName: rootTypeName,
|
|
381
|
-
fieldName: rootFieldName,
|
|
382
|
-
},
|
|
383
|
-
]);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
return paths;
|
|
387
|
-
};
|
|
388
|
-
}
|
|
5
|
+
const state_js_1 = require("../../../utils/state.js");
|
|
6
|
+
const edge_js_1 = require("./satisfiablity/edge.js");
|
|
7
|
+
const supergraph_js_1 = require("./satisfiablity/supergraph.js");
|
|
389
8
|
function SatisfiabilityRule(context, supergraphState) {
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
const objectState = supergraphState.objectTypes.get(typeName);
|
|
398
|
-
if (!objectState) {
|
|
399
|
-
throw new Error(`State of object type "${typeName}" not found in Supergraph state`);
|
|
9
|
+
const supergraph = new supergraph_js_1.Supergraph(supergraphState);
|
|
10
|
+
const unreachables = supergraph.validate();
|
|
11
|
+
const errorByFieldCoordinate = {};
|
|
12
|
+
for (const unreachable of unreachables) {
|
|
13
|
+
const edge = unreachable.superPath.edge();
|
|
14
|
+
if (!edge) {
|
|
15
|
+
throw new Error('Expected edge to be defined');
|
|
400
16
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
for (const sourceGraphId of objectState.byGraph.keys()) {
|
|
406
|
-
graph.addNode(sourceGraphId);
|
|
407
|
-
}
|
|
408
|
-
for (const sourceGraphId of objectState.byGraph.keys()) {
|
|
409
|
-
const otherGraphIds = graphIds.filter(g => g !== sourceGraphId);
|
|
410
|
-
for (const destGraphId of otherGraphIds) {
|
|
411
|
-
if (canGraphMoveToGraphByEntity(supergraphState, objectState.name, sourceGraphId, destGraphId)) {
|
|
412
|
-
graph.addDependency(sourceGraphId, destGraphId);
|
|
413
|
-
}
|
|
17
|
+
if ((0, edge_js_1.isFieldEdge)(edge)) {
|
|
18
|
+
const fieldCoordinate = `${edge.move.typeName}.${edge.move.fieldName}`;
|
|
19
|
+
if (!errorByFieldCoordinate[fieldCoordinate]) {
|
|
20
|
+
errorByFieldCoordinate[fieldCoordinate] = [];
|
|
414
21
|
}
|
|
22
|
+
errorByFieldCoordinate[fieldCoordinate].push(unreachable);
|
|
415
23
|
}
|
|
416
|
-
movabilityGraph.set(typeName, graph);
|
|
417
|
-
return graph;
|
|
418
24
|
}
|
|
419
25
|
return {
|
|
420
26
|
ObjectTypeField(objectState, fieldState) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
|
-
if (objectState.byGraph.size === 1) {
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
const dependenciesOfObjectType = typeDependencies.dependentsOf(objectState.name);
|
|
430
|
-
const isReachableByRootType = {
|
|
431
|
-
query: dependenciesOfObjectType.includes('Query'),
|
|
432
|
-
mutation: dependenciesOfObjectType.includes('Mutation'),
|
|
433
|
-
subscription: dependenciesOfObjectType.includes('Subscription'),
|
|
434
|
-
};
|
|
435
|
-
const isReachable = isReachableByRootType.query ||
|
|
436
|
-
isReachableByRootType.mutation ||
|
|
437
|
-
isReachableByRootType.subscription;
|
|
438
|
-
if (!isReachable) {
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
const objectStateGraphPairs = Array.from(objectState.byGraph);
|
|
442
|
-
const fieldStateGraphPairs = Array.from(fieldState.byGraph);
|
|
443
|
-
if (objectStateGraphPairs.some(([_, objectTypeStateInGraph]) => objectTypeStateInGraph.inaccessible === true) ||
|
|
444
|
-
fieldStateGraphPairs.some(([_, fieldStateInGraph]) => fieldStateInGraph.inaccessible === true)) {
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
447
|
-
const isFieldShareableInAllSubgraphs = Array.from(fieldState.byGraph).every(([graphId, fieldStateInGraph]) => {
|
|
448
|
-
const fieldShareable = fieldStateInGraph.shareable &&
|
|
449
|
-
context.subgraphStates.get(graphId).version !== 'v1.0';
|
|
450
|
-
const typeShareable = objectState.byGraph.get(graphId).shareable === true;
|
|
451
|
-
return fieldShareable || typeShareable;
|
|
452
|
-
});
|
|
453
|
-
if (isFieldShareableInAllSubgraphs) {
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
if (fieldState.byGraph.size === objectState.byGraph.size &&
|
|
457
|
-
fieldStateGraphPairs.every(([_, f]) => f.usedAsKey === true && f.external === false && !f.override)) {
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
const keysInAllGraphs = objectStateGraphPairs.every(([_, o]) => o.keys.length > 0);
|
|
461
|
-
const uniqueKeyFieldsSet = new Set(objectStateGraphPairs
|
|
462
|
-
.map(([_, o]) => o.keys.map(k => k.fields))
|
|
463
|
-
.flat(1));
|
|
464
|
-
if (keysInAllGraphs && uniqueKeyFieldsSet.size === 1) {
|
|
27
|
+
const coordinate = `${objectState.name}.${fieldState.name}`;
|
|
28
|
+
const unreachables = errorByFieldCoordinate[coordinate];
|
|
29
|
+
if (!unreachables?.length) {
|
|
465
30
|
return;
|
|
466
31
|
}
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
},
|
|
472
|
-
Mutation: {
|
|
473
|
-
query: null,
|
|
474
|
-
reasons: [],
|
|
475
|
-
},
|
|
476
|
-
Subscription: {
|
|
477
|
-
query: null,
|
|
478
|
-
reasons: [],
|
|
479
|
-
},
|
|
480
|
-
};
|
|
481
|
-
const currentObjectTypeMovabilityGraph = getMovabilityGraphForType(objectState.name);
|
|
482
|
-
if (!currentObjectTypeMovabilityGraph) {
|
|
483
|
-
throw new Error(`Movability graph for object type "${objectState.name}" not found in Supergraph state`);
|
|
484
|
-
}
|
|
485
|
-
const findQueryPaths = createMemoizedQueryPathFinder();
|
|
486
|
-
if (uniqueKeyFieldsSet.size > 0) {
|
|
487
|
-
for (const graphId of objectState.byGraph.keys()) {
|
|
488
|
-
const fieldStateInGraph = fieldState.byGraph.get(graphId);
|
|
489
|
-
if (canGraphResolveField(objectState, fieldState, graphId, supergraphState, currentObjectTypeMovabilityGraph)) {
|
|
490
|
-
continue;
|
|
491
|
-
}
|
|
492
|
-
if (fieldStateInGraph?.external === true) {
|
|
493
|
-
const objectStateInGraph = objectState.byGraph.get(graphId);
|
|
494
|
-
if (objectStateInGraph.extension === true) {
|
|
495
|
-
continue;
|
|
496
|
-
}
|
|
497
|
-
if (fieldStateInGraph.required) {
|
|
498
|
-
continue;
|
|
499
|
-
}
|
|
500
|
-
if (fieldStateInGraph.provided) {
|
|
501
|
-
continue;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
const subgraphState = context.subgraphStates.get(graphId);
|
|
505
|
-
const schemaDefinitionOfGraph = subgraphState.schema;
|
|
506
|
-
const rootTypes = [
|
|
507
|
-
schemaDefinitionOfGraph.queryType
|
|
508
|
-
? [
|
|
509
|
-
'Query',
|
|
510
|
-
subgraphState.types.get(schemaDefinitionOfGraph.queryType),
|
|
511
|
-
]
|
|
512
|
-
: undefined,
|
|
513
|
-
schemaDefinitionOfGraph.mutationType
|
|
514
|
-
? [
|
|
515
|
-
'Mutation',
|
|
516
|
-
subgraphState.types.get(schemaDefinitionOfGraph.mutationType),
|
|
517
|
-
]
|
|
518
|
-
: undefined,
|
|
519
|
-
schemaDefinitionOfGraph.subscriptionType
|
|
520
|
-
? [
|
|
521
|
-
'Subscription',
|
|
522
|
-
subgraphState.types.get(schemaDefinitionOfGraph.subscriptionType),
|
|
523
|
-
]
|
|
524
|
-
: undefined,
|
|
525
|
-
].filter(helpers_js_2.isDefined);
|
|
526
|
-
if (rootTypes.length === 0) {
|
|
527
|
-
continue;
|
|
528
|
-
}
|
|
529
|
-
const otherGraphIds = objectStateGraphPairs
|
|
530
|
-
.filter(([g, _]) => g !== graphId)
|
|
531
|
-
.map(([g, _]) => g);
|
|
532
|
-
const graphsWithField = fieldStateGraphPairs
|
|
533
|
-
.filter(([g, _]) => canGraphResolveFieldDirectly(objectState, fieldState, g, supergraphState))
|
|
534
|
-
.map(([g, _]) => g);
|
|
535
|
-
const leafs = graphsWithField
|
|
536
|
-
.map(g => findLeafs(currentObjectTypeMovabilityGraph, graphId, g))
|
|
537
|
-
.flat(1);
|
|
538
|
-
if (leafs.length === 0 &&
|
|
539
|
-
currentObjectTypeMovabilityGraph.directDependenciesOf(graphId).length > 0) {
|
|
540
|
-
continue;
|
|
541
|
-
}
|
|
542
|
-
for (const [normalizedName, rootType] of rootTypes) {
|
|
543
|
-
const paths = findQueryPaths(supergraphState, normalizedName, Array.from(rootType.fields.keys()), objectState.name, fieldState.name, dependenciesOfObjectType);
|
|
544
|
-
const nonResolvablePaths = paths.filter(queryPath => !isSatisfiableQueryPath(supergraphState, queryPath));
|
|
545
|
-
if (nonResolvablePaths.length === 0) {
|
|
546
|
-
continue;
|
|
547
|
-
}
|
|
548
|
-
let shortestPath = nonResolvablePaths[0];
|
|
549
|
-
for (let i = 0; i < nonResolvablePaths.length; i++) {
|
|
550
|
-
const curr = nonResolvablePaths[i];
|
|
551
|
-
if (shortestPath.length > curr.length) {
|
|
552
|
-
shortestPath = curr;
|
|
553
|
-
}
|
|
554
|
-
if (shortestPath.length === curr.length) {
|
|
555
|
-
shortestPath = curr;
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
const query = printQueryPath(supergraphState, shortestPath);
|
|
559
|
-
const reasons = [];
|
|
560
|
-
const canBeIndirectlyResolved = leafs.length > 0;
|
|
561
|
-
const cannotMoveToList = (sourceGraphId) => canBeIndirectlyResolved
|
|
562
|
-
? graphsWithField
|
|
563
|
-
.map(gid => {
|
|
564
|
-
const keys = objectState.byGraph.get(gid).keys.map(k => k.fields);
|
|
565
|
-
if (keys.length > 0) {
|
|
566
|
-
return objectState.byGraph
|
|
567
|
-
.get(gid)
|
|
568
|
-
.keys.map(k => k.fields)
|
|
569
|
-
.map(fields => `cannot move to subgraph "${context.graphIdToName(gid)}" using @key(fields: "${fields}") of "${objectState.name}", the key field(s) cannot be resolved from subgraph "${context.graphIdToName(sourceGraphId)}".`);
|
|
570
|
-
}
|
|
571
|
-
return `cannot move to subgraph "${context.graphIdToName(gid)}", which has field "${objectState.name}.${fieldState.name}", because type "${objectState.name}" has no @key defined in subgraph "${context.graphIdToName(gid)}".`;
|
|
572
|
-
})
|
|
573
|
-
.flat(1)
|
|
574
|
-
: otherGraphIds
|
|
575
|
-
.filter(g => !currentObjectTypeMovabilityGraph.directDependenciesOf(graphId).includes(g))
|
|
576
|
-
.map(gid => {
|
|
577
|
-
const keys = objectState.byGraph.get(gid).keys.map(k => k.fields);
|
|
578
|
-
if (keys.length > 0) {
|
|
579
|
-
return objectState.byGraph
|
|
580
|
-
.get(gid)
|
|
581
|
-
.keys.map(k => k.fields)
|
|
582
|
-
.map(fields => `cannot move to subgraph "${context.graphIdToName(gid)}" using @key(fields: "${fields}") of "${objectState.name}", the key field(s) cannot be resolved from subgraph "${context.graphIdToName(sourceGraphId)}".`);
|
|
583
|
-
}
|
|
584
|
-
return `cannot move to subgraph "${context.graphIdToName(gid)}", which has field "${objectState.name}.${fieldState.name}", because type "${objectState.name}" has no @key defined in subgraph "${context.graphIdToName(gid)}".`;
|
|
585
|
-
})
|
|
586
|
-
.flat(1);
|
|
587
|
-
const fromSubgraphs = [graphId].concat(leafs);
|
|
588
|
-
if (!fieldStateInGraph) {
|
|
589
|
-
fromSubgraphs.forEach(gid => {
|
|
590
|
-
reasons.push([
|
|
591
|
-
gid,
|
|
592
|
-
[`cannot find field "${objectState.name}.${fieldState.name}".`].concat(cannotMoveToList(gid)),
|
|
593
|
-
]);
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
else if (fieldStateInGraph.external) {
|
|
597
|
-
fromSubgraphs.forEach(gid => {
|
|
598
|
-
reasons.push([
|
|
599
|
-
gid,
|
|
600
|
-
[
|
|
601
|
-
`field "${objectState.name}.${fieldState.name}" is not resolvable because marked @external.`,
|
|
602
|
-
].concat(cannotMoveToList(gid)),
|
|
603
|
-
]);
|
|
604
|
-
});
|
|
605
|
-
}
|
|
606
|
-
else {
|
|
607
|
-
console.log('can NOT resolve field', fieldState.name, 'in graph', graphId, 'reason: unknown');
|
|
608
|
-
}
|
|
609
|
-
if (!query || reasons.length === 0) {
|
|
610
|
-
continue;
|
|
611
|
-
}
|
|
612
|
-
context.reportError(new graphql_1.GraphQLError([
|
|
613
|
-
'The following supergraph API query:',
|
|
614
|
-
query,
|
|
615
|
-
'cannot be satisfied by the subgraphs because:',
|
|
616
|
-
...reasons.map(([gid, reasons]) => {
|
|
617
|
-
return (`- from subgraph "${context.graphIdToName(gid)}":\n` +
|
|
618
|
-
reasons.map(r => ` - ${r}`).join('\n'));
|
|
619
|
-
}),
|
|
620
|
-
].join('\n'), {
|
|
621
|
-
extensions: {
|
|
622
|
-
code: 'SATISFIABILITY_ERROR',
|
|
623
|
-
},
|
|
624
|
-
}));
|
|
625
|
-
}
|
|
32
|
+
for (const unreachable of unreachables) {
|
|
33
|
+
const queryString = printQueryPath(supergraphState, unreachable.superPath.steps());
|
|
34
|
+
if (!queryString) {
|
|
35
|
+
return;
|
|
626
36
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
const
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
const isShareableWithOtherGraphs = Array.from(subgraphState.types.values())
|
|
634
|
-
.filter(t => dependenciesOfObjectType.includes(t.name))
|
|
635
|
-
.every(t => {
|
|
636
|
-
if (t.kind === state_js_1.TypeKind.OBJECT) {
|
|
637
|
-
if (t.shareable &&
|
|
638
|
-
subgraphState.version !== 'v1.0') {
|
|
639
|
-
return true;
|
|
640
|
-
}
|
|
641
|
-
const fields = Array.from(t.fields.values());
|
|
642
|
-
if (fields
|
|
643
|
-
.filter(f => (0, state_js_2.stripTypeModifiers)(f.type) === objectState.name)
|
|
644
|
-
.every(f => f.shareable === true &&
|
|
645
|
-
subgraphState.version !== 'v1.0')) {
|
|
646
|
-
return true;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
return false;
|
|
650
|
-
});
|
|
651
|
-
if (isShareableWithOtherGraphs) {
|
|
652
|
-
continue;
|
|
653
|
-
}
|
|
654
|
-
const graphHasAtLeastOneResolvableField = Array.from(objectState.fields.values()).some(f => {
|
|
655
|
-
const fieldInGraph = f.byGraph.get(graphId);
|
|
656
|
-
if (!fieldInGraph) {
|
|
657
|
-
return false;
|
|
658
|
-
}
|
|
659
|
-
if (fieldInGraph.inaccessible === true) {
|
|
660
|
-
return false;
|
|
661
|
-
}
|
|
662
|
-
return true;
|
|
663
|
-
});
|
|
664
|
-
if (!graphHasAtLeastOneResolvableField) {
|
|
665
|
-
continue;
|
|
666
|
-
}
|
|
667
|
-
const entityTypesReferencingLookingObject = dependenciesOfObjectType
|
|
668
|
-
.map(typeName => supergraphState.objectTypes.get(typeName))
|
|
669
|
-
.filter((t) => !!t && Array.from(t.byGraph.values()).some(tg => tg.keys.length > 0));
|
|
670
|
-
const graphIdsUnableToResolveFieldViaEntityType = [];
|
|
671
|
-
for (const [graphId] of graphsWithoutField) {
|
|
672
|
-
const localEntityTypes = entityTypesReferencingLookingObject.filter(et => et.byGraph.has(graphId));
|
|
673
|
-
const isFieldResolvableThroughEntity = localEntityTypes.some(et => graphsWithField.some(targetGraphId => canGraphMoveToGraphByEntity(supergraphState, et.name, graphId, targetGraphId)));
|
|
674
|
-
if (!isFieldResolvableThroughEntity) {
|
|
675
|
-
graphIdsUnableToResolveFieldViaEntityType.push(graphId);
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
if (graphIdsUnableToResolveFieldViaEntityType.length === 0) {
|
|
679
|
-
continue;
|
|
680
|
-
}
|
|
681
|
-
const schemaDefinitionOfGraph = subgraphState.schema;
|
|
682
|
-
const rootTypes = [
|
|
683
|
-
schemaDefinitionOfGraph.queryType
|
|
684
|
-
? [
|
|
685
|
-
'Query',
|
|
686
|
-
subgraphState.types.get(schemaDefinitionOfGraph.queryType),
|
|
687
|
-
]
|
|
688
|
-
: undefined,
|
|
689
|
-
schemaDefinitionOfGraph.mutationType
|
|
690
|
-
? [
|
|
691
|
-
'Mutation',
|
|
692
|
-
subgraphState.types.get(schemaDefinitionOfGraph.mutationType),
|
|
693
|
-
]
|
|
694
|
-
: undefined,
|
|
695
|
-
schemaDefinitionOfGraph.subscriptionType
|
|
696
|
-
? [
|
|
697
|
-
'Subscription',
|
|
698
|
-
subgraphState.types.get(schemaDefinitionOfGraph.subscriptionType),
|
|
699
|
-
]
|
|
700
|
-
: undefined,
|
|
701
|
-
].filter(helpers_js_2.isDefined);
|
|
702
|
-
if (rootTypes.length === 0) {
|
|
703
|
-
continue;
|
|
704
|
-
}
|
|
705
|
-
for (const [normalizedName, rootType] of rootTypes) {
|
|
706
|
-
const rootTypeFields = Array.from(rootType.fields.keys()).filter(f => f !== '_entities' && f !== '_service');
|
|
707
|
-
if (rootTypeFields.length === 0) {
|
|
708
|
-
continue;
|
|
709
|
-
}
|
|
710
|
-
const supergraphRootType = supergraphState.objectTypes.get(normalizedName);
|
|
711
|
-
const rootFieldsReferencingObjectType = Array.from(supergraphRootType.fields.values()).filter(f => {
|
|
712
|
-
const fieldOutputTypeName = (0, state_js_2.stripTypeModifiers)(f.type);
|
|
713
|
-
return (fieldOutputTypeName === objectState.name ||
|
|
714
|
-
dependenciesOfObjectType.includes(fieldOutputTypeName));
|
|
715
|
-
});
|
|
716
|
-
if (rootFieldsReferencingObjectType.length === 0) {
|
|
717
|
-
continue;
|
|
718
|
-
}
|
|
719
|
-
const graphIdsImplementingObjectType = Array.from(objectState.byGraph.keys());
|
|
720
|
-
if (rootFieldsReferencingObjectType.every(field => graphIdsImplementingObjectType.every(g => field.byGraph.has(g)))) {
|
|
721
|
-
continue;
|
|
722
|
-
}
|
|
723
|
-
const areRootFieldsShared = graphsWithField.every(g => {
|
|
724
|
-
const localVersion = context.subgraphStates.get(g).version;
|
|
725
|
-
if (localVersion !== 'v1.0') {
|
|
726
|
-
return false;
|
|
727
|
-
}
|
|
728
|
-
const localSubgraph = context.subgraphStates.get(g);
|
|
729
|
-
const localSchemaDefinition = localSubgraph.schema;
|
|
730
|
-
const localRootTypeName = normalizedName === 'Query'
|
|
731
|
-
? localSchemaDefinition.queryType
|
|
732
|
-
: normalizedName === 'Mutation'
|
|
733
|
-
? localSchemaDefinition.mutationType
|
|
734
|
-
: normalizedName === 'Subscription'
|
|
735
|
-
? localSchemaDefinition.subscriptionType
|
|
736
|
-
: undefined;
|
|
737
|
-
if (!localRootTypeName) {
|
|
738
|
-
return false;
|
|
739
|
-
}
|
|
740
|
-
const localRootType = localSubgraph.types.get(localRootTypeName);
|
|
741
|
-
const localRootFields = Array.from(localRootType.fields.keys());
|
|
742
|
-
return rootFieldsReferencingObjectType.every(f => localRootFields.includes(f.name));
|
|
743
|
-
});
|
|
744
|
-
if (areRootFieldsShared) {
|
|
745
|
-
continue;
|
|
746
|
-
}
|
|
747
|
-
const paths = findQueryPaths(supergraphState, normalizedName, Array.from(rootType.fields.keys()), objectState.name, fieldState.name, dependenciesOfObjectType);
|
|
748
|
-
const nonResolvablePaths = paths.filter(queryPath => !isSatisfiableQueryPath(supergraphState, queryPath));
|
|
749
|
-
if (nonResolvablePaths.length === 0) {
|
|
750
|
-
continue;
|
|
751
|
-
}
|
|
752
|
-
if (!aggregatedErrorByRootType[normalizedName].query) {
|
|
753
|
-
aggregatedErrorByRootType[normalizedName].query = printExampleQuery(supergraphState, normalizedName, rootTypeFields, objectState.name, fieldState.name, graphId, dependenciesOfObjectType);
|
|
754
|
-
}
|
|
755
|
-
const firstFieldImplementingGraph = graphsWithField[0];
|
|
756
|
-
const graphNameOwningField = context.graphIdToName(firstFieldImplementingGraph);
|
|
757
|
-
aggregatedErrorByRootType[normalizedName].reasons.push([
|
|
758
|
-
graphId,
|
|
759
|
-
[
|
|
760
|
-
`cannot find field "${objectState.name}.${fieldState.name}".`,
|
|
761
|
-
`cannot move to subgraph "${graphNameOwningField}", which has field "${objectState.name}.${fieldState.name}", because type "${objectState.name}" has no @key defined in subgraph "${graphNameOwningField}".`,
|
|
762
|
-
],
|
|
763
|
-
]);
|
|
37
|
+
const errorsBySourceGraph = {};
|
|
38
|
+
const reasons = [];
|
|
39
|
+
for (const error of unreachable.listErrors()) {
|
|
40
|
+
const sourceGraphName = error.sourceGraphName;
|
|
41
|
+
if (!errorsBySourceGraph[sourceGraphName]) {
|
|
42
|
+
errorsBySourceGraph[sourceGraphName] = [];
|
|
764
43
|
}
|
|
44
|
+
errorsBySourceGraph[sourceGraphName].push(error);
|
|
765
45
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
46
|
+
for (const sourceGraphName in errorsBySourceGraph) {
|
|
47
|
+
const errors = errorsBySourceGraph[sourceGraphName];
|
|
48
|
+
reasons.push([sourceGraphName, errors.map(e => e.message)]);
|
|
49
|
+
}
|
|
50
|
+
if (reasons.length === 0) {
|
|
770
51
|
continue;
|
|
771
52
|
}
|
|
772
53
|
context.reportError(new graphql_1.GraphQLError([
|
|
773
54
|
'The following supergraph API query:',
|
|
774
|
-
|
|
55
|
+
queryString,
|
|
775
56
|
'cannot be satisfied by the subgraphs because:',
|
|
776
|
-
...
|
|
777
|
-
|
|
778
|
-
|
|
57
|
+
...reasons.map(([graphName, reasons]) => {
|
|
58
|
+
if (reasons.length === 1) {
|
|
59
|
+
return `- from subgraph "${graphName}": ${reasons[0]}`;
|
|
60
|
+
}
|
|
61
|
+
return (`- from subgraph "${graphName}":\n` + reasons.map(r => ` - ${r}`).join('\n'));
|
|
779
62
|
}),
|
|
780
63
|
].join('\n'), {
|
|
781
64
|
extensions: {
|
|
@@ -787,38 +70,6 @@ function SatisfiabilityRule(context, supergraphState) {
|
|
|
787
70
|
};
|
|
788
71
|
}
|
|
789
72
|
exports.SatisfiabilityRule = SatisfiabilityRule;
|
|
790
|
-
function buildOutputTypesDependencies(supergraphState) {
|
|
791
|
-
const graph = new dependency_graph_js_1.DepGraph({
|
|
792
|
-
circular: true,
|
|
793
|
-
});
|
|
794
|
-
for (const [typeName, typeState] of supergraphState.objectTypes) {
|
|
795
|
-
if (typeName === '_Service') {
|
|
796
|
-
continue;
|
|
797
|
-
}
|
|
798
|
-
graph.addNode(typeName);
|
|
799
|
-
for (const [_, fieldState] of typeState.fields) {
|
|
800
|
-
const referencedTypeName = (0, state_js_2.stripTypeModifiers)(fieldState.type);
|
|
801
|
-
if (!graph.hasNode(referencedTypeName)) {
|
|
802
|
-
graph.addNode(referencedTypeName);
|
|
803
|
-
}
|
|
804
|
-
graph.addDependency(typeName, referencedTypeName);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
for (const [typeName, typeState] of supergraphState.unionTypes) {
|
|
808
|
-
if (typeName === '_Entity') {
|
|
809
|
-
continue;
|
|
810
|
-
}
|
|
811
|
-
graph.addNode(typeName);
|
|
812
|
-
for (const memberType of typeState.members) {
|
|
813
|
-
const referencedTypeName = memberType;
|
|
814
|
-
if (!graph.hasNode(referencedTypeName)) {
|
|
815
|
-
graph.addNode(referencedTypeName);
|
|
816
|
-
}
|
|
817
|
-
graph.addDependency(typeName, referencedTypeName);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
return graph;
|
|
821
|
-
}
|
|
822
73
|
function printLine(msg, indentLevel) {
|
|
823
74
|
return ' '.repeat(indentLevel + 1) + msg;
|
|
824
75
|
}
|
|
@@ -835,12 +86,11 @@ function printQueryPath(supergraphState, queryPath) {
|
|
|
835
86
|
throw new Error(`Field "${point.typeName}.${point.fieldName}" not found in Supergraph state`);
|
|
836
87
|
}
|
|
837
88
|
const args = Array.from(fieldState.args)
|
|
838
|
-
.filter(([_, argState]) => (0, state_js_2.isNonNull)(argState.type))
|
|
839
89
|
.map(([name, argState]) => `${name}: ${(0, graphql_1.print)(createEmptyValueNode(argState.type, supergraphState))}`)
|
|
840
90
|
.join(', ');
|
|
841
91
|
const argsPrinted = args.length > 0 ? `(${args})` : '';
|
|
842
92
|
if (i == queryPath.length - 1) {
|
|
843
|
-
const outputTypeName = (0,
|
|
93
|
+
const outputTypeName = (0, state_js_1.stripTypeModifiers)(fieldState.type);
|
|
844
94
|
endsWithScalar =
|
|
845
95
|
supergraphState.scalarTypes.has(outputTypeName) ||
|
|
846
96
|
supergraphState.enumTypes.has(outputTypeName) ||
|
|
@@ -879,240 +129,15 @@ function printQueryPath(supergraphState, queryPath) {
|
|
|
879
129
|
lines.push('}');
|
|
880
130
|
return lines.join('\n');
|
|
881
131
|
}
|
|
882
|
-
function findQueryPathInType(visitedTypes, supergraphState, typeState, leafTypeName, leafFieldName, onQueryPathFound, typesInBetweenRootAndLeaf = [], currentPath = []) {
|
|
883
|
-
if (typeState.name !== leafTypeName) {
|
|
884
|
-
if (!typesInBetweenRootAndLeaf.includes(typeState.name)) {
|
|
885
|
-
return;
|
|
886
|
-
}
|
|
887
|
-
if (visitedTypes.has(typeState.name)) {
|
|
888
|
-
return;
|
|
889
|
-
}
|
|
890
|
-
visitedTypes.add(typeState.name);
|
|
891
|
-
}
|
|
892
|
-
if ('fields' in typeState) {
|
|
893
|
-
for (const [fieldName, fieldState] of typeState.fields) {
|
|
894
|
-
if (fieldName === leafFieldName && typeState.name === leafTypeName) {
|
|
895
|
-
onQueryPathFound(currentPath.concat([{ typeName: typeState.name, fieldName }]));
|
|
896
|
-
return;
|
|
897
|
-
}
|
|
898
|
-
const fieldOutputTypeName = (0, state_js_2.stripTypeModifiers)(fieldState.type);
|
|
899
|
-
const referencedType = supergraphState.objectTypes.get(fieldOutputTypeName) ??
|
|
900
|
-
supergraphState.unionTypes.get(fieldOutputTypeName) ??
|
|
901
|
-
supergraphState.interfaceTypes.get(fieldOutputTypeName);
|
|
902
|
-
if (!referencedType) {
|
|
903
|
-
continue;
|
|
904
|
-
}
|
|
905
|
-
if (referencedType.name === typeState.name) {
|
|
906
|
-
return;
|
|
907
|
-
}
|
|
908
|
-
findQueryPathInType(visitedTypes, supergraphState, referencedType, leafTypeName, leafFieldName, onQueryPathFound, typesInBetweenRootAndLeaf, currentPath.concat([{ typeName: typeState.name, fieldName }]));
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
else {
|
|
912
|
-
for (const member of typeState.members) {
|
|
913
|
-
const referencedType = supergraphState.objectTypes.get(member) ??
|
|
914
|
-
supergraphState.unionTypes.get(member) ??
|
|
915
|
-
supergraphState.interfaceTypes.get(member);
|
|
916
|
-
if (!referencedType) {
|
|
917
|
-
continue;
|
|
918
|
-
}
|
|
919
|
-
if (referencedType.name === typeState.name) {
|
|
920
|
-
return;
|
|
921
|
-
}
|
|
922
|
-
findQueryPathInType(visitedTypes, supergraphState, referencedType, leafTypeName, leafFieldName, onQueryPathFound, typesInBetweenRootAndLeaf, currentPath.concat([{ typeName: member }]));
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
function printExampleQuery(supergraphState, rootTypeName, rootTypeFieldsToStartWith, leafTypeName, leafFieldName, graphId, typesInBetweenRootAndLeaf = []) {
|
|
927
|
-
const rootType = supergraphState.objectTypes.get(rootTypeName);
|
|
928
|
-
function visitType(typeState, descendants, visitedTypes) {
|
|
929
|
-
if (visitedTypes.includes(typeState.name)) {
|
|
930
|
-
return null;
|
|
931
|
-
}
|
|
932
|
-
if ('members' in typeState) {
|
|
933
|
-
for (const member of typeState.members) {
|
|
934
|
-
const result = member === leafTypeName
|
|
935
|
-
? visitLeafType(supergraphState.objectTypes.get(member), descendants.concat([
|
|
936
|
-
{
|
|
937
|
-
kind: graphql_1.Kind.INLINE_FRAGMENT,
|
|
938
|
-
typeCondition: {
|
|
939
|
-
kind: graphql_1.Kind.NAMED_TYPE,
|
|
940
|
-
name: {
|
|
941
|
-
kind: graphql_1.Kind.NAME,
|
|
942
|
-
value: member,
|
|
943
|
-
},
|
|
944
|
-
},
|
|
945
|
-
selectionSet: {
|
|
946
|
-
kind: graphql_1.Kind.SELECTION_SET,
|
|
947
|
-
selections: [],
|
|
948
|
-
},
|
|
949
|
-
},
|
|
950
|
-
]))
|
|
951
|
-
: visitType(supergraphState.objectTypes.get(member), descendants.concat([
|
|
952
|
-
{
|
|
953
|
-
kind: graphql_1.Kind.INLINE_FRAGMENT,
|
|
954
|
-
typeCondition: {
|
|
955
|
-
kind: graphql_1.Kind.NAMED_TYPE,
|
|
956
|
-
name: {
|
|
957
|
-
kind: graphql_1.Kind.NAME,
|
|
958
|
-
value: member,
|
|
959
|
-
},
|
|
960
|
-
},
|
|
961
|
-
selectionSet: {
|
|
962
|
-
kind: graphql_1.Kind.SELECTION_SET,
|
|
963
|
-
selections: [],
|
|
964
|
-
},
|
|
965
|
-
},
|
|
966
|
-
]), visitedTypes.concat(typeState.name));
|
|
967
|
-
if (result) {
|
|
968
|
-
return result;
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
return null;
|
|
972
|
-
}
|
|
973
|
-
for (const [fieldName, fieldState] of Array.from(typeState.fields.entries()).reverse()) {
|
|
974
|
-
if (typeState.name === rootTypeName && !rootTypeFieldsToStartWith.includes(fieldName)) {
|
|
975
|
-
continue;
|
|
976
|
-
}
|
|
977
|
-
const fieldOutputTypeName = (0, state_js_2.stripTypeModifiers)(fieldState.type);
|
|
978
|
-
if (fieldOutputTypeName === leafTypeName) {
|
|
979
|
-
return visitLeafType(supergraphState.objectTypes.get(fieldOutputTypeName), descendants.concat([
|
|
980
|
-
{
|
|
981
|
-
kind: graphql_1.Kind.FIELD,
|
|
982
|
-
name: {
|
|
983
|
-
kind: graphql_1.Kind.NAME,
|
|
984
|
-
value: fieldName,
|
|
985
|
-
},
|
|
986
|
-
arguments: Array.from(fieldState.args).map(([argName, argState]) => ({
|
|
987
|
-
kind: graphql_1.Kind.ARGUMENT,
|
|
988
|
-
name: {
|
|
989
|
-
kind: graphql_1.Kind.NAME,
|
|
990
|
-
value: argName,
|
|
991
|
-
},
|
|
992
|
-
value: createEmptyValueNode(argState.type, supergraphState),
|
|
993
|
-
})),
|
|
994
|
-
},
|
|
995
|
-
]));
|
|
996
|
-
}
|
|
997
|
-
else if (typesInBetweenRootAndLeaf.includes(fieldOutputTypeName) &&
|
|
998
|
-
!visitedTypes.includes(fieldOutputTypeName)) {
|
|
999
|
-
const referencedType = supergraphState.objectTypes.get(fieldOutputTypeName) ??
|
|
1000
|
-
supergraphState.unionTypes.get(fieldOutputTypeName);
|
|
1001
|
-
return visitType(referencedType, descendants.concat([
|
|
1002
|
-
{
|
|
1003
|
-
kind: graphql_1.Kind.FIELD,
|
|
1004
|
-
name: {
|
|
1005
|
-
kind: graphql_1.Kind.NAME,
|
|
1006
|
-
value: fieldName,
|
|
1007
|
-
},
|
|
1008
|
-
arguments: Array.from(fieldState.args).map(([argName, argState]) => ({
|
|
1009
|
-
kind: graphql_1.Kind.ARGUMENT,
|
|
1010
|
-
name: {
|
|
1011
|
-
kind: graphql_1.Kind.NAME,
|
|
1012
|
-
value: argName,
|
|
1013
|
-
},
|
|
1014
|
-
value: createEmptyValueNode(argState.type, supergraphState),
|
|
1015
|
-
})),
|
|
1016
|
-
},
|
|
1017
|
-
]), visitedTypes.concat(typeState.name));
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
return null;
|
|
1021
|
-
}
|
|
1022
|
-
function visitLeafType(objectTypeState, descendants) {
|
|
1023
|
-
for (const [fieldName, fieldState] of objectTypeState.fields) {
|
|
1024
|
-
if (fieldName !== leafFieldName) {
|
|
1025
|
-
continue;
|
|
1026
|
-
}
|
|
1027
|
-
const fieldOutputTypeName = (0, state_js_2.stripTypeModifiers)(fieldState.type);
|
|
1028
|
-
const isObjectSpreadCapable = supergraphState.objectTypes.has(fieldOutputTypeName) ||
|
|
1029
|
-
supergraphState.interfaceTypes.has(fieldOutputTypeName) ||
|
|
1030
|
-
supergraphState.unionTypes.has(fieldOutputTypeName);
|
|
1031
|
-
return descendants.concat([
|
|
1032
|
-
{
|
|
1033
|
-
kind: graphql_1.Kind.FIELD,
|
|
1034
|
-
name: {
|
|
1035
|
-
kind: graphql_1.Kind.NAME,
|
|
1036
|
-
value: fieldName,
|
|
1037
|
-
},
|
|
1038
|
-
arguments: Array.from(fieldState.args).map(([argName, argState]) => ({
|
|
1039
|
-
kind: graphql_1.Kind.ARGUMENT,
|
|
1040
|
-
name: {
|
|
1041
|
-
kind: graphql_1.Kind.NAME,
|
|
1042
|
-
value: argName,
|
|
1043
|
-
},
|
|
1044
|
-
value: createEmptyValueNode(argState.type, supergraphState),
|
|
1045
|
-
})),
|
|
1046
|
-
selectionSet: isObjectSpreadCapable
|
|
1047
|
-
?
|
|
1048
|
-
{
|
|
1049
|
-
kind: graphql_1.Kind.SELECTION_SET,
|
|
1050
|
-
selections: [
|
|
1051
|
-
{
|
|
1052
|
-
kind: graphql_1.Kind.FRAGMENT_SPREAD,
|
|
1053
|
-
name: {
|
|
1054
|
-
kind: graphql_1.Kind.NAME,
|
|
1055
|
-
value: '',
|
|
1056
|
-
},
|
|
1057
|
-
},
|
|
1058
|
-
],
|
|
1059
|
-
}
|
|
1060
|
-
: undefined,
|
|
1061
|
-
},
|
|
1062
|
-
]);
|
|
1063
|
-
}
|
|
1064
|
-
return null;
|
|
1065
|
-
}
|
|
1066
|
-
const tree = visitType(rootType, [], []);
|
|
1067
|
-
let currentField = null;
|
|
1068
|
-
if (!tree) {
|
|
1069
|
-
return null;
|
|
1070
|
-
}
|
|
1071
|
-
tree.reverse();
|
|
1072
|
-
for (const field of tree) {
|
|
1073
|
-
if (!currentField) {
|
|
1074
|
-
currentField = {
|
|
1075
|
-
...field,
|
|
1076
|
-
};
|
|
1077
|
-
}
|
|
1078
|
-
else {
|
|
1079
|
-
currentField = {
|
|
1080
|
-
...field,
|
|
1081
|
-
selectionSet: {
|
|
1082
|
-
kind: graphql_1.Kind.SELECTION_SET,
|
|
1083
|
-
selections: [currentField],
|
|
1084
|
-
},
|
|
1085
|
-
};
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
const query = {
|
|
1089
|
-
kind: graphql_1.Kind.DOCUMENT,
|
|
1090
|
-
definitions: [
|
|
1091
|
-
{
|
|
1092
|
-
kind: graphql_1.Kind.OPERATION_DEFINITION,
|
|
1093
|
-
operation: rootTypeName === 'Query'
|
|
1094
|
-
? graphql_1.OperationTypeNode.QUERY
|
|
1095
|
-
: rootTypeName === 'Mutation'
|
|
1096
|
-
? graphql_1.OperationTypeNode.MUTATION
|
|
1097
|
-
: graphql_1.OperationTypeNode.SUBSCRIPTION,
|
|
1098
|
-
selectionSet: {
|
|
1099
|
-
kind: graphql_1.Kind.SELECTION_SET,
|
|
1100
|
-
selections: [currentField],
|
|
1101
|
-
},
|
|
1102
|
-
},
|
|
1103
|
-
],
|
|
1104
|
-
};
|
|
1105
|
-
return (0, graphql_1.print)(query);
|
|
1106
|
-
}
|
|
1107
132
|
function createEmptyValueNode(fullType, supergraphState) {
|
|
1108
|
-
if ((0,
|
|
133
|
+
if ((0, state_js_1.isList)(fullType)) {
|
|
1109
134
|
return {
|
|
1110
135
|
kind: graphql_1.Kind.LIST,
|
|
1111
136
|
values: [],
|
|
1112
137
|
};
|
|
1113
138
|
}
|
|
1114
|
-
if ((0,
|
|
1115
|
-
const innerType = (0,
|
|
139
|
+
if ((0, state_js_1.isNonNull)(fullType)) {
|
|
140
|
+
const innerType = (0, state_js_1.stripNonNull)(fullType);
|
|
1116
141
|
return createEmptyValueNode(innerType, supergraphState);
|
|
1117
142
|
}
|
|
1118
143
|
if (supergraphState.enumTypes.has(fullType)) {
|
|
@@ -1133,7 +158,7 @@ function createEmptyValueNode(fullType, supergraphState) {
|
|
|
1133
158
|
return {
|
|
1134
159
|
kind: graphql_1.Kind.OBJECT,
|
|
1135
160
|
fields: Array.from(inputObjectTypeState.fields)
|
|
1136
|
-
.filter(([_, fieldState]) => (0,
|
|
161
|
+
.filter(([_, fieldState]) => (0, state_js_1.isNonNull)(fieldState.type))
|
|
1137
162
|
.map(([fieldName, fieldState]) => ({
|
|
1138
163
|
kind: graphql_1.Kind.OBJECT_FIELD,
|
|
1139
164
|
name: {
|
|
@@ -1174,64 +199,3 @@ function createEmptyValueNode(fullType, supergraphState) {
|
|
|
1174
199
|
}
|
|
1175
200
|
throw new Error(`Type "${fullType}" is not supported.`);
|
|
1176
201
|
}
|
|
1177
|
-
function resolveFieldsFromFieldSet(fields, typeName, graphId, supergraphState) {
|
|
1178
|
-
const paths = new Set();
|
|
1179
|
-
const coordinates = new Set();
|
|
1180
|
-
const selectionSet = (0, helpers_js_1.parseFields)(fields);
|
|
1181
|
-
if (!selectionSet) {
|
|
1182
|
-
return {
|
|
1183
|
-
coordinates,
|
|
1184
|
-
paths,
|
|
1185
|
-
pairs: [],
|
|
1186
|
-
};
|
|
1187
|
-
}
|
|
1188
|
-
const pairs = [];
|
|
1189
|
-
findFieldPathsFromSelectionSet(paths, coordinates, pairs, typeName, selectionSet, typeName, graphId, supergraphState);
|
|
1190
|
-
return {
|
|
1191
|
-
coordinates,
|
|
1192
|
-
paths,
|
|
1193
|
-
pairs,
|
|
1194
|
-
};
|
|
1195
|
-
}
|
|
1196
|
-
function findFieldPathsFromSelectionSet(fieldPaths, coordinates, pairs, typeName, selectionSet, currentPath, graphId, supergraphState) {
|
|
1197
|
-
for (const selection of selectionSet.selections) {
|
|
1198
|
-
if (selection.kind === graphql_1.Kind.FIELD) {
|
|
1199
|
-
const innerPath = `${currentPath}.${selection.name.value}`;
|
|
1200
|
-
fieldPaths.add(innerPath);
|
|
1201
|
-
if (Array.isArray(typeName)) {
|
|
1202
|
-
for (const t of typeName) {
|
|
1203
|
-
pairs.push([innerPath, { typeName: t, fieldName: selection.name.value }]);
|
|
1204
|
-
coordinates.add(`${t}.${selection.name.value}`);
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
else {
|
|
1208
|
-
pairs.push([innerPath, { typeName, fieldName: selection.name.value }]);
|
|
1209
|
-
coordinates.add(`${typeName}.${selection.name.value}`);
|
|
1210
|
-
}
|
|
1211
|
-
if (selection.selectionSet) {
|
|
1212
|
-
const types = (Array.isArray(typeName) ? typeName : [typeName]).map(tName => {
|
|
1213
|
-
const outputType = supergraphState.objectTypes.get(tName) ?? supergraphState.interfaceTypes.get(tName);
|
|
1214
|
-
if (!outputType) {
|
|
1215
|
-
throw new Error(`Type "${tName}" is not defined.`);
|
|
1216
|
-
}
|
|
1217
|
-
return outputType;
|
|
1218
|
-
});
|
|
1219
|
-
const typesWithField = types.filter(t => t.fields.has(selection.name.value));
|
|
1220
|
-
if (typesWithField.length === 0) {
|
|
1221
|
-
throw new Error(`Type "${typeName.toString()}" does not have field "${selection.name.value}".`);
|
|
1222
|
-
}
|
|
1223
|
-
const outputTypes = typesWithField.map(t => (0, state_js_2.stripTypeModifiers)(t.fields.get(selection.name.value).type));
|
|
1224
|
-
findFieldPathsFromSelectionSet(fieldPaths, coordinates, pairs, outputTypes, selection.selectionSet, innerPath, graphId, supergraphState);
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
else if (selection.kind === graphql_1.Kind.INLINE_FRAGMENT) {
|
|
1228
|
-
if (!selection.typeCondition) {
|
|
1229
|
-
throw new Error(`Inline fragment without type condition is not supported.`);
|
|
1230
|
-
}
|
|
1231
|
-
findFieldPathsFromSelectionSet(fieldPaths, coordinates, pairs, selection.typeCondition.name.value, selection.selectionSet, `${currentPath}.(${selection.typeCondition.name.value})`, graphId, supergraphState);
|
|
1232
|
-
}
|
|
1233
|
-
else {
|
|
1234
|
-
throw new Error(`Fragment spread is not supported.`);
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
}
|