Skip to content

Commit d77a760

Browse files
authored
feat: expose subgraph defined directives (#2287)
1 parent a94ffee commit d77a760

File tree

7 files changed

+96
-61
lines changed

7 files changed

+96
-61
lines changed

composition-go/index.global.js

Lines changed: 48 additions & 48 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

composition/src/normalization/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Warning } from '../warnings/types';
2-
import { DocumentNode, GraphQLSchema, OperationTypeNode } from 'graphql';
2+
import { DirectiveDefinitionNode, DocumentNode, GraphQLSchema, OperationTypeNode } from 'graphql';
33
import { ConfigurationData } from '../router-configuration/types';
44
import {
55
AuthorizationData,
@@ -11,6 +11,7 @@ import {
1111
} from '../schema-building/types';
1212
import { Graph } from '../resolvability-graph/graph';
1313
import { InternalSubgraph } from '../subgraph/types';
14+
import { DirectiveName } from '../types/types';
1415

1516
export type NormalizationFailure = {
1617
errors: Array<Error>;
@@ -23,6 +24,7 @@ export type NormalizationSuccess = {
2324
concreteTypeNamesByAbstractTypeName: Map<string, Set<string>>;
2425
conditionalFieldDataByCoordinates: Map<string, ConditionalFieldData>;
2526
configurationDataByTypeName: Map<string, ConfigurationData>;
27+
directiveDefinitionByDirectiveName: Map<DirectiveName, DirectiveDefinitionNode>;
2628
entityInterfaces: Map<string, EntityInterfaceSubgraphData>;
2729
entityDataByTypeName: Map<string, EntityData>;
2830
fieldCoordsByNamedTypeName: Map<string, Set<string>>;

composition/src/subgraph/types.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { DocumentNode, GraphQLSchema, OperationTypeNode } from 'graphql';
1+
import { DirectiveDefinitionNode, DocumentNode, GraphQLSchema, OperationTypeNode } from 'graphql';
22
import { ConfigurationData } from '../router-configuration/types';
33
import {
44
ConditionalFieldData,
55
EntityInterfaceSubgraphData,
66
ParentDefinitionData,
77
PersistedDirectiveDefinitionData,
88
} from '../schema-building/types';
9-
import { TypeName } from '../types/types';
9+
import { DirectiveName, TypeName } from '../types/types';
1010

1111
export type Subgraph = {
1212
definitions: DocumentNode;
@@ -16,6 +16,7 @@ export type Subgraph = {
1616

1717
export type SubgraphConfig = {
1818
configurationDataByTypeName: Map<TypeName, ConfigurationData>;
19+
directiveDefinitionByDirectiveName: Map<DirectiveName, DirectiveDefinitionNode>;
1920
isVersionTwo: boolean;
2021
parentDefinitionDataByTypeName: Map<TypeName, ParentDefinitionData>;
2122
schema: GraphQLSchema;
@@ -25,14 +26,15 @@ export type InternalSubgraph = {
2526
conditionalFieldDataByCoordinates: Map<string, ConditionalFieldData>;
2627
configurationDataByTypeName: Map<string, ConfigurationData>;
2728
definitions: DocumentNode;
29+
directiveDefinitionByDirectiveName: Map<DirectiveName, DirectiveDefinitionNode>;
2830
entityInterfaces: Map<string, EntityInterfaceSubgraphData>;
2931
isVersionTwo: boolean;
3032
keyFieldNamesByParentTypeName: Map<string, Set<string>>;
3133
name: string;
3234
operationTypes: Map<string, OperationTypeNode>;
3335
overriddenFieldNamesByParentTypeName: Map<string, Set<string>>;
3436
parentDefinitionDataByTypeName: Map<string, ParentDefinitionData>;
35-
persistedDirectiveDefinitionDataByDirectiveName: Map<string, PersistedDirectiveDefinitionData>;
37+
persistedDirectiveDefinitionDataByDirectiveName: Map<DirectiveName, PersistedDirectiveDefinitionData>;
3638
schema: GraphQLSchema;
3739
url: string;
3840
};

composition/src/v1/federation/federation-factory.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2821,6 +2821,7 @@ export class FederationFactory {
28212821
for (const subgraph of this.internalSubgraphBySubgraphName.values()) {
28222822
subgraphConfigBySubgraphName.set(subgraph.name, {
28232823
configurationDataByTypeName: subgraph.configurationDataByTypeName,
2824+
directiveDefinitionByDirectiveName: subgraph.directiveDefinitionByDirectiveName,
28242825
isVersionTwo: subgraph.isVersionTwo,
28252826
parentDefinitionDataByTypeName: subgraph.parentDefinitionDataByTypeName,
28262827
schema: subgraph.schema,
@@ -3112,6 +3113,7 @@ export class FederationFactory {
31123113
for (const subgraph of this.internalSubgraphBySubgraphName.values()) {
31133114
subgraphConfigBySubgraphName.set(subgraph.name, {
31143115
configurationDataByTypeName: subgraph.configurationDataByTypeName,
3116+
directiveDefinitionByDirectiveName: subgraph.directiveDefinitionByDirectiveName,
31153117
isVersionTwo: subgraph.isVersionTwo,
31163118
parentDefinitionDataByTypeName: subgraph.parentDefinitionDataByTypeName,
31173119
schema: subgraph.schema,

composition/src/v1/normalization/normalization-factory.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ import {
376376
} from './types';
377377
import { newConfigurationData, newFieldSetConditionData } from '../../router-configuration/utils';
378378
import { ImplementationErrors, InvalidFieldImplementation } from '../../utils/types';
379-
import { FieldName, SubgraphName } from '../../types/types';
379+
import { DirectiveName, FieldName, SubgraphName } from '../../types/types';
380380
import { HandleFieldInheritableDirectivesParams, ValidateOneOfDirectiveParams } from './params';
381381

382382
export function normalizeSubgraphFromString(subgraphSDL: string, noLocation = true): NormalizationResult {
@@ -405,7 +405,7 @@ export class NormalizationFactory {
405405
configurationDataByTypeName = new Map<string, ConfigurationData>();
406406
customDirectiveDefinitions = new Map<string, DirectiveDefinitionNode>();
407407
definedDirectiveNames = new Set<string>();
408-
directiveDefinitionByDirectiveName = new Map<string, DirectiveDefinitionNode>();
408+
directiveDefinitionByDirectiveName = new Map<DirectiveName, DirectiveDefinitionNode>();
409409
directiveDefinitionDataByDirectiveName = initializeDirectiveDefinitionDatas();
410410
doesParentRequireFetchReasons = false;
411411
edfsDirectiveReferences = new Set<string>();
@@ -418,7 +418,6 @@ export class NormalizationFactory {
418418
invalidConfigureDescriptionNodeDatas: Array<NodeData> = [];
419419
invalidORScopesCoords = new Set<string>();
420420
invalidRepeatedDirectiveNameByCoords = new Map<string, Set<string>>();
421-
isCurrentParentExtension = false;
422421
isParentObjectExternal = false;
423422
isParentObjectShareable = false;
424423
isSubgraphEventDrivenGraph = false;
@@ -427,7 +426,6 @@ export class NormalizationFactory {
427426
lastParentNodeKind: Kind = Kind.NULL;
428427
lastChildNodeKind: Kind = Kind.NULL;
429428
parentTypeNamesWithAuthDirectives = new Set<string>();
430-
keyFieldSetDataByTypeName = new Map<string, KeyFieldSetData>();
431429
keyFieldSetsByEntityTypeNameByFieldCoords = new Map<string, Map<string, Set<string>>>();
432430
keyFieldNamesByParentTypeName = new Map<string, Set<string>>();
433431
fieldCoordsByNamedTypeName = new Map<string, Set<string>>();
@@ -3756,6 +3754,7 @@ export class NormalizationFactory {
37563754
concreteTypeNamesByAbstractTypeName: this.concreteTypeNamesByAbstractTypeName,
37573755
conditionalFieldDataByCoordinates: this.conditionalFieldDataByCoords,
37583756
configurationDataByTypeName: this.configurationDataByTypeName,
3757+
directiveDefinitionByDirectiveName: this.directiveDefinitionByDirectiveName,
37593758
entityDataByTypeName: this.entityDataByTypeName,
37603759
entityInterfaces: this.entityInterfaceDataByTypeName,
37613760
fieldCoordsByNamedTypeName: this.fieldCoordsByNamedTypeName,
@@ -3858,6 +3857,7 @@ export function batchNormalize(subgraphs: Subgraph[]): BatchNormalizationResult
38583857
conditionalFieldDataByCoordinates: normalizationResult.conditionalFieldDataByCoordinates,
38593858
configurationDataByTypeName: normalizationResult.configurationDataByTypeName,
38603859
definitions: normalizationResult.subgraphAST,
3860+
directiveDefinitionByDirectiveName: normalizationResult.directiveDefinitionByDirectiveName,
38613861
entityInterfaces: normalizationResult.entityInterfaces,
38623862
isVersionTwo: normalizationResult.isVersionTwo,
38633863
keyFieldNamesByParentTypeName: normalizationResult.keyFieldNamesByParentTypeName,

composition/src/v1/utils/constants.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ import {
103103
URL_LOWER,
104104
VALUES,
105105
} from '../../utils/string-constants';
106+
import { DirectiveName } from '../../types/types';
106107

107108
export const REQUIRED_STRING_TYPE_NODE: TypeNode = {
108109
kind: Kind.NON_NULL_TYPE,
@@ -477,7 +478,7 @@ export const EDFS_REDIS_SUBSCRIBE_DEFINITION: DirectiveDefinitionNode = {
477478
repeatable: false,
478479
};
479480

480-
export const BASE_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME = new Map<string, DirectiveDefinitionNode>([
481+
export const BASE_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME = new Map<DirectiveName, DirectiveDefinitionNode>([
481482
[DEPRECATED, DEPRECATED_DEFINITION],
482483
[EXTENDS, EXTENDS_DEFINITION],
483484
[EXTERNAL, EXTERNAL_DEFINITION],
@@ -495,7 +496,7 @@ export const BASE_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME = new Map<string, Direc
495496
[TAG, TAG_DEFINITION],
496497
]);
497498

498-
export const ALL_IN_BUILT_DIRECTIVE_NAMES = new Set<string>([
499+
export const ALL_IN_BUILT_DIRECTIVE_NAMES = new Set<DirectiveName>([
499500
AUTHENTICATED,
500501
COMPOSE_DIRECTIVE,
501502
CONFIGURE_DESCRIPTION,
@@ -860,7 +861,7 @@ export const SUBSCRIPTION_FIELD_CONDITION_DEFINITION: InputObjectTypeDefinitionN
860861
name: stringToNameNode(SUBSCRIPTION_FIELD_CONDITION),
861862
};
862863

863-
export const V2_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME = new Map<string, DirectiveDefinitionNode>([
864+
export const V2_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME = new Map<DirectiveName, DirectiveDefinitionNode>([
864865
[AUTHENTICATED, AUTHENTICATED_DEFINITION],
865866
[COMPOSE_DIRECTIVE, COMPOSE_DIRECTIVE_DEFINITION],
866867
[INACCESSIBLE, INACCESSIBLE_DEFINITION],

composition/tests/v1/federation-factory.test.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
BASE_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME,
23
incompatibleParentTypeMergeError,
34
INPUT_OBJECT,
45
InputObjectDefinitionData,
@@ -13,6 +14,7 @@ import {
1314
ScalarDefinitionData,
1415
Subgraph,
1516
SubgraphName,
17+
V2_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME,
1618
} from '../../src';
1719
import { describe, expect, test } from 'vitest';
1820
import {
@@ -522,8 +524,11 @@ describe('FederationFactory tests', () => {
522524
});
523525

524526
test('that subgraphs are federated #2', () => {
525-
const result = federateSubgraphsSuccess([subgraphA, subgraphB], ROUTER_COMPATIBILITY_VERSION_ONE);
526-
expect(schemaToSortedNormalizedString(result.federatedGraphSchema)).toBe(
527+
const { federatedGraphSchema, subgraphConfigBySubgraphName } = federateSubgraphsSuccess(
528+
[subgraphA, subgraphB],
529+
ROUTER_COMPATIBILITY_VERSION_ONE,
530+
);
531+
expect(schemaToSortedNormalizedString(federatedGraphSchema)).toBe(
527532
normalizeString(
528533
versionTwoRouterDefinitions +
529534
`
@@ -554,6 +559,27 @@ describe('FederationFactory tests', () => {
554559
`,
555560
),
556561
);
562+
563+
const subgraphAConfig = subgraphConfigBySubgraphName.get(subgraphA.name);
564+
expect(subgraphAConfig).toBeDefined();
565+
566+
const subgraphBConfig = subgraphConfigBySubgraphName.get(subgraphB.name);
567+
expect(subgraphBConfig).toBeDefined();
568+
569+
expect(subgraphAConfig!.directiveDefinitionByDirectiveName).toHaveLength(22);
570+
expect(subgraphBConfig!.directiveDefinitionByDirectiveName).toHaveLength(23);
571+
572+
for (const directiveName of BASE_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME.keys()) {
573+
expect(subgraphAConfig!.directiveDefinitionByDirectiveName.has(directiveName));
574+
expect(subgraphBConfig!.directiveDefinitionByDirectiveName.has(directiveName));
575+
}
576+
577+
for (const directiveName of V2_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME.keys()) {
578+
expect(subgraphAConfig!.directiveDefinitionByDirectiveName.has(directiveName));
579+
expect(subgraphBConfig!.directiveDefinitionByDirectiveName.has(directiveName));
580+
}
581+
582+
expect(subgraphBConfig!.directiveDefinitionByDirectiveName.has('a'));
557583
});
558584

559585
test('that extension orphans return an error', () => {
@@ -1120,6 +1146,8 @@ const subgraphB: Subgraph = {
11201146
name: 'subgraph-b',
11211147
url: '',
11221148
definitions: parse(`
1149+
directive @a on FIELD_DEFINITION | OBJECT
1150+
11231151
type Query {
11241152
trainer: [Trainer!]!
11251153
pokemon: [Pokemon!]! @shareable

0 commit comments

Comments
 (0)