Skip to content

Commit 6f2756b

Browse files
committed
Fix operation type changes
1 parent 6b83adb commit 6f2756b

File tree

6 files changed

+131
-41
lines changed

6 files changed

+131
-41
lines changed

packages/core/__tests__/diff/object.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('object', () => {
3232
`);
3333

3434
const changes = await diff(a, b);
35-
expect(changes).toHaveLength(4);
35+
expect(changes).toHaveLength(5);
3636

3737
const change = findFirstChangeByPath(changes, 'B');
3838
const mutation = findFirstChangeByPath(changes, 'Mutation');

packages/core/__tests__/diff/schema.test.ts

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -829,9 +829,45 @@ test('adding root type should not be breaking', async () => {
829829
`);
830830

831831
const changes = await diff(schemaA, schemaB);
832-
expect(changes).toHaveLength(2);
833-
834-
const subscription = findFirstChangeByPath(changes, 'Subscription');
835-
expect(subscription).toBeDefined();
836-
expect(subscription!.criticality.level).toEqual(CriticalityLevel.NonBreaking);
832+
expect(changes).toMatchInlineSnapshot(`
833+
[
834+
{
835+
"criticality": {
836+
"level": "BREAKING",
837+
},
838+
"message": "Schema subscription root has changed from 'unknown' to 'Subscription'",
839+
"meta": {
840+
"newSubscriptionTypeName": "Subscription",
841+
"oldSubscriptionTypeName": "unknown",
842+
},
843+
"type": "SCHEMA_SUBSCRIPTION_TYPE_CHANGED",
844+
},
845+
{
846+
"criticality": {
847+
"level": "NON_BREAKING",
848+
},
849+
"message": "Type 'Subscription' was added",
850+
"meta": {
851+
"addedTypeKind": "ObjectTypeDefinition",
852+
"addedTypeName": "Subscription",
853+
},
854+
"path": "Subscription",
855+
"type": "TYPE_ADDED",
856+
},
857+
{
858+
"criticality": {
859+
"level": "NON_BREAKING",
860+
},
861+
"message": "Field 'onFoo' was added to object type 'Subscription'",
862+
"meta": {
863+
"addedFieldName": "onFoo",
864+
"addedFieldReturnType": "String",
865+
"typeName": "Subscription",
866+
"typeType": "object type",
867+
},
868+
"path": "Subscription.onFoo",
869+
"type": "FIELD_ADDED",
870+
},
871+
]
872+
`);
837873
});

packages/core/src/diff/schema.ts

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -98,26 +98,15 @@ export function diffSchema(oldSchema: GraphQLSchema, newSchema: GraphQLSchema):
9898
}
9999

100100
function changesInSchema(oldSchema: GraphQLSchema, newSchema: GraphQLSchema, addChange: AddChange) {
101-
const defaultNames = {
102-
query: 'Query',
103-
mutation: 'Mutation',
104-
subscription: 'Subscription',
105-
};
106101
const oldRoot = {
107-
query: (oldSchema.getQueryType() || ({} as GraphQLObjectType)).name ?? defaultNames.query,
108-
mutation:
109-
(oldSchema.getMutationType() || ({} as GraphQLObjectType)).name ?? defaultNames.mutation,
110-
subscription:
111-
(oldSchema.getSubscriptionType() || ({} as GraphQLObjectType)).name ??
112-
defaultNames.subscription,
102+
query: (oldSchema.getQueryType() || ({} as GraphQLObjectType)).name,
103+
mutation: (oldSchema.getMutationType() || ({} as GraphQLObjectType)).name,
104+
subscription: (oldSchema.getSubscriptionType() || ({} as GraphQLObjectType)).name,
113105
};
114106
const newRoot = {
115-
query: (newSchema.getQueryType() || ({} as GraphQLObjectType)).name ?? defaultNames.query,
116-
mutation:
117-
(newSchema.getMutationType() || ({} as GraphQLObjectType)).name ?? defaultNames.mutation,
118-
subscription:
119-
(newSchema.getSubscriptionType() || ({} as GraphQLObjectType)).name ??
120-
defaultNames.subscription,
107+
query: (newSchema.getQueryType() || ({} as GraphQLObjectType)).name,
108+
mutation: (newSchema.getMutationType() || ({} as GraphQLObjectType)).name,
109+
subscription: (newSchema.getSubscriptionType() || ({} as GraphQLObjectType)).name,
121110
};
122111

123112
if (isNotEqual(oldRoot.query, newRoot.query)) {

packages/patch/src/__tests__/types.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,24 @@ describe('enum', () => {
3131
await expectPatchToMatch(before, after);
3232
});
3333

34+
test('typeAdded Mutation', async () => {
35+
const before = /* GraphQL */ `
36+
type Query {
37+
foo: String
38+
}
39+
`;
40+
const after = /* GraphQL */ `
41+
type Query {
42+
foo: String
43+
}
44+
45+
type Mutation {
46+
dooFoo: String
47+
}
48+
`;
49+
await expectPatchToMatch(before, after);
50+
});
51+
3452
test('typeDescriptionChanged: Added', async () => {
3553
const before = /* GraphQL */ `
3654
enum Status {

packages/patch/src/errors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ export class DeletedAttributeNotFoundError extends NoopError {
154154
export class ChangedCoordinateNotFoundError extends Error {
155155
constructor(expectedKind: Kind, expectedNameOrValue: string | undefined) {
156156
super(
157-
`The "${expectedKind}" ${expectedNameOrValue ? `"${expectedNameOrValue}"` : ''}does not exist.`,
157+
`The "${expectedKind}" ${expectedNameOrValue ? `"${expectedNameOrValue}" ` : ''}does not exist.`,
158158
);
159159
}
160160
}

packages/patch/src/patches/schema.ts

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable unicorn/no-negated-condition */
2-
import { Kind, NameNode, OperationTypeNode } from 'graphql';
2+
import { Kind, NameNode, OperationTypeDefinitionNode, OperationTypeNode } from 'graphql';
33
import type { Change, ChangeType } from '@graphql-inspector/core';
4-
import { ChangedCoordinateNotFoundError, handleError, ValueMismatchError } from '../errors.js';
4+
import { handleError, ValueMismatchError } from '../errors.js';
55
import { nameNode } from '../node-templates.js';
66
import { PatchConfig, SchemaNode } from '../types.js';
77

@@ -15,11 +15,28 @@ export function schemaMutationTypeChanged(
1515
({ operation }) => operation === OperationTypeNode.MUTATION,
1616
);
1717
if (!mutation) {
18-
handleError(
19-
change,
20-
new ChangedCoordinateNotFoundError(Kind.SCHEMA_DEFINITION, 'mutation'),
21-
config,
22-
);
18+
if (change.meta.oldMutationTypeName !== 'unknown') {
19+
handleError(
20+
change,
21+
new ValueMismatchError(
22+
Kind.SCHEMA_DEFINITION,
23+
change.meta.oldMutationTypeName,
24+
'unknown',
25+
),
26+
config,
27+
);
28+
}
29+
(schemaNode.operationTypes as OperationTypeDefinitionNode[]) = [
30+
...(schemaNode.operationTypes ?? []),
31+
{
32+
kind: Kind.OPERATION_TYPE_DEFINITION,
33+
operation: OperationTypeNode.MUTATION,
34+
type: {
35+
kind: Kind.NAMED_TYPE,
36+
name: nameNode(change.meta.newMutationTypeName),
37+
},
38+
},
39+
];
2340
} else {
2441
if (mutation.type.name.value !== change.meta.oldMutationTypeName) {
2542
handleError(
@@ -47,11 +64,24 @@ export function schemaQueryTypeChanged(
4764
({ operation }) => operation === OperationTypeNode.MUTATION,
4865
);
4966
if (!query) {
50-
handleError(
51-
change,
52-
new ChangedCoordinateNotFoundError(Kind.SCHEMA_DEFINITION, 'query'),
53-
config,
54-
);
67+
if (change.meta.oldQueryTypeName !== 'unknown') {
68+
handleError(
69+
change,
70+
new ValueMismatchError(Kind.SCHEMA_DEFINITION, change.meta.oldQueryTypeName, 'unknown'),
71+
config,
72+
);
73+
}
74+
(schemaNode.operationTypes as OperationTypeDefinitionNode[]) = [
75+
...(schemaNode.operationTypes ?? []),
76+
{
77+
kind: Kind.OPERATION_TYPE_DEFINITION,
78+
operation: OperationTypeNode.QUERY,
79+
type: {
80+
kind: Kind.NAMED_TYPE,
81+
name: nameNode(change.meta.newQueryTypeName),
82+
},
83+
},
84+
];
5585
} else {
5686
if (query.type.name.value !== change.meta.oldQueryTypeName) {
5787
handleError(
@@ -79,11 +109,28 @@ export function schemaSubscriptionTypeChanged(
79109
({ operation }) => operation === OperationTypeNode.SUBSCRIPTION,
80110
);
81111
if (!sub) {
82-
handleError(
83-
change,
84-
new ChangedCoordinateNotFoundError(Kind.SCHEMA_DEFINITION, 'subscription'),
85-
config,
86-
);
112+
if (change.meta.oldSubscriptionTypeName !== 'unknown') {
113+
handleError(
114+
change,
115+
new ValueMismatchError(
116+
Kind.SCHEMA_DEFINITION,
117+
change.meta.oldSubscriptionTypeName,
118+
'unknown',
119+
),
120+
config,
121+
);
122+
}
123+
(schemaNode.operationTypes as OperationTypeDefinitionNode[]) = [
124+
...(schemaNode.operationTypes ?? []),
125+
{
126+
kind: Kind.OPERATION_TYPE_DEFINITION,
127+
operation: OperationTypeNode.QUERY,
128+
type: {
129+
kind: Kind.NAMED_TYPE,
130+
name: nameNode(change.meta.newSubscriptionTypeName),
131+
},
132+
},
133+
];
87134
} else {
88135
if (sub.type.name.value !== change.meta.oldSubscriptionTypeName) {
89136
handleError(

0 commit comments

Comments
 (0)