@apollo/federation-internals 2.8.3 → 2.9.0-beta.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/dist/argumentCompositionStrategies.d.ts +17 -0
- package/dist/argumentCompositionStrategies.d.ts.map +1 -1
- package/dist/argumentCompositionStrategies.js +38 -0
- package/dist/argumentCompositionStrategies.js.map +1 -1
- package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
- package/dist/extractSubgraphsFromSupergraph.js +59 -8
- package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
- package/dist/federation.d.ts +5 -2
- package/dist/federation.d.ts.map +1 -1
- package/dist/federation.js +16 -2
- package/dist/federation.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/operations.d.ts +3 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +26 -5
- package/dist/operations.js.map +1 -1
- package/dist/schemaUpgrader.d.ts.map +1 -1
- package/dist/schemaUpgrader.js +50 -31
- package/dist/schemaUpgrader.js.map +1 -1
- package/dist/specs/coreSpec.d.ts +1 -0
- package/dist/specs/coreSpec.d.ts.map +1 -1
- package/dist/specs/coreSpec.js +18 -0
- package/dist/specs/coreSpec.js.map +1 -1
- package/dist/specs/costSpec.d.ts +17 -0
- package/dist/specs/costSpec.d.ts.map +1 -0
- package/dist/specs/costSpec.js +49 -0
- package/dist/specs/costSpec.js.map +1 -0
- package/dist/specs/federationSpec.d.ts +3 -1
- package/dist/specs/federationSpec.d.ts.map +1 -1
- package/dist/specs/federationSpec.js +8 -1
- package/dist/specs/federationSpec.js.map +1 -1
- package/dist/supergraphs.d.ts.map +1 -1
- package/dist/supergraphs.js +1 -0
- package/dist/supergraphs.js.map +1 -1
- package/package.json +1 -1
- package/src/argumentCompositionStrategies.ts +37 -0
- package/src/extractSubgraphsFromSupergraph.ts +94 -7
- package/src/federation.ts +21 -2
- package/src/index.ts +1 -0
- package/src/operations.ts +41 -4
- package/src/schemaUpgrader.ts +55 -31
- package/src/specs/coreSpec.ts +21 -0
- package/src/specs/costSpec.ts +60 -0
- package/src/specs/federationSpec.ts +9 -1
- package/src/supergraphs.ts +1 -0
package/dist/supergraphs.js
CHANGED
|
@@ -39,6 +39,7 @@ exports.ROUTER_SUPPORTED_SUPERGRAPH_FEATURES = new Set([
|
|
|
39
39
|
'https://specs.apollo.dev/policy/v0.1',
|
|
40
40
|
'https://specs.apollo.dev/source/v0.1',
|
|
41
41
|
'https://specs.apollo.dev/context/v0.1',
|
|
42
|
+
'https://specs.apollo.dev/cost/v0.1',
|
|
42
43
|
]);
|
|
43
44
|
const coreVersionZeroDotOneUrl = coreSpec_1.FeatureUrl.parse('https://specs.apollo.dev/core/v0.1');
|
|
44
45
|
function checkFeatureSupport(coreFeatures, supportedFeatures) {
|
package/dist/supergraphs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supergraphs.js","sourceRoot":"","sources":["../src/supergraphs.ts"],"names":[],"mappings":";;;AACA,+CAAkF;AAClF,+CAAiE;AACjE,+CAAmF;AACnF,+CAAgE;AAChE,qFAA8H;AAC9H,mCAAiC;AAGpB,QAAA,qCAAqC,GAAG,IAAI,GAAG,CAAC;IAC3D,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;IACpC,mCAAmC;IACnC,mCAAmC;IACnC,mCAAmC;IACnC,4CAA4C;IAC5C,4CAA4C;CAC7C,CAAC,CAAC;AAEU,QAAA,oCAAoC,GAAG,IAAI,GAAG,CAAC;IAC1D,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;IACpC,mCAAmC;IACnC,mCAAmC;IACnC,mCAAmC;IACnC,4CAA4C;IAC5C,4CAA4C;IAC5C,6CAA6C;IAC7C,8CAA8C;IAC9C,sCAAsC;IACtC,sCAAsC;IACtC,uCAAuC;
|
|
1
|
+
{"version":3,"file":"supergraphs.js","sourceRoot":"","sources":["../src/supergraphs.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -59,4 +59,41 @@ export const ARGUMENT_COMPOSITION_STRATEGIES = {
|
|
|
59
59
|
return acc.concat(newValues);
|
|
60
60
|
}, []),
|
|
61
61
|
},
|
|
62
|
+
NULLABLE_AND: {
|
|
63
|
+
name: 'NULLABLE_AND',
|
|
64
|
+
isTypeSupported: supportFixedTypes((schema: Schema) => [schema.booleanType()]),
|
|
65
|
+
mergeValues: (values: (boolean | null | undefined)[]) => values.reduce((acc, next) => {
|
|
66
|
+
if (acc === null || acc === undefined) {
|
|
67
|
+
return next;
|
|
68
|
+
} else if (next === null || next === undefined) {
|
|
69
|
+
return acc;
|
|
70
|
+
} else {
|
|
71
|
+
return acc && next;
|
|
72
|
+
}
|
|
73
|
+
}, undefined),
|
|
74
|
+
},
|
|
75
|
+
NULLABLE_MAX: {
|
|
76
|
+
name: 'NULLABLE_MAX',
|
|
77
|
+
isTypeSupported: supportFixedTypes((schema: Schema) => [schema.intType(), new NonNullType(schema.intType())]),
|
|
78
|
+
mergeValues: (values: any[]) => values.reduce((a: any, b: any) => a !== undefined && b !== undefined ? Math.max(a, b) : a ?? b, undefined),
|
|
79
|
+
},
|
|
80
|
+
NULLABLE_UNION: {
|
|
81
|
+
name: 'NULLABLE_UNION',
|
|
82
|
+
isTypeSupported: (_: Schema, type: InputType) => ({ valid: isListType(type) }),
|
|
83
|
+
mergeValues: (values: any[]) => {
|
|
84
|
+
if (values.every((v) => v === undefined)) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const combined = new Set();
|
|
89
|
+
for (const subgraphValues of values) {
|
|
90
|
+
if (Array.isArray(subgraphValues)) {
|
|
91
|
+
for (const value of subgraphValues) {
|
|
92
|
+
combined.add(value);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return Array.from(combined);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
62
99
|
}
|
|
@@ -40,7 +40,7 @@ import { parseSelectionSet } from "./operations";
|
|
|
40
40
|
import fs from 'fs';
|
|
41
41
|
import path from 'path';
|
|
42
42
|
import { validateStringContainsBoolean } from "./utils";
|
|
43
|
-
import { CONTEXT_VERSIONS, ContextSpecDefinition, DirectiveDefinition, errorCauses, isFederationDirectiveDefinedInSchema, printErrors } from ".";
|
|
43
|
+
import { CONTEXT_VERSIONS, ContextSpecDefinition, DirectiveDefinition, FeatureUrl, FederationDirectiveName, SchemaElement, errorCauses, isFederationDirectiveDefinedInSchema, printErrors } from ".";
|
|
44
44
|
|
|
45
45
|
function filteredTypes(
|
|
46
46
|
supergraph: Schema,
|
|
@@ -224,11 +224,13 @@ export function extractSubgraphsFromSupergraph(supergraph: Schema, validateExtra
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
const types = filteredTypes(supergraph, joinSpec, coreFeatures.coreDefinition);
|
|
227
|
+
const originalDirectiveNames = getApolloDirectiveNames(supergraph);
|
|
227
228
|
const args: ExtractArguments = {
|
|
228
229
|
supergraph,
|
|
229
230
|
subgraphs,
|
|
230
231
|
joinSpec,
|
|
231
232
|
filteredTypes: types,
|
|
233
|
+
originalDirectiveNames,
|
|
232
234
|
getSubgraph,
|
|
233
235
|
getSubgraphEnumValue,
|
|
234
236
|
};
|
|
@@ -292,6 +294,7 @@ type ExtractArguments = {
|
|
|
292
294
|
subgraphs: Subgraphs,
|
|
293
295
|
joinSpec: JoinSpecDefinition,
|
|
294
296
|
filteredTypes: NamedType[],
|
|
297
|
+
originalDirectiveNames: Record<string, string>,
|
|
295
298
|
getSubgraph: (application: Directive<any, { graph?: string }>) => Subgraph | undefined,
|
|
296
299
|
getSubgraphEnumValue: (subgraphName: string) => string
|
|
297
300
|
}
|
|
@@ -348,7 +351,8 @@ function addAllEmptySubgraphTypes(args: ExtractArguments): TypesInfo {
|
|
|
348
351
|
for (const application of typeApplications) {
|
|
349
352
|
const subgraph = getSubgraph(application);
|
|
350
353
|
assert(subgraph, () => `Should have found the subgraph for ${application}`);
|
|
351
|
-
subgraph.schema.addType(newNamedType(type.kind, type.name));
|
|
354
|
+
const subgraphType = subgraph.schema.addType(newNamedType(type.kind, type.name));
|
|
355
|
+
propagateDemandControlDirectives(type, subgraphType, subgraph, args.originalDirectiveNames);
|
|
352
356
|
}
|
|
353
357
|
break;
|
|
354
358
|
}
|
|
@@ -434,6 +438,8 @@ function extractObjOrItfContent(args: ExtractArguments, info: TypeInfo<ObjectTyp
|
|
|
434
438
|
const implementsDirective = args.joinSpec.implementsDirective(args.supergraph);
|
|
435
439
|
assert(implementsDirective, '@join__implements should existing for a fed2 supergraph');
|
|
436
440
|
|
|
441
|
+
const originalDirectiveNames = args.originalDirectiveNames;
|
|
442
|
+
|
|
437
443
|
for (const { type, subgraphsInfo } of info) {
|
|
438
444
|
const implementsApplications = type.appliedDirectivesOf(implementsDirective);
|
|
439
445
|
for (const application of implementsApplications) {
|
|
@@ -444,13 +450,17 @@ function extractObjOrItfContent(args: ExtractArguments, info: TypeInfo<ObjectTyp
|
|
|
444
450
|
subgraphInfo.type.addImplementedInterface(args.interface);
|
|
445
451
|
}
|
|
446
452
|
|
|
453
|
+
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) {
|
|
454
|
+
propagateDemandControlDirectives(type, subgraphType, subgraph, args.originalDirectiveNames);
|
|
455
|
+
}
|
|
456
|
+
|
|
447
457
|
for (const field of type.fields()) {
|
|
448
458
|
const fieldApplications = field.appliedDirectivesOf(fieldDirective);
|
|
449
459
|
if (fieldApplications.length === 0) {
|
|
450
460
|
// In fed2 subgraph, no @join__field means that the field is in all the subgraphs in which the type is.
|
|
451
461
|
const isShareable = isObjectType(type) && subgraphsInfo.size > 1;
|
|
452
462
|
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) {
|
|
453
|
-
addSubgraphField({ field, type: subgraphType, subgraph, isShareable });
|
|
463
|
+
addSubgraphField({ field, type: subgraphType, subgraph, isShareable, originalDirectiveNames });
|
|
454
464
|
}
|
|
455
465
|
} else {
|
|
456
466
|
const isShareable = isObjectType(type)
|
|
@@ -468,15 +478,58 @@ function extractObjOrItfContent(args: ExtractArguments, info: TypeInfo<ObjectTyp
|
|
|
468
478
|
}
|
|
469
479
|
|
|
470
480
|
const { type: subgraphType, subgraph } = subgraphsInfo.get(joinFieldArgs.graph)!;
|
|
471
|
-
addSubgraphField({ field, type: subgraphType, subgraph, isShareable, joinFieldArgs });
|
|
481
|
+
addSubgraphField({ field, type: subgraphType, subgraph, isShareable, joinFieldArgs, originalDirectiveNames });
|
|
472
482
|
}
|
|
473
483
|
}
|
|
474
484
|
}
|
|
475
485
|
}
|
|
476
486
|
}
|
|
477
487
|
|
|
488
|
+
/**
|
|
489
|
+
* Builds a map of original name to new name for Apollo feature directives. This is
|
|
490
|
+
* used to handle cases where a directive is renamed via an import statement. For
|
|
491
|
+
* example, importing a directive with a custom name like
|
|
492
|
+
* ```graphql
|
|
493
|
+
* @link(url: "https://specs.apollo.dev/cost/v0.1", import: [{ name: "@cost", as: "@renamedCost" }])
|
|
494
|
+
* ```
|
|
495
|
+
* results in a map entry of `cost -> renamedCost` with the `@` prefix removed.
|
|
496
|
+
*
|
|
497
|
+
* If the directive is imported under its default name, that also results in an entry. So,
|
|
498
|
+
* ```graphql
|
|
499
|
+
* @link(url: "https://specs.apollo.dev/cost/v0.1", import: ["@cost"])
|
|
500
|
+
* ```
|
|
501
|
+
* results in a map entry of `cost -> cost`. This duals as a way to check if a directive
|
|
502
|
+
* is included in the supergraph schema.
|
|
503
|
+
*
|
|
504
|
+
* **Important:** This map does _not_ include directives imported from identities other
|
|
505
|
+
* than `specs.apollo.dev`. This helps us avoid extracting directives to subgraphs
|
|
506
|
+
* when a custom directive's name conflicts with that of a default one.
|
|
507
|
+
*/
|
|
508
|
+
function getApolloDirectiveNames(supergraph: Schema): Record<string, string> {
|
|
509
|
+
const originalDirectiveNames: Record<string, string> = {};
|
|
510
|
+
for (const linkDirective of supergraph.schemaDefinition.appliedDirectivesOf("link")) {
|
|
511
|
+
if (linkDirective.arguments().url && linkDirective.arguments().import) {
|
|
512
|
+
const url = FeatureUrl.maybeParse(linkDirective.arguments().url);
|
|
513
|
+
if (!url?.identity.includes("specs.apollo.dev")) {
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
for (const importedDirective of linkDirective.arguments().import) {
|
|
518
|
+
if (importedDirective.name && importedDirective.as) {
|
|
519
|
+
originalDirectiveNames[importedDirective.name.replace('@', '')] = importedDirective.as.replace('@', '');
|
|
520
|
+
} else if (typeof importedDirective === 'string') {
|
|
521
|
+
originalDirectiveNames[importedDirective.replace('@', '')] = importedDirective.replace('@', '');
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return originalDirectiveNames;
|
|
528
|
+
}
|
|
529
|
+
|
|
478
530
|
function extractInputObjContent(args: ExtractArguments, info: TypeInfo<InputObjectType>[]) {
|
|
479
531
|
const fieldDirective = args.joinSpec.fieldDirective(args.supergraph);
|
|
532
|
+
const originalDirectiveNames = args.originalDirectiveNames;
|
|
480
533
|
|
|
481
534
|
for (const { type, subgraphsInfo } of info) {
|
|
482
535
|
for (const field of type.fields()) {
|
|
@@ -484,7 +537,7 @@ function extractInputObjContent(args: ExtractArguments, info: TypeInfo<InputObje
|
|
|
484
537
|
if (fieldApplications.length === 0) {
|
|
485
538
|
// In fed2 subgraph, no @join__field means that the field is in all the subgraphs in which the type is.
|
|
486
539
|
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) {
|
|
487
|
-
addSubgraphInputField({ field, type: subgraphType, subgraph });
|
|
540
|
+
addSubgraphInputField({ field, type: subgraphType, subgraph, originalDirectiveNames });
|
|
488
541
|
}
|
|
489
542
|
} else {
|
|
490
543
|
for (const application of fieldApplications) {
|
|
@@ -496,7 +549,7 @@ function extractInputObjContent(args: ExtractArguments, info: TypeInfo<InputObje
|
|
|
496
549
|
}
|
|
497
550
|
|
|
498
551
|
const { type: subgraphType, subgraph } = subgraphsInfo.get(args.graph)!;
|
|
499
|
-
addSubgraphInputField({ field, type: subgraphType, subgraph, joinFieldArgs: args});
|
|
552
|
+
addSubgraphInputField({ field, type: subgraphType, subgraph, joinFieldArgs: args, originalDirectiveNames });
|
|
500
553
|
}
|
|
501
554
|
}
|
|
502
555
|
}
|
|
@@ -506,8 +559,13 @@ function extractInputObjContent(args: ExtractArguments, info: TypeInfo<InputObje
|
|
|
506
559
|
function extractEnumTypeContent(args: ExtractArguments, info: TypeInfo<EnumType>[]) {
|
|
507
560
|
// This was added in join 0.3, so it can genuinely be undefined.
|
|
508
561
|
const enumValueDirective = args.joinSpec.enumValueDirective(args.supergraph);
|
|
562
|
+
const originalDirectiveNames = args.originalDirectiveNames;
|
|
509
563
|
|
|
510
564
|
for (const { type, subgraphsInfo } of info) {
|
|
565
|
+
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) {
|
|
566
|
+
propagateDemandControlDirectives(type, subgraphType, subgraph, originalDirectiveNames);
|
|
567
|
+
}
|
|
568
|
+
|
|
511
569
|
for (const value of type.values) {
|
|
512
570
|
const enumValueApplications = enumValueDirective ? value.appliedDirectivesOf(enumValueDirective) : [];
|
|
513
571
|
if (enumValueApplications.length === 0) {
|
|
@@ -620,6 +678,24 @@ function maybeDumpSubgraphSchema(subgraph: Subgraph): string {
|
|
|
620
678
|
}
|
|
621
679
|
}
|
|
622
680
|
|
|
681
|
+
function propagateDemandControlDirectives(source: SchemaElement<any, any>, dest: SchemaElement<any, any>, subgraph: Subgraph, originalDirectiveNames?: Record<string, string>) {
|
|
682
|
+
const costDirectiveName = originalDirectiveNames?.[FederationDirectiveName.COST];
|
|
683
|
+
if (costDirectiveName) {
|
|
684
|
+
const costDirective = source.appliedDirectivesOf(costDirectiveName).pop();
|
|
685
|
+
if (costDirective) {
|
|
686
|
+
dest.applyDirective(subgraph.metadata().costDirective().name, costDirective.arguments());
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const listSizeDirectiveName = originalDirectiveNames?.[FederationDirectiveName.LIST_SIZE];
|
|
691
|
+
if (listSizeDirectiveName) {
|
|
692
|
+
const listSizeDirective = source.appliedDirectivesOf(listSizeDirectiveName).pop();
|
|
693
|
+
if (listSizeDirective) {
|
|
694
|
+
dest.applyDirective(subgraph.metadata().listSizeDirective().name, listSizeDirective.arguments());
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
623
699
|
function errorToString(e: any,): string {
|
|
624
700
|
const causes = errorCauses(e);
|
|
625
701
|
return causes ? printErrors(causes) : String(e);
|
|
@@ -631,12 +707,14 @@ function addSubgraphField({
|
|
|
631
707
|
subgraph,
|
|
632
708
|
isShareable,
|
|
633
709
|
joinFieldArgs,
|
|
710
|
+
originalDirectiveNames,
|
|
634
711
|
}: {
|
|
635
712
|
field: FieldDefinition<ObjectType | InterfaceType>,
|
|
636
713
|
type: ObjectType | InterfaceType,
|
|
637
714
|
subgraph: Subgraph,
|
|
638
715
|
isShareable: boolean,
|
|
639
716
|
joinFieldArgs?: JoinFieldDirectiveArguments,
|
|
717
|
+
originalDirectiveNames?: Record<string, string>,
|
|
640
718
|
}): FieldDefinition<ObjectType | InterfaceType> {
|
|
641
719
|
const copiedFieldType = joinFieldArgs?.type
|
|
642
720
|
? decodeType(joinFieldArgs.type, subgraph.schema, subgraph.name)
|
|
@@ -644,7 +722,8 @@ function addSubgraphField({
|
|
|
644
722
|
|
|
645
723
|
const subgraphField = type.addField(field.name, copiedFieldType);
|
|
646
724
|
for (const arg of field.arguments()) {
|
|
647
|
-
subgraphField.addArgument(arg.name, copyType(arg.type!, subgraph.schema, subgraph.name), arg.defaultValue);
|
|
725
|
+
const argDef = subgraphField.addArgument(arg.name, copyType(arg.type!, subgraph.schema, subgraph.name), arg.defaultValue);
|
|
726
|
+
propagateDemandControlDirectives(arg, argDef, subgraph, originalDirectiveNames)
|
|
648
727
|
}
|
|
649
728
|
if (joinFieldArgs?.requires) {
|
|
650
729
|
subgraphField.applyDirective(subgraph.metadata().requiresDirective(), {'fields': joinFieldArgs.requires});
|
|
@@ -689,6 +768,9 @@ function addSubgraphField({
|
|
|
689
768
|
if (isShareable && !external && !usedOverridden) {
|
|
690
769
|
subgraphField.applyDirective(subgraph.metadata().shareableDirective());
|
|
691
770
|
}
|
|
771
|
+
|
|
772
|
+
propagateDemandControlDirectives(field, subgraphField, subgraph, originalDirectiveNames);
|
|
773
|
+
|
|
692
774
|
return subgraphField;
|
|
693
775
|
}
|
|
694
776
|
|
|
@@ -697,11 +779,13 @@ function addSubgraphInputField({
|
|
|
697
779
|
type,
|
|
698
780
|
subgraph,
|
|
699
781
|
joinFieldArgs,
|
|
782
|
+
originalDirectiveNames,
|
|
700
783
|
}: {
|
|
701
784
|
field: InputFieldDefinition,
|
|
702
785
|
type: InputObjectType,
|
|
703
786
|
subgraph: Subgraph,
|
|
704
787
|
joinFieldArgs?: JoinFieldDirectiveArguments,
|
|
788
|
+
originalDirectiveNames?: Record<string, string>
|
|
705
789
|
}): InputFieldDefinition {
|
|
706
790
|
const copiedType = joinFieldArgs?.type
|
|
707
791
|
? decodeType(joinFieldArgs?.type, subgraph.schema, subgraph.name)
|
|
@@ -709,6 +793,9 @@ function addSubgraphInputField({
|
|
|
709
793
|
|
|
710
794
|
const inputField = type.addField(field.name, copiedType);
|
|
711
795
|
inputField.defaultValue = field.defaultValue
|
|
796
|
+
|
|
797
|
+
propagateDemandControlDirectives(field, inputField, subgraph, originalDirectiveNames);
|
|
798
|
+
|
|
712
799
|
return inputField;
|
|
713
800
|
}
|
|
714
801
|
|
package/src/federation.ts
CHANGED
|
@@ -100,6 +100,7 @@ import {
|
|
|
100
100
|
SourceFieldDirectiveArgs,
|
|
101
101
|
SourceTypeDirectiveArgs,
|
|
102
102
|
} from "./specs/sourceSpec";
|
|
103
|
+
import { CostDirectiveArguments, ListSizeDirectiveArguments } from "./specs/costSpec";
|
|
103
104
|
|
|
104
105
|
const linkSpec = LINK_VERSIONS.latest();
|
|
105
106
|
const tagSpec = TAG_VERSIONS.latest();
|
|
@@ -1275,6 +1276,14 @@ export class FederationMetadata {
|
|
|
1275
1276
|
return this.getPost20FederationDirective(FederationDirectiveName.CONTEXT);
|
|
1276
1277
|
}
|
|
1277
1278
|
|
|
1279
|
+
costDirective(): Post20FederationDirectiveDefinition<CostDirectiveArguments> {
|
|
1280
|
+
return this.getPost20FederationDirective(FederationDirectiveName.COST);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
listSizeDirective(): Post20FederationDirectiveDefinition<ListSizeDirectiveArguments> {
|
|
1284
|
+
return this.getPost20FederationDirective(FederationDirectiveName.LIST_SIZE);
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1278
1287
|
allFederationDirectives(): DirectiveDefinition[] {
|
|
1279
1288
|
const baseDirectives: DirectiveDefinition[] = [
|
|
1280
1289
|
this.keyDirective(),
|
|
@@ -1338,6 +1347,16 @@ export class FederationMetadata {
|
|
|
1338
1347
|
baseDirectives.push(fromContextDirective);
|
|
1339
1348
|
}
|
|
1340
1349
|
|
|
1350
|
+
const costDirective = this.costDirective();
|
|
1351
|
+
if (isFederationDirectiveDefinedInSchema(costDirective)) {
|
|
1352
|
+
baseDirectives.push(costDirective);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
const listSizeDirective = this.listSizeDirective();
|
|
1356
|
+
if (isFederationDirectiveDefinedInSchema(listSizeDirective)) {
|
|
1357
|
+
baseDirectives.push(listSizeDirective);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1341
1360
|
return baseDirectives;
|
|
1342
1361
|
}
|
|
1343
1362
|
|
|
@@ -1831,9 +1850,9 @@ export function setSchemaAsFed2Subgraph(schema: Schema, useLatest: boolean = fal
|
|
|
1831
1850
|
|
|
1832
1851
|
// This is the full @link declaration as added by `asFed2SubgraphDocument`. It's here primarily for uses by tests that print and match
|
|
1833
1852
|
// subgraph schema to avoid having to update 20+ tests every time we use a new directive or the order of import changes ...
|
|
1834
|
-
export const FEDERATION2_LINK_WITH_FULL_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.
|
|
1853
|
+
export const FEDERATION2_LINK_WITH_FULL_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject", "@authenticated", "@requiresScopes", "@policy", "@sourceAPI", "@sourceType", "@sourceField", "@context", "@fromContext", "@cost", "@listSize"])';
|
|
1835
1854
|
// This is the full @link declaration that is added when upgrading fed v1 subgraphs to v2 version. It should only be used by tests.
|
|
1836
|
-
export const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.
|
|
1855
|
+
export const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"])';
|
|
1837
1856
|
|
|
1838
1857
|
// This is the federation @link for tests that go through the SchemaUpgrader.
|
|
1839
1858
|
export const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS_UPGRADED = '@link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"])';
|
package/src/index.ts
CHANGED
package/src/operations.ts
CHANGED
|
@@ -56,6 +56,8 @@ import { assert, mapKeys, mapValues, MapWithCachedArrays, MultiMap, SetMultiMap
|
|
|
56
56
|
import { argumentsEquals, argumentsFromAST, isValidValue, valueToAST, valueToString } from "./values";
|
|
57
57
|
import { v1 as uuidv1 } from 'uuid';
|
|
58
58
|
|
|
59
|
+
export const DEFAULT_MIN_USAGES_TO_OPTIMIZE = 2;
|
|
60
|
+
|
|
59
61
|
function validate(condition: any, message: () => string, sourceAST?: ASTNode): asserts condition {
|
|
60
62
|
if (!condition) {
|
|
61
63
|
throw ERRORS.INVALID_GRAPHQL.err(message(), { nodes: sourceAST });
|
|
@@ -934,25 +936,55 @@ export class Operation extends DirectiveTargetElement<Operation> {
|
|
|
934
936
|
this.appliedDirectives,
|
|
935
937
|
);
|
|
936
938
|
}
|
|
939
|
+
|
|
940
|
+
private collectUndefinedVariablesFromFragments(fragments: NamedFragments): Variable[] {
|
|
941
|
+
const collector = new VariableCollector();
|
|
942
|
+
for (const namedFragment of fragments.definitions()) {
|
|
943
|
+
namedFragment.selectionSet.usedVariables().forEach(v => {
|
|
944
|
+
if (!this.variableDefinitions.definition(v)) {
|
|
945
|
+
collector.add(v);
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
return collector.variables();
|
|
950
|
+
}
|
|
937
951
|
|
|
938
952
|
// Returns a copy of this operation with the provided updated selection set and fragments.
|
|
939
|
-
private withUpdatedSelectionSetAndFragments(
|
|
953
|
+
private withUpdatedSelectionSetAndFragments(
|
|
954
|
+
newSelectionSet: SelectionSet,
|
|
955
|
+
newFragments: NamedFragments | undefined,
|
|
956
|
+
allAvailableVariables?: VariableDefinitions,
|
|
957
|
+
): Operation {
|
|
940
958
|
if (this.selectionSet === newSelectionSet && newFragments === this.fragments) {
|
|
941
959
|
return this;
|
|
942
960
|
}
|
|
961
|
+
|
|
962
|
+
let newVariableDefinitions = this.variableDefinitions;
|
|
963
|
+
if (allAvailableVariables && newFragments) {
|
|
964
|
+
const undefinedVariables = this.collectUndefinedVariablesFromFragments(newFragments);
|
|
965
|
+
if (undefinedVariables.length > 0) {
|
|
966
|
+
newVariableDefinitions = new VariableDefinitions();
|
|
967
|
+
newVariableDefinitions.addAll(this.variableDefinitions);
|
|
968
|
+
newVariableDefinitions.addAll(allAvailableVariables.filter(undefinedVariables));
|
|
969
|
+
}
|
|
970
|
+
}
|
|
943
971
|
|
|
944
972
|
return new Operation(
|
|
945
973
|
this.schema(),
|
|
946
974
|
this.rootKind,
|
|
947
975
|
newSelectionSet,
|
|
948
|
-
|
|
976
|
+
newVariableDefinitions,
|
|
949
977
|
newFragments,
|
|
950
978
|
this.name,
|
|
951
979
|
this.appliedDirectives,
|
|
952
980
|
);
|
|
953
981
|
}
|
|
954
982
|
|
|
955
|
-
optimize(
|
|
983
|
+
optimize(
|
|
984
|
+
fragments?: NamedFragments,
|
|
985
|
+
minUsagesToOptimize: number = DEFAULT_MIN_USAGES_TO_OPTIMIZE,
|
|
986
|
+
allAvailableVariables?: VariableDefinitions,
|
|
987
|
+
): Operation {
|
|
956
988
|
assert(minUsagesToOptimize >= 1, `Expected 'minUsagesToOptimize' to be at least 1, but got ${minUsagesToOptimize}`)
|
|
957
989
|
if (!fragments || fragments.isEmpty()) {
|
|
958
990
|
return this;
|
|
@@ -1001,11 +1033,16 @@ export class Operation extends DirectiveTargetElement<Operation> {
|
|
|
1001
1033
|
}
|
|
1002
1034
|
}
|
|
1003
1035
|
|
|
1004
|
-
return this.withUpdatedSelectionSetAndFragments(
|
|
1036
|
+
return this.withUpdatedSelectionSetAndFragments(
|
|
1037
|
+
optimizedSelection,
|
|
1038
|
+
finalFragments ?? undefined,
|
|
1039
|
+
allAvailableVariables,
|
|
1040
|
+
);
|
|
1005
1041
|
}
|
|
1006
1042
|
|
|
1007
1043
|
generateQueryFragments(): Operation {
|
|
1008
1044
|
const [minimizedSelectionSet, fragments] = this.selectionSet.minimizeSelectionSet();
|
|
1045
|
+
|
|
1009
1046
|
return new Operation(
|
|
1010
1047
|
this.schema(),
|
|
1011
1048
|
this.rootKind,
|
package/src/schemaUpgrader.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
Directive,
|
|
12
12
|
Extension,
|
|
13
13
|
FieldDefinition,
|
|
14
|
+
InterfaceType,
|
|
14
15
|
isCompositeType,
|
|
15
16
|
isInterfaceType,
|
|
16
17
|
isObjectType,
|
|
@@ -230,6 +231,28 @@ export function upgradeSubgraphsIfNecessary(inputs: Subgraphs): UpgradeResult {
|
|
|
230
231
|
const subgraphs = new Subgraphs();
|
|
231
232
|
let errors: GraphQLError[] = [];
|
|
232
233
|
const subgraphsUsingInterfaceObject = [];
|
|
234
|
+
|
|
235
|
+
// build a data structure to help us do computation only once
|
|
236
|
+
const objectTypeMap = new Map<string, Map<string, [ObjectType | InterfaceType, FederationMetadata]>>();
|
|
237
|
+
for (const subgraph of inputs.values()) {
|
|
238
|
+
for (const t of subgraph.schema.objectTypes()) {
|
|
239
|
+
let entry = objectTypeMap.get(t.name);
|
|
240
|
+
if (!entry) {
|
|
241
|
+
entry = new Map();
|
|
242
|
+
objectTypeMap.set(t.name, entry);
|
|
243
|
+
}
|
|
244
|
+
entry.set(subgraph.name, [t, subgraph.metadata()]);
|
|
245
|
+
}
|
|
246
|
+
for (const t of subgraph.schema.interfaceTypes()) {
|
|
247
|
+
let entry = objectTypeMap.get(t.name);
|
|
248
|
+
if (!entry) {
|
|
249
|
+
entry = new Map();
|
|
250
|
+
objectTypeMap.set(t.name, entry);
|
|
251
|
+
}
|
|
252
|
+
entry.set(subgraph.name, [t, subgraph.metadata()]);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
233
256
|
for (const subgraph of inputs.values()) {
|
|
234
257
|
if (subgraph.isFed2Subgraph()) {
|
|
235
258
|
subgraphs.add(subgraph);
|
|
@@ -237,8 +260,7 @@ export function upgradeSubgraphsIfNecessary(inputs: Subgraphs): UpgradeResult {
|
|
|
237
260
|
subgraphsUsingInterfaceObject.push(subgraph.name);
|
|
238
261
|
}
|
|
239
262
|
} else {
|
|
240
|
-
const
|
|
241
|
-
const res = new SchemaUpgrader(subgraph, otherSubgraphs).upgrade();
|
|
263
|
+
const res = new SchemaUpgrader(subgraph, inputs.values(), objectTypeMap).upgrade();
|
|
242
264
|
if (res.errors) {
|
|
243
265
|
errors = errors.concat(res.errors);
|
|
244
266
|
} else {
|
|
@@ -291,16 +313,6 @@ function isRootTypeExtension(type: NamedType): boolean {
|
|
|
291
313
|
&& (type.hasAppliedDirective(metadata.extendsDirective()) || (type.hasExtensionElements() && !type.hasNonExtensionElements()));
|
|
292
314
|
}
|
|
293
315
|
|
|
294
|
-
function resolvesField(subgraph: Subgraph, field: FieldDefinition<ObjectType>): boolean {
|
|
295
|
-
const metadata = subgraph.metadata();
|
|
296
|
-
const t = subgraph.schema.type(field.parent.name);
|
|
297
|
-
if (!t || !isObjectType(t)) {
|
|
298
|
-
return false;
|
|
299
|
-
}
|
|
300
|
-
const f = t.field(field.name);
|
|
301
|
-
return !!f && (!metadata.isFieldExternal(f) || metadata.isFieldPartiallyExternal(f));
|
|
302
|
-
}
|
|
303
|
-
|
|
304
316
|
function getField(schema: Schema, typeName: string, fieldName: string): FieldDefinition<CompositeType> | undefined {
|
|
305
317
|
const type = schema.type(typeName);
|
|
306
318
|
return type && isCompositeType(type) ? type.field(fieldName) : undefined;
|
|
@@ -313,7 +325,7 @@ class SchemaUpgrader {
|
|
|
313
325
|
private readonly metadata: FederationMetadata;
|
|
314
326
|
private readonly errors: GraphQLError[] = [];
|
|
315
327
|
|
|
316
|
-
constructor(private readonly originalSubgraph: Subgraph, private readonly
|
|
328
|
+
constructor(private readonly originalSubgraph: Subgraph, private readonly allSubgraphs: readonly Subgraph[], private readonly objectTypeMap: Map<string, Map<string, [ObjectType | InterfaceType, FederationMetadata]>>) {
|
|
317
329
|
// Note that as we clone the original schema, the 'sourceAST' values in the elements of the new schema will be those of the original schema
|
|
318
330
|
// and those won't be updated as we modify the schema to make it fed2-enabled. This is _important_ for us here as this is what ensures that
|
|
319
331
|
// later merge errors "AST" nodes ends up pointing to the original schema, the one that make sense to the user.
|
|
@@ -380,8 +392,9 @@ class SchemaUpgrader {
|
|
|
380
392
|
}
|
|
381
393
|
|
|
382
394
|
const extensionAST = firstOf<Extension<any>>(type.extensions().values())?.sourceAST;
|
|
383
|
-
|
|
384
|
-
|
|
395
|
+
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name)!.entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name);
|
|
396
|
+
for (let i = 0; i < typeInOtherSubgraphs.length; i += 1) {
|
|
397
|
+
const otherType = typeInOtherSubgraphs[i][1][0];
|
|
385
398
|
if (otherType && otherType.hasNonExtensionElements()) {
|
|
386
399
|
return;
|
|
387
400
|
}
|
|
@@ -589,13 +602,12 @@ class SchemaUpgrader {
|
|
|
589
602
|
// case territory in the first place, so this is probably good enough (that is, there is
|
|
590
603
|
// customer schema for which what we do here matter but not that I know of for which it's
|
|
591
604
|
// not good enough).
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const keysInOther = typeInOther.appliedDirectivesOf(other.metadata().keyDirective());
|
|
605
|
+
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name)!.entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name);
|
|
606
|
+
|
|
607
|
+
for (const [otherSubgraphName, v] of typeInOtherSubgraphs) {
|
|
608
|
+
const [typeInOther, metadata] = v;
|
|
609
|
+
assert(isCompositeType(typeInOther), () => `Type ${type} is of kind ${type.kind} in ${this.subgraph.name} but ${typeInOther.kind} in ${otherSubgraphName}`);
|
|
610
|
+
const keysInOther = typeInOther.appliedDirectivesOf(metadata.keyDirective());
|
|
599
611
|
if (keysInOther.length === 0) {
|
|
600
612
|
continue;
|
|
601
613
|
}
|
|
@@ -702,7 +714,10 @@ class SchemaUpgrader {
|
|
|
702
714
|
// - to every "value type" (in the fed1 sense of non-root type and non-entity) if it is used in any other subgraphs
|
|
703
715
|
// - to any (non-external) field of an entity/root-type that is not a key field and if another subgraphs resolve it (fully or partially through @provides)
|
|
704
716
|
for (const type of this.schema.objectTypes()) {
|
|
705
|
-
if
|
|
717
|
+
if(type.isSubscriptionRootType()) {
|
|
718
|
+
continue;
|
|
719
|
+
}
|
|
720
|
+
if (type.hasAppliedDirective(keyDirective) || (type.isRootType())) {
|
|
706
721
|
for (const field of type.fields()) {
|
|
707
722
|
// To know if the field is a "key" field which doesn't need shareable, we rely on whether the field is shareable in the original
|
|
708
723
|
// schema (the fed1 version), because as fed1 schema will have no @shareable, the key fields will effectively be the only field
|
|
@@ -710,17 +725,26 @@ class SchemaUpgrader {
|
|
|
710
725
|
if (originalMetadata.isFieldShareable(field)) {
|
|
711
726
|
continue;
|
|
712
727
|
}
|
|
713
|
-
|
|
714
|
-
|
|
728
|
+
|
|
729
|
+
const entries = Array.from(this.objectTypeMap.get(type.name)!.entries());
|
|
730
|
+
const typeInOtherSubgraphs = entries.filter(([subgraphName, v]) => {
|
|
731
|
+
if (subgraphName === this.subgraph.name) {
|
|
732
|
+
return false;
|
|
733
|
+
}
|
|
734
|
+
const f = v[0].field(field.name);
|
|
735
|
+
return !!f && (!v[1].isFieldExternal(f) || v[1].isFieldPartiallyExternal(f));
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
if (typeInOtherSubgraphs.length > 0 && !field.hasAppliedDirective(shareableDirective)) {
|
|
715
739
|
field.applyDirective(shareableDirective);
|
|
716
|
-
this.addChange(new ShareableFieldAddition(field.coordinate,
|
|
740
|
+
this.addChange(new ShareableFieldAddition(field.coordinate, typeInOtherSubgraphs.map(([s]) => s)));
|
|
717
741
|
}
|
|
718
742
|
}
|
|
719
743
|
} else {
|
|
720
|
-
const
|
|
721
|
-
if (
|
|
744
|
+
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name)!.entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name);
|
|
745
|
+
if (typeInOtherSubgraphs.length > 0 && !type.hasAppliedDirective(shareableDirective)) {
|
|
722
746
|
type.applyDirective(shareableDirective);
|
|
723
|
-
this.addChange(new ShareableTypeAddition(type.coordinate,
|
|
747
|
+
this.addChange(new ShareableTypeAddition(type.coordinate, typeInOtherSubgraphs.map(([s]) => s)));
|
|
724
748
|
}
|
|
725
749
|
}
|
|
726
750
|
}
|
|
@@ -739,8 +763,8 @@ class SchemaUpgrader {
|
|
|
739
763
|
continue;
|
|
740
764
|
}
|
|
741
765
|
if (this.external(element)) {
|
|
742
|
-
const tagIsUsedInOtherDefinition = this.
|
|
743
|
-
.map((s) => getField(s.schema, element.parent.name, element.name))
|
|
766
|
+
const tagIsUsedInOtherDefinition = this.allSubgraphs
|
|
767
|
+
.map((s) => s.name === this.originalSubgraph.name ? undefined : getField(s.schema, element.parent.name, element.name))
|
|
744
768
|
.filter((f) => !(f && f.hasAppliedDirective('external')))
|
|
745
769
|
.some((f) => f && f.appliedDirectivesOf('tag').some((d) => valueEquals(application.arguments(), d.arguments())));
|
|
746
770
|
|
package/src/specs/coreSpec.ts
CHANGED
|
@@ -552,6 +552,27 @@ export class CoreSpecDefinition extends FeatureDefinition {
|
|
|
552
552
|
return feature.addElementsToSchema(schema);
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
+
applyFeatureAsLink(schema: Schema, feature: FeatureDefinition, purpose?: CorePurpose, imports?: CoreImport[]): GraphQLError[] {
|
|
556
|
+
const existing = schema.schemaDefinition.appliedDirectivesOf(linkDirectiveDefaultName).find((link) => link.arguments().url === feature.toString());
|
|
557
|
+
if (existing) {
|
|
558
|
+
existing.remove();
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const coreDirective = this.coreDirective(schema);
|
|
562
|
+
const args: LinkDirectiveArgs = {
|
|
563
|
+
url: feature.toString(),
|
|
564
|
+
import: (existing?.arguments().import ?? []).concat(imports?.map((i) => i.as ? { name: `@${i.name}`, as: `@${i.as}` } : `@${i.name}`)),
|
|
565
|
+
feature: undefined,
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
if (this.supportPurposes() && purpose) {
|
|
569
|
+
args.for = purpose;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
schema.schemaDefinition.applyDirective(coreDirective, args);
|
|
573
|
+
return feature.addElementsToSchema(schema);
|
|
574
|
+
}
|
|
575
|
+
|
|
555
576
|
extractFeatureUrl(args: CoreOrLinkDirectiveArgs): FeatureUrl {
|
|
556
577
|
return FeatureUrl.parse(args[this.urlArgName()]!);
|
|
557
578
|
}
|