Skip to content

Commit 8e02a49

Browse files
authored
Contract root types (#6770)
1 parent 84a4ae0 commit 8e02a49

File tree

4 files changed

+51
-22
lines changed

4 files changed

+51
-22
lines changed

.changeset/fifty-deers-shake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'hive': patch
3+
---
4+
5+
Adjust contract logic to allow removing mutation and subscription types

packages/services/schema/src/lib/federation-tag-extraction.spec.ts renamed to packages/services/schema/src/lib/__tests__/federation-tag-extraction.spec.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
applyTagFilterOnSubgraphs,
44
applyTagFilterToInaccessibleTransformOnSubgraphSchema,
55
type Federation2SubgraphDocumentNodeByTagsFilter,
6-
} from './federation-tag-extraction';
6+
} from '../federation-tag-extraction';
77

88
describe('applyTagFilterToInaccessibleTransformOnSubgraphSchema', () => {
99
describe('correct @inaccessible directive usage based on subgraph version/imports', () => {
@@ -370,6 +370,46 @@ describe('applyTagFilterToInaccessibleTransformOnSubgraphSchema', () => {
370370
}
371371
`);
372372
});
373+
374+
test('mutation object type is returned in "typesWithAllFieldsInaccessible" if all its fields are excluded', () => {
375+
const filter: Federation2SubgraphDocumentNodeByTagsFilter = {
376+
include: new Set(),
377+
exclude: new Set(['exclude']),
378+
};
379+
const sdl = parse(/* GraphQL */ `
380+
schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@tag"]) {
381+
query: Query
382+
}
383+
384+
type Query {
385+
field1: String!
386+
}
387+
388+
type Mutation {
389+
field1: ID! @tag(name: "exclude")
390+
}
391+
`);
392+
393+
const output = applyTagFilterToInaccessibleTransformOnSubgraphSchema(sdl, filter);
394+
395+
expect(output.typesWithAllFieldsInaccessible.entries().toArray()).toEqual([
396+
['Mutation', true],
397+
]);
398+
399+
expect(print(output.typeDefs)).toMatchInlineSnapshot(`
400+
schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@tag"]) {
401+
query: Query
402+
}
403+
404+
type Query {
405+
field1: String!
406+
}
407+
408+
type Mutation {
409+
field1: ID! @federation__inaccessible
410+
}
411+
`);
412+
});
373413
});
374414

375415
describe('interface type', () => {

packages/services/schema/src/lib/reachable-type-filter.spec.ts renamed to packages/services/schema/src/lib/__tests__/reachable-type-filter.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { parse, print } from 'graphql';
2-
import { addDirectiveOnTypes, getReachableTypes } from './reachable-type-filter';
2+
import { addDirectiveOnTypes, getReachableTypes } from '../reachable-type-filter';
33

44
describe('getReachableTypes', () => {
55
it('includes the query type', () => {

packages/services/schema/src/lib/federation-tag-extraction.ts

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -63,34 +63,20 @@ function hasIntersection<T>(a: Set<T>, b: Set<T>): boolean {
6363
return false;
6464
}
6565

66-
function getRootTypeNamesFromDocumentNode(document: DocumentNode) {
66+
function getRootQueryTypeNameFromDocumentNode(document: DocumentNode) {
6767
let queryName: string | null = 'Query';
68-
let mutationName: string | null = 'Mutation';
69-
let subscriptionName: string | null = 'Subscription';
7068

7169
for (const definition of document.definitions) {
7270
if (definition.kind === Kind.SCHEMA_DEFINITION || definition.kind === Kind.SCHEMA_EXTENSION) {
7371
for (const operationTypeDefinition of definition.operationTypes ?? []) {
7472
if (operationTypeDefinition.operation === 'query') {
7573
queryName = operationTypeDefinition.type.name.value;
7674
}
77-
if (operationTypeDefinition.operation === 'mutation') {
78-
mutationName = operationTypeDefinition.type.name.value;
79-
}
80-
if (operationTypeDefinition.operation === 'subscription') {
81-
subscriptionName = operationTypeDefinition.type.name.value;
82-
}
8375
}
8476
}
8577
}
8678

87-
const names = new Set<string>();
88-
89-
names.add(queryName);
90-
names.add(mutationName);
91-
names.add(subscriptionName);
92-
93-
return names;
79+
return queryName;
9480
}
9581

9682
type ObjectLikeNode =
@@ -127,7 +113,7 @@ export function applyTagFilterToInaccessibleTransformOnSubgraphSchema(
127113
tagDirectiveName,
128114
inaccessibleDirectiveName,
129115
);
130-
const rootTypeNames = getRootTypeNamesFromDocumentNode(documentNode);
116+
const rootQueryTypeName = getRootQueryTypeNameFromDocumentNode(documentNode);
131117

132118
const typesWithAllFieldsInaccessibleTracker = new Map<string, boolean>();
133119

@@ -355,9 +341,7 @@ export function applyTagFilterToInaccessibleTransformOnSubgraphSchema(
355341
[Kind.UNION_TYPE_DEFINITION]: scalarAndUnionHandler,
356342
});
357343

358-
for (const rootTypeName of rootTypeNames) {
359-
typesWithAllFieldsInaccessibleTracker.delete(rootTypeName);
360-
}
344+
typesWithAllFieldsInaccessibleTracker.delete(rootQueryTypeName);
361345

362346
return {
363347
typeDefs,

0 commit comments

Comments
 (0)