@wundergraph/composition 0.6.0 → 0.6.2
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/dist/ast/ast.js +1 -0
- package/dist/ast/ast.js.map +1 -1
- package/dist/ast/utils.d.ts +4 -3
- package/dist/ast/utils.js +35 -9
- package/dist/ast/utils.js.map +1 -1
- package/dist/errors/errors.d.ts +1 -0
- package/dist/errors/errors.js +6 -3
- package/dist/errors/errors.js.map +1 -1
- package/dist/federation/federation-factory.d.ts +13 -4
- package/dist/federation/federation-factory.js +202 -91
- package/dist/federation/federation-factory.js.map +1 -1
- package/dist/federation/utils.d.ts +9 -1
- package/dist/federation/utils.js +9 -1
- package/dist/federation/utils.js.map +1 -1
- package/dist/normalization/normalization-factory.d.ts +3 -0
- package/dist/normalization/normalization-factory.js +16 -2
- package/dist/normalization/normalization-factory.js.map +1 -1
- package/dist/normalization/utils.js +12 -0
- package/dist/normalization/utils.js.map +1 -1
- package/dist/subgraph/subgraph.d.ts +1 -0
- package/dist/subgraph/subgraph.js +5 -4
- package/dist/subgraph/subgraph.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/constants.js +83 -18
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/string-constants.d.ts +7 -1
- package/dist/utils/string-constants.js +9 -3
- package/dist/utils/string-constants.js.map +1 -1
- package/dist/utils/utils.d.ts +1 -0
- package/dist/utils/utils.js +11 -1
- package/dist/utils/utils.js.map +1 -1
- package/package.json +2 -2
|
@@ -16,6 +16,7 @@ const constants_1 = require("../utils/constants");
|
|
|
16
16
|
const normalization_factory_1 = require("../normalization/normalization-factory");
|
|
17
17
|
class FederationFactory {
|
|
18
18
|
abstractToConcreteTypeNames = new Map();
|
|
19
|
+
areFieldsExternal = false;
|
|
19
20
|
areFieldsShareable = false;
|
|
20
21
|
argumentTypeNameSet = new Set();
|
|
21
22
|
argumentConfigurations = [];
|
|
@@ -38,11 +39,13 @@ class FederationFactory {
|
|
|
38
39
|
isCurrentParentExtensionType = false;
|
|
39
40
|
isParentRootType = false;
|
|
40
41
|
isParentInputObject = false;
|
|
42
|
+
keyFieldsByParentTypeName = new Map();
|
|
41
43
|
outputFieldTypeNameSet = new Set();
|
|
42
44
|
parents = new Map();
|
|
43
45
|
rootTypeNames = new Set([string_constants_1.DEFAULT_MUTATION, string_constants_1.DEFAULT_QUERY, string_constants_1.DEFAULT_SUBSCRIPTION]);
|
|
44
46
|
subgraphs = [];
|
|
45
47
|
shareableErrorTypeNames = new Map();
|
|
48
|
+
evaluatedObjectLikesBySubgraph = new Map();
|
|
46
49
|
constructor(subgraphs) {
|
|
47
50
|
this.subgraphs = subgraphs;
|
|
48
51
|
}
|
|
@@ -70,12 +73,6 @@ class FederationFactory {
|
|
|
70
73
|
(0, subgraph_1.walkSubgraphToCollectFields)(this, subgraph);
|
|
71
74
|
}
|
|
72
75
|
}
|
|
73
|
-
isFieldEntityKey(parent) {
|
|
74
|
-
if (parent.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION || parent.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
|
|
75
|
-
return parent.entityKeys.has(this.childName);
|
|
76
|
-
}
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
76
|
getEnumMergeMethod(enumName) {
|
|
80
77
|
if (this.inputFieldTypeNameSet.has(enumName) || this.argumentTypeNameSet.has(enumName)) {
|
|
81
78
|
if (this.outputFieldTypeNameSet.has(enumName)) {
|
|
@@ -141,6 +138,7 @@ class FederationFactory {
|
|
|
141
138
|
const existingArgumentContainer = argumentMap.get(argName);
|
|
142
139
|
if (!existingArgumentContainer) {
|
|
143
140
|
argumentMap.set(argName, {
|
|
141
|
+
directives: this.extractPersistedDirectives(argumentNode.directives || [], (0, utils_2.newPersistedDirectivesContainer)()),
|
|
144
142
|
includeDefaultValue: !!argumentNode.defaultValue,
|
|
145
143
|
node: (0, ast_1.inputValueDefinitionNodeToMutable)(argumentNode, this.childName),
|
|
146
144
|
requiredSubgraphs: this.upsertRequiredSubgraph(new Set(), isRequired),
|
|
@@ -148,6 +146,7 @@ class FederationFactory {
|
|
|
148
146
|
});
|
|
149
147
|
continue;
|
|
150
148
|
}
|
|
149
|
+
this.extractPersistedDirectives(argumentNode.directives || [], existingArgumentContainer.directives);
|
|
151
150
|
(0, utils_1.setLongestDescriptionForNode)(existingArgumentContainer.node, argumentNode.description);
|
|
152
151
|
this.upsertRequiredSubgraph(existingArgumentContainer.requiredSubgraphs, isRequired);
|
|
153
152
|
existingArgumentContainer.subgraphs.add(this.currentSubgraphName);
|
|
@@ -165,11 +164,22 @@ class FederationFactory {
|
|
|
165
164
|
}
|
|
166
165
|
return argumentMap;
|
|
167
166
|
}
|
|
167
|
+
isFieldEntityKey() {
|
|
168
|
+
const parent = this.keyFieldsByParentTypeName.get(this.parentTypeName);
|
|
169
|
+
if (parent) {
|
|
170
|
+
return parent.has(this.childName);
|
|
171
|
+
}
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
isFieldExternal(node) {
|
|
175
|
+
return this.areFieldsExternal || (0, utils_1.isNodeExternal)(node);
|
|
176
|
+
}
|
|
168
177
|
isFieldShareable(node, parent) {
|
|
169
|
-
return (!this.isCurrentSubgraphVersionTwo
|
|
170
|
-
this.areFieldsShareable
|
|
171
|
-
|
|
172
|
-
(
|
|
178
|
+
return (!this.isCurrentSubgraphVersionTwo
|
|
179
|
+
|| this.areFieldsShareable
|
|
180
|
+
|| this.isFieldEntityKey()
|
|
181
|
+
|| (0, utils_1.isNodeShareable)(node)
|
|
182
|
+
|| (0, utils_1.isNodeOverridden)(node));
|
|
173
183
|
}
|
|
174
184
|
upsertDirectiveNode(node) {
|
|
175
185
|
const directiveName = node.name.value;
|
|
@@ -199,6 +209,27 @@ class FederationFactory {
|
|
|
199
209
|
this.executableDirectives.add(directiveName);
|
|
200
210
|
}
|
|
201
211
|
}
|
|
212
|
+
areAllFieldInstancesExternalOrShareable(fieldContainer) {
|
|
213
|
+
let shareableFields = 0;
|
|
214
|
+
let unshareableFields = 0;
|
|
215
|
+
for (const [subgraphName, isShareable] of fieldContainer.subgraphsByShareable) {
|
|
216
|
+
if (isShareable) {
|
|
217
|
+
shareableFields += 1;
|
|
218
|
+
if (shareableFields && unshareableFields) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (fieldContainer.subgraphsByExternal.get(subgraphName)) {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
unshareableFields += 1;
|
|
227
|
+
if (shareableFields || unshareableFields > 1) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
202
233
|
upsertFieldNode(node) {
|
|
203
234
|
const parent = this.isCurrentParentExtensionType
|
|
204
235
|
? (0, utils_3.getOrThrowError)(this.extensions, this.parentTypeName, string_constants_1.EXTENSIONS)
|
|
@@ -209,6 +240,7 @@ class FederationFactory {
|
|
|
209
240
|
throw (0, errors_1.unexpectedKindFatalError)(this.parentTypeName);
|
|
210
241
|
}
|
|
211
242
|
const fieldMap = parent.fields;
|
|
243
|
+
const isFieldExternal = this.isFieldExternal(node);
|
|
212
244
|
const isFieldShareable = this.isFieldShareable(node, parent);
|
|
213
245
|
const fieldPath = `${this.parentTypeName}.${this.childName}`;
|
|
214
246
|
const fieldRootTypeName = (0, type_merging_1.getNamedTypeForChild)(fieldPath, node.type);
|
|
@@ -218,6 +250,7 @@ class FederationFactory {
|
|
|
218
250
|
(0, utils_1.setLongestDescriptionForNode)(existingFieldContainer.node, node.description);
|
|
219
251
|
existingFieldContainer.subgraphs.add(this.currentSubgraphName);
|
|
220
252
|
existingFieldContainer.subgraphsByShareable.set(this.currentSubgraphName, isFieldShareable);
|
|
253
|
+
existingFieldContainer.subgraphsByExternal.set(this.currentSubgraphName, isFieldExternal);
|
|
221
254
|
const { typeErrors, typeNode } = (0, type_merging_1.getLeastRestrictiveMergedTypeNode)(existingFieldContainer.node.type, node.type, this.parentTypeName, this.childName);
|
|
222
255
|
if (typeNode) {
|
|
223
256
|
existingFieldContainer.node.type = typeNode;
|
|
@@ -229,30 +262,38 @@ class FederationFactory {
|
|
|
229
262
|
this.errors.push((0, errors_1.incompatibleChildTypesError)(this.parentTypeName, this.childName, typeErrors[0], typeErrors[1]));
|
|
230
263
|
}
|
|
231
264
|
this.upsertArguments(node, existingFieldContainer.arguments);
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
265
|
+
/* A field is valid if one of the following is true:
|
|
266
|
+
1. The field is an interface
|
|
267
|
+
2. The field is external
|
|
268
|
+
3. The existing fields AND the current field are ALL shareable
|
|
269
|
+
4. All other fields besides the current field are external
|
|
270
|
+
*/
|
|
271
|
+
if (this.isCurrentParentInterface
|
|
272
|
+
|| isFieldExternal
|
|
273
|
+
|| (existingFieldContainer.isShareable && isFieldShareable)
|
|
274
|
+
|| this.areAllFieldInstancesExternalOrShareable(existingFieldContainer)) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const shareableErrorTypeNames = this.shareableErrorTypeNames.get(this.parentTypeName);
|
|
278
|
+
if (shareableErrorTypeNames) {
|
|
279
|
+
shareableErrorTypeNames.add(this.childName);
|
|
241
280
|
}
|
|
281
|
+
else {
|
|
282
|
+
this.shareableErrorTypeNames.set(this.parentTypeName, new Set([this.childName]));
|
|
283
|
+
}
|
|
284
|
+
// }
|
|
242
285
|
return;
|
|
243
286
|
}
|
|
244
287
|
this.outputFieldTypeNameSet.add(fieldRootTypeName);
|
|
245
288
|
fieldMap.set(this.childName, {
|
|
246
289
|
arguments: this.upsertArguments(node, new Map()),
|
|
247
|
-
directives: this.extractPersistedDirectives(node.directives || [],
|
|
248
|
-
directives: new Map(),
|
|
249
|
-
tags: new Map(),
|
|
250
|
-
}),
|
|
290
|
+
directives: this.extractPersistedDirectives(node.directives || [], (0, utils_2.newPersistedDirectivesContainer)()),
|
|
251
291
|
isShareable: isFieldShareable,
|
|
252
292
|
node: (0, ast_1.fieldDefinitionNodeToMutable)(node, this.parentTypeName),
|
|
253
293
|
namedTypeName: fieldRootTypeName,
|
|
254
294
|
subgraphs: new Set([this.currentSubgraphName]),
|
|
255
295
|
subgraphsByShareable: new Map([[this.currentSubgraphName, isFieldShareable]]),
|
|
296
|
+
subgraphsByExternal: new Map([[this.currentSubgraphName, isFieldExternal]]),
|
|
256
297
|
});
|
|
257
298
|
}
|
|
258
299
|
upsertValueNode(node) {
|
|
@@ -276,10 +317,7 @@ class FederationFactory {
|
|
|
276
317
|
}
|
|
277
318
|
enumValues.set(this.childName, {
|
|
278
319
|
appearances: 1,
|
|
279
|
-
directives: this.extractPersistedDirectives(node.directives || [],
|
|
280
|
-
directives: new Map(),
|
|
281
|
-
tags: new Map(),
|
|
282
|
-
}),
|
|
320
|
+
directives: this.extractPersistedDirectives(node.directives || [], (0, utils_2.newPersistedDirectivesContainer)()),
|
|
283
321
|
node: (0, ast_1.enumValueDefinitionNodeToMutable)(node),
|
|
284
322
|
});
|
|
285
323
|
return;
|
|
@@ -314,10 +352,7 @@ class FederationFactory {
|
|
|
314
352
|
this.inputFieldTypeNameSet.add(inputValueNamedType);
|
|
315
353
|
inputValues.set(this.childName, {
|
|
316
354
|
appearances: 1,
|
|
317
|
-
directives: this.extractPersistedDirectives(node.directives || [],
|
|
318
|
-
directives: new Map(),
|
|
319
|
-
tags: new Map(),
|
|
320
|
-
}),
|
|
355
|
+
directives: this.extractPersistedDirectives(node.directives || [], (0, utils_2.newPersistedDirectivesContainer)()),
|
|
321
356
|
includeDefaultValue: !!node.defaultValue,
|
|
322
357
|
node: (0, ast_1.inputValueDefinitionNodeToMutable)(node, this.parentTypeName),
|
|
323
358
|
});
|
|
@@ -344,10 +379,7 @@ class FederationFactory {
|
|
|
344
379
|
}
|
|
345
380
|
this.parents.set(parentTypeName, {
|
|
346
381
|
appearances: 1,
|
|
347
|
-
directives: this.extractPersistedDirectives(node.directives || [],
|
|
348
|
-
directives: new Map(),
|
|
349
|
-
tags: new Map(),
|
|
350
|
-
}),
|
|
382
|
+
directives: this.extractPersistedDirectives(node.directives || [], (0, utils_2.newPersistedDirectivesContainer)()),
|
|
351
383
|
values: new Map(),
|
|
352
384
|
kind: node.kind,
|
|
353
385
|
node: (0, ast_1.enumTypeDefinitionNodeToMutable)(node),
|
|
@@ -363,10 +395,7 @@ class FederationFactory {
|
|
|
363
395
|
}
|
|
364
396
|
this.parents.set(parentTypeName, {
|
|
365
397
|
appearances: 1,
|
|
366
|
-
directives: this.extractPersistedDirectives(node.directives || [],
|
|
367
|
-
directives: new Map(),
|
|
368
|
-
tags: new Map(),
|
|
369
|
-
}),
|
|
398
|
+
directives: this.extractPersistedDirectives(node.directives || [], (0, utils_2.newPersistedDirectivesContainer)()),
|
|
370
399
|
fields: new Map(),
|
|
371
400
|
kind: node.kind,
|
|
372
401
|
node: (0, ast_1.inputObjectTypeDefinitionNodeToMutable)(node),
|
|
@@ -384,10 +413,7 @@ class FederationFactory {
|
|
|
384
413
|
const nestedInterfaces = new Set();
|
|
385
414
|
(0, utils_1.extractInterfaces)(node, nestedInterfaces);
|
|
386
415
|
this.parents.set(parentTypeName, {
|
|
387
|
-
directives: this.extractPersistedDirectives(node.directives || [],
|
|
388
|
-
directives: new Map(),
|
|
389
|
-
tags: new Map(),
|
|
390
|
-
}),
|
|
416
|
+
directives: this.extractPersistedDirectives(node.directives || [], (0, utils_2.newPersistedDirectivesContainer)()),
|
|
391
417
|
fields: new Map(),
|
|
392
418
|
interfaces: nestedInterfaces,
|
|
393
419
|
kind: node.kind,
|
|
@@ -403,10 +429,7 @@ class FederationFactory {
|
|
|
403
429
|
return;
|
|
404
430
|
}
|
|
405
431
|
this.parents.set(parentTypeName, {
|
|
406
|
-
directives: this.extractPersistedDirectives(node.directives || [],
|
|
407
|
-
directives: new Map(),
|
|
408
|
-
tags: new Map(),
|
|
409
|
-
}),
|
|
432
|
+
directives: this.extractPersistedDirectives(node.directives || [], (0, utils_2.newPersistedDirectivesContainer)()),
|
|
410
433
|
kind: node.kind,
|
|
411
434
|
node: (0, ast_1.scalarTypeDefinitionNodeToMutable)(node),
|
|
412
435
|
});
|
|
@@ -426,10 +449,7 @@ class FederationFactory {
|
|
|
426
449
|
const entityKeys = new Set();
|
|
427
450
|
(0, utils_1.extractEntityKeys)(node, entityKeys, this.errors);
|
|
428
451
|
this.parents.set(parentTypeName, {
|
|
429
|
-
directives: this.extractPersistedDirectives(node.directives || [],
|
|
430
|
-
directives: new Map(),
|
|
431
|
-
tags: new Map(),
|
|
432
|
-
}),
|
|
452
|
+
directives: this.extractPersistedDirectives(node.directives || [], (0, utils_2.newPersistedDirectivesContainer)()),
|
|
433
453
|
fields: new Map(),
|
|
434
454
|
entityKeys,
|
|
435
455
|
interfaces,
|
|
@@ -452,10 +472,7 @@ class FederationFactory {
|
|
|
452
472
|
return;
|
|
453
473
|
}
|
|
454
474
|
this.parents.set(parentTypeName, {
|
|
455
|
-
directives: this.extractPersistedDirectives(node.directives || [],
|
|
456
|
-
directives: new Map(),
|
|
457
|
-
tags: new Map(),
|
|
458
|
-
}),
|
|
475
|
+
directives: this.extractPersistedDirectives(node.directives || [], (0, utils_2.newPersistedDirectivesContainer)()),
|
|
459
476
|
kind: node.kind,
|
|
460
477
|
members: new Set(node.types?.map((member) => member.name.value)),
|
|
461
478
|
node: (0, ast_1.unionTypeDefinitionNodeToMutable)(node),
|
|
@@ -478,10 +495,7 @@ class FederationFactory {
|
|
|
478
495
|
const interfaces = (0, utils_1.extractInterfaces)(node, new Set());
|
|
479
496
|
const entityKeys = (0, utils_1.extractEntityKeys)(node, new Set(), this.errors);
|
|
480
497
|
this.extensions.set(this.parentTypeName, {
|
|
481
|
-
directives: this.extractPersistedDirectives(node.directives || [],
|
|
482
|
-
directives: new Map(),
|
|
483
|
-
tags: new Map(),
|
|
484
|
-
}),
|
|
498
|
+
directives: this.extractPersistedDirectives(node.directives || [], (0, utils_2.newPersistedDirectivesContainer)()),
|
|
485
499
|
entityKeys,
|
|
486
500
|
fields: new Map(),
|
|
487
501
|
interfaces,
|
|
@@ -621,7 +635,7 @@ class FederationFactory {
|
|
|
621
635
|
errors.push({
|
|
622
636
|
argumentName,
|
|
623
637
|
missingSubgraphs,
|
|
624
|
-
requiredSubgraphs: [...argumentContainer.requiredSubgraphs]
|
|
638
|
+
requiredSubgraphs: [...argumentContainer.requiredSubgraphs],
|
|
625
639
|
});
|
|
626
640
|
}
|
|
627
641
|
// If the argument is always optional, but it's not defined in all subgraphs that define the field,
|
|
@@ -630,7 +644,7 @@ class FederationFactory {
|
|
|
630
644
|
}
|
|
631
645
|
argumentContainer.node.defaultValue = argumentContainer.includeDefaultValue
|
|
632
646
|
? argumentContainer.node.defaultValue : undefined;
|
|
633
|
-
args.push(
|
|
647
|
+
args.push((0, utils_1.pushPersistedDirectivesAndGetNode)(argumentContainer));
|
|
634
648
|
if (argumentNames) {
|
|
635
649
|
argumentNames.push(argumentName);
|
|
636
650
|
}
|
|
@@ -662,7 +676,7 @@ class FederationFactory {
|
|
|
662
676
|
if (!fieldContainer.arguments) {
|
|
663
677
|
return fieldContainer.node;
|
|
664
678
|
}
|
|
665
|
-
(0, utils_1.
|
|
679
|
+
(0, utils_1.pushPersistedDirectivesAndGetNode)(fieldContainer);
|
|
666
680
|
const fieldName = fieldContainer.node.name.value;
|
|
667
681
|
const fieldPath = `${parentTypeName}.${fieldName}`;
|
|
668
682
|
const args = [];
|
|
@@ -676,12 +690,34 @@ class FederationFactory {
|
|
|
676
690
|
this.argumentConfigurations.push({
|
|
677
691
|
argumentNames,
|
|
678
692
|
fieldName,
|
|
679
|
-
typeName: parentTypeName
|
|
693
|
+
typeName: parentTypeName,
|
|
680
694
|
});
|
|
681
695
|
}
|
|
682
696
|
fieldContainer.node.arguments = args;
|
|
683
697
|
return fieldContainer.node;
|
|
684
698
|
}
|
|
699
|
+
// the deprecated directive with the longest reason is kept
|
|
700
|
+
upsertDeprecatedDirective(directive, deprecatedDirectiveContainer) {
|
|
701
|
+
if (!directive.arguments || directive.arguments.length < 1) {
|
|
702
|
+
deprecatedDirectiveContainer.directive = directive;
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
if (directive.arguments.length !== 1) {
|
|
706
|
+
this.errors.push(errors_1.invalidDeprecatedDirectiveError);
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
const reasonArgument = directive.arguments[0].value;
|
|
710
|
+
if (reasonArgument.kind !== graphql_1.Kind.STRING) {
|
|
711
|
+
this.errors.push(errors_1.invalidDeprecatedDirectiveError);
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
if (deprecatedDirectiveContainer.reason
|
|
715
|
+
&& reasonArgument.value.length < deprecatedDirectiveContainer.reason.length) {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
deprecatedDirectiveContainer.reason = reasonArgument.value;
|
|
719
|
+
deprecatedDirectiveContainer.directive = directive;
|
|
720
|
+
}
|
|
685
721
|
// tags with the same name string are merged
|
|
686
722
|
mergeTagDirectives(directive, map) {
|
|
687
723
|
// the directive has been validated in the normalizer
|
|
@@ -705,6 +741,10 @@ class FederationFactory {
|
|
|
705
741
|
if (!this.persistedDirectives.has(directiveName)) {
|
|
706
742
|
continue;
|
|
707
743
|
}
|
|
744
|
+
if (directiveName == string_constants_1.DEPRECATED) {
|
|
745
|
+
this.upsertDeprecatedDirective(directive, container.deprecated);
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
708
748
|
if (directiveName === string_constants_1.TAG) {
|
|
709
749
|
this.mergeTagDirectives(directive, container.tags);
|
|
710
750
|
continue;
|
|
@@ -723,13 +763,13 @@ class FederationFactory {
|
|
|
723
763
|
}
|
|
724
764
|
return container;
|
|
725
765
|
}
|
|
726
|
-
|
|
766
|
+
isFieldResolvableByEntityAncestor(entityAncestors, fieldSubgraphs, parentTypeName) {
|
|
727
767
|
if (!this.graph.hasNode(parentTypeName)) {
|
|
728
768
|
return false;
|
|
729
769
|
}
|
|
730
770
|
for (const entityAncestorName of entityAncestors) {
|
|
731
771
|
const path = `${entityAncestorName}.${parentTypeName}`;
|
|
732
|
-
if (this.graphPaths.get(path)) {
|
|
772
|
+
if (entityAncestorName !== parentTypeName && this.graphPaths.get(path)) {
|
|
733
773
|
return true;
|
|
734
774
|
}
|
|
735
775
|
if (entityAncestorName === parentTypeName) {
|
|
@@ -745,11 +785,67 @@ class FederationFactory {
|
|
|
745
785
|
}
|
|
746
786
|
return false;
|
|
747
787
|
}
|
|
788
|
+
shouldEvaluateObjectLike(rootTypeFieldSubgraphs, parentTypeName) {
|
|
789
|
+
for (const subgraph of rootTypeFieldSubgraphs) {
|
|
790
|
+
const evaluatedObjectLikes = this.evaluatedObjectLikesBySubgraph.get(subgraph);
|
|
791
|
+
if (evaluatedObjectLikes && evaluatedObjectLikes.has(parentTypeName)) {
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
return true;
|
|
795
|
+
}
|
|
796
|
+
return false;
|
|
797
|
+
}
|
|
798
|
+
isFieldExternalInAllMutualSubgraphs(subgraphs, fieldContainer) {
|
|
799
|
+
const mutualSubgraphs = (0, utils_3.getAllMutualEntries)(subgraphs, fieldContainer.subgraphs);
|
|
800
|
+
if (mutualSubgraphs.size < 1) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
for (const mutualSubgraph of mutualSubgraphs) {
|
|
804
|
+
const isExternal = fieldContainer.subgraphsByExternal.get(mutualSubgraph);
|
|
805
|
+
if (isExternal) {
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
return true;
|
|
811
|
+
}
|
|
812
|
+
updateEvaluatedSubgraphOccurrences(rootTypeFieldSubgraphs, objectSubgraphs, entityAncestors, parentTypeName) {
|
|
813
|
+
const mutualSubgraphs = (0, utils_3.getAllMutualEntries)(rootTypeFieldSubgraphs, objectSubgraphs);
|
|
814
|
+
if (mutualSubgraphs.size > 0) {
|
|
815
|
+
for (const mutualSubgraph of mutualSubgraphs) {
|
|
816
|
+
const evaluatedObjects = this.evaluatedObjectLikesBySubgraph.get(mutualSubgraph);
|
|
817
|
+
if (evaluatedObjects) {
|
|
818
|
+
evaluatedObjects.add(parentTypeName);
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
this.evaluatedObjectLikesBySubgraph.set(mutualSubgraph, new Set([parentTypeName]));
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
for (const entityAncestor of entityAncestors) {
|
|
826
|
+
const entityContainer = (0, utils_3.getOrThrowError)(this.parents, entityAncestor, string_constants_1.PARENTS);
|
|
827
|
+
const mutualEntityAncestorRootTypeFieldSubgraphs = (0, utils_3.getAllMutualEntries)(rootTypeFieldSubgraphs, entityContainer.subgraphs);
|
|
828
|
+
const mutualEntityAncestorSubgraphs = (0, utils_3.getAllMutualEntries)(mutualEntityAncestorRootTypeFieldSubgraphs, objectSubgraphs);
|
|
829
|
+
for (const mutualSubgraph of mutualEntityAncestorSubgraphs) {
|
|
830
|
+
const objects = this.evaluatedObjectLikesBySubgraph.get(mutualSubgraph);
|
|
831
|
+
if (objects) {
|
|
832
|
+
objects.add(parentTypeName);
|
|
833
|
+
}
|
|
834
|
+
else {
|
|
835
|
+
this.evaluatedObjectLikesBySubgraph.set(mutualSubgraph, new Set([parentTypeName]));
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
748
840
|
evaluateResolvabilityOfObject(parentContainer, rootTypeFieldData, currentFieldPath, evaluatedObjectLikes, entityAncestors, isParentAbstract = false) {
|
|
749
841
|
const parentTypeName = parentContainer.node.name.value;
|
|
750
842
|
if (evaluatedObjectLikes.has(parentTypeName)) {
|
|
751
843
|
return;
|
|
752
844
|
}
|
|
845
|
+
if (!this.shouldEvaluateObjectLike(rootTypeFieldData.subgraphs, parentTypeName)) {
|
|
846
|
+
evaluatedObjectLikes.add(parentTypeName);
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
753
849
|
for (const [fieldName, fieldContainer] of parentContainer.fields) {
|
|
754
850
|
const fieldNamedTypeName = fieldContainer.namedTypeName;
|
|
755
851
|
if (string_constants_1.ROOT_TYPES.has(fieldNamedTypeName)) {
|
|
@@ -759,10 +855,16 @@ class FederationFactory {
|
|
|
759
855
|
if (evaluatedObjectLikes.has(fieldNamedTypeName)) {
|
|
760
856
|
continue;
|
|
761
857
|
}
|
|
762
|
-
|
|
858
|
+
if (this.isFieldExternalInAllMutualSubgraphs(rootTypeFieldData.subgraphs, fieldContainer)) {
|
|
859
|
+
continue;
|
|
860
|
+
}
|
|
861
|
+
this.updateEvaluatedSubgraphOccurrences(rootTypeFieldData.subgraphs, parentContainer.subgraphs, entityAncestors, parentTypeName);
|
|
862
|
+
evaluatedObjectLikes.add(parentTypeName);
|
|
863
|
+
const isFieldResolvable = (0, utils_3.doSetsHaveAnyOverlap)(rootTypeFieldData.subgraphs, fieldContainer.subgraphs)
|
|
864
|
+
|| this.isFieldResolvableByEntityAncestor(entityAncestors, fieldContainer.subgraphs, parentTypeName);
|
|
763
865
|
const newCurrentFieldPath = currentFieldPath + (isParentAbstract ? ' ' : '.') + fieldName;
|
|
764
866
|
const entity = this.entities.get(fieldNamedTypeName);
|
|
765
|
-
if (isFieldResolvable
|
|
867
|
+
if (isFieldResolvable) {
|
|
766
868
|
// The base scalars are not in this.parentMap
|
|
767
869
|
if (constants_1.BASE_SCALARS.has(fieldNamedTypeName)) {
|
|
768
870
|
continue;
|
|
@@ -774,12 +876,12 @@ class FederationFactory {
|
|
|
774
876
|
case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
|
|
775
877
|
continue;
|
|
776
878
|
case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
|
|
777
|
-
this.evaluateResolvabilityOfObject(childContainer, rootTypeFieldData, newCurrentFieldPath,
|
|
879
|
+
this.evaluateResolvabilityOfObject(childContainer, rootTypeFieldData, newCurrentFieldPath, evaluatedObjectLikes, entity ? [...entityAncestors, fieldNamedTypeName] : [...entityAncestors]);
|
|
778
880
|
continue;
|
|
779
881
|
case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
|
|
780
882
|
// intentional fallthrough
|
|
781
883
|
case graphql_1.Kind.UNION_TYPE_DEFINITION:
|
|
782
|
-
this.evaluateResolvabilityOfAbstractType(fieldNamedTypeName, childContainer.kind, rootTypeFieldData, newCurrentFieldPath,
|
|
884
|
+
this.evaluateResolvabilityOfAbstractType(fieldNamedTypeName, childContainer.kind, rootTypeFieldData, newCurrentFieldPath, evaluatedObjectLikes, entity ? [...entityAncestors, fieldNamedTypeName] : [...entityAncestors], fieldContainer.subgraphs);
|
|
783
885
|
continue;
|
|
784
886
|
default:
|
|
785
887
|
this.errors.push((0, errors_1.unexpectedObjectResponseType)(newCurrentFieldPath, (0, utils_3.kindToTypeString)(childContainer.kind)));
|
|
@@ -809,13 +911,14 @@ class FederationFactory {
|
|
|
809
911
|
}
|
|
810
912
|
}
|
|
811
913
|
}
|
|
812
|
-
evaluateResolvabilityOfAbstractType(
|
|
813
|
-
if (evaluatedObjectLikes.has(
|
|
914
|
+
evaluateResolvabilityOfAbstractType(abstractTypeName, abstractKind, rootTypeFieldData, currentFieldPath, evaluatedObjectLikes, entityAncestors, parentSubgraphs) {
|
|
915
|
+
if (evaluatedObjectLikes.has(abstractTypeName)) {
|
|
814
916
|
return;
|
|
815
917
|
}
|
|
816
|
-
|
|
918
|
+
evaluatedObjectLikes.add(abstractTypeName);
|
|
919
|
+
const concreteTypeNames = this.abstractToConcreteTypeNames.get(abstractTypeName);
|
|
817
920
|
if (!concreteTypeNames) {
|
|
818
|
-
(0, errors_1.noConcreteTypesForAbstractTypeError)((0, utils_3.kindToTypeString)(
|
|
921
|
+
(0, errors_1.noConcreteTypesForAbstractTypeError)((0, utils_3.kindToTypeString)(abstractKind), abstractTypeName);
|
|
819
922
|
return;
|
|
820
923
|
}
|
|
821
924
|
for (const concreteTypeName of concreteTypeNames) {
|
|
@@ -824,14 +927,14 @@ class FederationFactory {
|
|
|
824
927
|
}
|
|
825
928
|
const concreteParentContainer = (0, utils_3.getOrThrowError)(this.parents, concreteTypeName, string_constants_1.PARENTS);
|
|
826
929
|
if (concreteParentContainer.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION) {
|
|
827
|
-
|
|
828
|
-
continue;
|
|
930
|
+
throw (0, errors_1.unexpectedParentKindErrorMessage)(concreteTypeName, 'Object', (0, utils_3.kindToTypeString)(concreteParentContainer.kind));
|
|
829
931
|
}
|
|
932
|
+
// If the concrete type is unreachable through the abstract type, it is not an error
|
|
830
933
|
if (!(0, utils_3.doSetsHaveAnyOverlap)(concreteParentContainer.subgraphs, parentSubgraphs)) {
|
|
831
934
|
continue;
|
|
832
935
|
}
|
|
833
936
|
const entity = this.entities.get(concreteTypeName);
|
|
834
|
-
this.evaluateResolvabilityOfObject(concreteParentContainer, rootTypeFieldData, currentFieldPath + ` ... on ` + concreteTypeName,
|
|
937
|
+
this.evaluateResolvabilityOfObject(concreteParentContainer, rootTypeFieldData, currentFieldPath + ` ... on ` + concreteTypeName, evaluatedObjectLikes, entity ? [...entityAncestors, concreteTypeName] : [...entityAncestors], true);
|
|
835
938
|
}
|
|
836
939
|
}
|
|
837
940
|
federate() {
|
|
@@ -840,6 +943,7 @@ class FederationFactory {
|
|
|
840
943
|
for (const subgraph of this.subgraphs) {
|
|
841
944
|
this.isCurrentSubgraphVersionTwo = subgraph.isVersionTwo;
|
|
842
945
|
this.currentSubgraphName = subgraph.name;
|
|
946
|
+
this.keyFieldsByParentTypeName = subgraph.keyFieldsByParentTypeName;
|
|
843
947
|
(0, subgraph_1.walkSubgraphToFederate)(subgraph.definitions, factory);
|
|
844
948
|
}
|
|
845
949
|
const definitions = [];
|
|
@@ -900,7 +1004,7 @@ class FederationFactory {
|
|
|
900
1004
|
const values = [];
|
|
901
1005
|
const mergeMethod = this.getEnumMergeMethod(parentTypeName);
|
|
902
1006
|
for (const enumValueContainer of parentContainer.values.values()) {
|
|
903
|
-
(0, utils_1.
|
|
1007
|
+
(0, utils_1.pushPersistedDirectivesAndGetNode)(enumValueContainer);
|
|
904
1008
|
switch (mergeMethod) {
|
|
905
1009
|
case utils_2.MergeMethod.CONSISTENT:
|
|
906
1010
|
if (enumValueContainer.appearances < parentContainer.appearances) {
|
|
@@ -919,12 +1023,12 @@ class FederationFactory {
|
|
|
919
1023
|
}
|
|
920
1024
|
}
|
|
921
1025
|
parentContainer.node.values = values;
|
|
922
|
-
definitions.push((0, utils_1.
|
|
1026
|
+
definitions.push((0, utils_1.pushPersistedDirectivesAndGetNode)(parentContainer));
|
|
923
1027
|
break;
|
|
924
1028
|
case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
925
1029
|
const inputValues = [];
|
|
926
1030
|
for (const inputValueContainer of parentContainer.fields.values()) {
|
|
927
|
-
(0, utils_1.
|
|
1031
|
+
(0, utils_1.pushPersistedDirectivesAndGetNode)(inputValueContainer);
|
|
928
1032
|
if (parentContainer.appearances === inputValueContainer.appearances) {
|
|
929
1033
|
inputValues.push(inputValueContainer.node);
|
|
930
1034
|
}
|
|
@@ -934,7 +1038,7 @@ class FederationFactory {
|
|
|
934
1038
|
}
|
|
935
1039
|
}
|
|
936
1040
|
parentContainer.node.fields = inputValues;
|
|
937
|
-
definitions.push((0, utils_1.
|
|
1041
|
+
definitions.push((0, utils_1.pushPersistedDirectivesAndGetNode)(parentContainer));
|
|
938
1042
|
break;
|
|
939
1043
|
case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
|
|
940
1044
|
const interfaceFields = [];
|
|
@@ -942,7 +1046,7 @@ class FederationFactory {
|
|
|
942
1046
|
interfaceFields.push(this.getMergedFieldDefinitionNode(fieldContainer, parentTypeName));
|
|
943
1047
|
}
|
|
944
1048
|
parentContainer.node.fields = interfaceFields;
|
|
945
|
-
(0, utils_1.
|
|
1049
|
+
(0, utils_1.pushPersistedDirectivesAndGetNode)(parentContainer);
|
|
946
1050
|
// Interface implementations can only be evaluated after they've been fully merged
|
|
947
1051
|
if (parentContainer.interfaces.size > 0) {
|
|
948
1052
|
objectLikeContainersWithInterfaces.push(parentContainer);
|
|
@@ -957,7 +1061,7 @@ class FederationFactory {
|
|
|
957
1061
|
fields.push(this.getMergedFieldDefinitionNode(fieldContainer, parentTypeName));
|
|
958
1062
|
}
|
|
959
1063
|
parentContainer.node.fields = fields;
|
|
960
|
-
(0, utils_1.
|
|
1064
|
+
(0, utils_1.pushPersistedDirectivesAndGetNode)(parentContainer);
|
|
961
1065
|
// Interface implementations can only be evaluated after they've been fully merged
|
|
962
1066
|
if (parentContainer.interfaces.size > 0) {
|
|
963
1067
|
objectLikeContainersWithInterfaces.push(parentContainer);
|
|
@@ -967,7 +1071,7 @@ class FederationFactory {
|
|
|
967
1071
|
}
|
|
968
1072
|
break;
|
|
969
1073
|
case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
|
|
970
|
-
definitions.push((0, utils_1.
|
|
1074
|
+
definitions.push((0, utils_1.pushPersistedDirectivesAndGetNode)(parentContainer));
|
|
971
1075
|
break;
|
|
972
1076
|
case graphql_1.Kind.UNION_TYPE_DEFINITION:
|
|
973
1077
|
const types = [];
|
|
@@ -975,7 +1079,7 @@ class FederationFactory {
|
|
|
975
1079
|
types.push((0, utils_1.stringToNamedTypeNode)(memberName));
|
|
976
1080
|
}
|
|
977
1081
|
parentContainer.node.types = types;
|
|
978
|
-
definitions.push((0, utils_1.
|
|
1082
|
+
definitions.push((0, utils_1.pushPersistedDirectivesAndGetNode)(parentContainer));
|
|
979
1083
|
break;
|
|
980
1084
|
}
|
|
981
1085
|
}
|
|
@@ -995,11 +1099,18 @@ class FederationFactory {
|
|
|
995
1099
|
if (!rootTypeContainer || rootTypeContainer.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION) {
|
|
996
1100
|
continue;
|
|
997
1101
|
}
|
|
1102
|
+
// After evaluating all of a root type's fields, break and return if there are errors
|
|
1103
|
+
if (this.errors.length > 0) {
|
|
1104
|
+
break;
|
|
1105
|
+
}
|
|
998
1106
|
// If a root type field returns a Scalar or Enum, track it so that it is not evaluated it again
|
|
999
|
-
const
|
|
1107
|
+
const evaluatedRootScalarsAndEnums = new Set(constants_1.BASE_SCALARS);
|
|
1000
1108
|
for (const [rootTypeFieldName, rootTypeFieldContainer] of rootTypeContainer.fields) {
|
|
1001
1109
|
const rootTypeFieldNamedTypeName = rootTypeFieldContainer.namedTypeName;
|
|
1002
|
-
if (
|
|
1110
|
+
if (evaluatedRootScalarsAndEnums.has(rootTypeFieldNamedTypeName)) {
|
|
1111
|
+
continue;
|
|
1112
|
+
}
|
|
1113
|
+
if (!this.shouldEvaluateObjectLike(rootTypeFieldContainer.subgraphs, rootTypeFieldNamedTypeName)) {
|
|
1003
1114
|
continue;
|
|
1004
1115
|
}
|
|
1005
1116
|
const childContainer = (0, utils_3.getOrThrowError)(this.parents, rootTypeFieldNamedTypeName, string_constants_1.PARENTS);
|
|
@@ -1011,22 +1122,21 @@ class FederationFactory {
|
|
|
1011
1122
|
typeName: rootTypeName,
|
|
1012
1123
|
subgraphs: rootTypeFieldContainer.subgraphs,
|
|
1013
1124
|
};
|
|
1014
|
-
const evaluatedObjectLikes = new Set();
|
|
1015
1125
|
switch (childContainer.kind) {
|
|
1016
1126
|
case graphql_1.Kind.ENUM_TYPE_DEFINITION:
|
|
1017
1127
|
// intentional fallthrough
|
|
1018
1128
|
case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
|
|
1019
1129
|
// Root type fields whose response type is an Enums and Scalars will always be resolvable
|
|
1020
1130
|
// Consequently, subsequent checks can be skipped
|
|
1021
|
-
|
|
1131
|
+
evaluatedRootScalarsAndEnums.add(rootTypeFieldNamedTypeName);
|
|
1022
1132
|
continue;
|
|
1023
1133
|
case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
|
|
1024
|
-
this.evaluateResolvabilityOfObject(childContainer, rootTypeFieldData, fieldPath,
|
|
1134
|
+
this.evaluateResolvabilityOfObject(childContainer, rootTypeFieldData, fieldPath, new Set(), this.entities.has(rootTypeFieldNamedTypeName) ? [rootTypeFieldNamedTypeName] : []);
|
|
1025
1135
|
continue;
|
|
1026
1136
|
case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
|
|
1027
1137
|
// intentional fallthrough
|
|
1028
1138
|
case graphql_1.Kind.UNION_TYPE_DEFINITION:
|
|
1029
|
-
this.evaluateResolvabilityOfAbstractType(rootTypeFieldNamedTypeName, childContainer.kind, rootTypeFieldData, fieldPath,
|
|
1139
|
+
this.evaluateResolvabilityOfAbstractType(rootTypeFieldNamedTypeName, childContainer.kind, rootTypeFieldData, fieldPath, new Set(), this.entities.has(rootTypeFieldNamedTypeName) ? [rootTypeFieldNamedTypeName] : [], rootTypeFieldContainer.subgraphs);
|
|
1030
1140
|
continue;
|
|
1031
1141
|
default:
|
|
1032
1142
|
this.errors.push((0, errors_1.unexpectedObjectResponseType)(fieldPath, (0, utils_3.kindToTypeString)(childContainer.kind)));
|
|
@@ -1045,7 +1155,7 @@ class FederationFactory {
|
|
|
1045
1155
|
argumentConfigurations: this.argumentConfigurations,
|
|
1046
1156
|
federatedGraphAST: newAst,
|
|
1047
1157
|
federatedGraphSchema: (0, graphql_1.buildASTSchema)(newAst),
|
|
1048
|
-
}
|
|
1158
|
+
},
|
|
1049
1159
|
};
|
|
1050
1160
|
}
|
|
1051
1161
|
}
|
|
@@ -1079,6 +1189,7 @@ function federateSubgraphs(subgraphs) {
|
|
|
1079
1189
|
}
|
|
1080
1190
|
normalizedSubgraphs.push({
|
|
1081
1191
|
definitions: normalizationResult.subgraphAST,
|
|
1192
|
+
keyFieldsByParentTypeName: normalizationResult.keyFieldsByParentTypeName,
|
|
1082
1193
|
isVersionTwo: normalizationResult.isVersionTwo,
|
|
1083
1194
|
name,
|
|
1084
1195
|
operationTypes: normalizationResult.operationTypes,
|