Skip to content

Commit 26023b3

Browse files
excitement-engineerleebyron
authored andcommitted
Adding a type to a union is now a dangerous change. (#991)
1 parent 6953f97 commit 26023b3

File tree

2 files changed

+125
-4
lines changed

2 files changed

+125
-4
lines changed

src/utilities/__tests__/findBreakingChanges-test.js

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
findFieldsThatChangedType,
3131
findRemovedTypes,
3232
findTypesRemovedFromUnions,
33+
findTypesAddedToUnions,
3334
findTypesThatChangedKind,
3435
findValuesRemovedFromEnums,
3536
findValuesAddedToEnums,
@@ -1390,6 +1391,60 @@ describe('findDangerousChanges', () => {
13901391
);
13911392
});
13921393

1394+
it('should detect if a type was added to a union type', () => {
1395+
const type1 = new GraphQLObjectType({
1396+
name: 'Type1',
1397+
fields: {
1398+
field1: { type: GraphQLString },
1399+
}
1400+
});
1401+
// logially equivalent to type1; findTypesRemovedFromUnions should not
1402+
// treat this as different than type1
1403+
const type1a = new GraphQLObjectType({
1404+
name: 'Type1',
1405+
fields: {
1406+
field1: { type: GraphQLString },
1407+
}
1408+
});
1409+
const type2 = new GraphQLObjectType({
1410+
name: 'Type2',
1411+
fields: {
1412+
field1: { type: GraphQLString },
1413+
}
1414+
});
1415+
1416+
const oldUnionType = new GraphQLUnionType({
1417+
name: 'UnionType1',
1418+
types: [ type1 ],
1419+
resolveType: () => null,
1420+
});
1421+
const newUnionType = new GraphQLUnionType({
1422+
name: 'UnionType1',
1423+
types: [ type1a, type2 ],
1424+
resolveType: () => null,
1425+
});
1426+
1427+
const oldSchema = new GraphQLSchema({
1428+
query: queryType,
1429+
types: [
1430+
oldUnionType,
1431+
]
1432+
});
1433+
const newSchema = new GraphQLSchema({
1434+
query: queryType,
1435+
types: [
1436+
newUnionType,
1437+
]
1438+
});
1439+
1440+
expect(findTypesAddedToUnions(oldSchema, newSchema)).to.eql([
1441+
{
1442+
type: DangerousChangeType.TYPE_ADDED_TO_UNION,
1443+
description: 'Type2 was added to union type UnionType1.',
1444+
},
1445+
]);
1446+
});
1447+
13931448
it('should find all dangerous changes', () => {
13941449
const enumThatGainsAValueOld = new GraphQLEnumType({
13951450
name: 'EnumType1',
@@ -1422,6 +1477,29 @@ describe('findDangerousChanges', () => {
14221477
},
14231478
});
14241479

1480+
const typeInUnion1 = new GraphQLObjectType({
1481+
name: 'TypeInUnion1',
1482+
fields: {
1483+
field1: { type: GraphQLString },
1484+
}
1485+
});
1486+
const typeInUnion2 = new GraphQLObjectType({
1487+
name: 'TypeInUnion2',
1488+
fields: {
1489+
field1: { type: GraphQLString },
1490+
}
1491+
});
1492+
const unionTypeThatGainsATypeOld = new GraphQLUnionType({
1493+
name: 'UnionTypeThatGainsAType',
1494+
types: [ typeInUnion1 ],
1495+
resolveType: () => null,
1496+
});
1497+
const unionTypeThatGainsATypeNew = new GraphQLUnionType({
1498+
name: 'UnionTypeThatGainsAType',
1499+
types: [ typeInUnion1, typeInUnion2 ],
1500+
resolveType: () => null,
1501+
});
1502+
14251503
const newType = new GraphQLObjectType({
14261504
name: 'Type1',
14271505
fields: {
@@ -1441,15 +1519,17 @@ describe('findDangerousChanges', () => {
14411519
query: queryType,
14421520
types: [
14431521
oldType,
1444-
enumThatGainsAValueOld
1522+
enumThatGainsAValueOld,
1523+
unionTypeThatGainsATypeOld
14451524
]
14461525
});
14471526

14481527
const newSchema = new GraphQLSchema({
14491528
query: queryType,
14501529
types: [
14511530
newType,
1452-
enumThatGainsAValueNew
1531+
enumThatGainsAValueNew,
1532+
unionTypeThatGainsATypeNew
14531533
]
14541534
});
14551535

@@ -1461,6 +1541,11 @@ describe('findDangerousChanges', () => {
14611541
{
14621542
description: 'VALUE2 was added to enum type EnumType1.',
14631543
type: 'VALUE_ADDED_TO_ENUM',
1544+
},
1545+
{
1546+
type: DangerousChangeType.TYPE_ADDED_TO_UNION,
1547+
description: 'TypeInUnion2 was added to union type ' +
1548+
'UnionTypeThatGainsAType.',
14641549
}
14651550
];
14661551

src/utilities/findBreakingChanges.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ export const BreakingChangeType = {
4444

4545
export const DangerousChangeType = {
4646
ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE',
47-
VALUE_ADDED_TO_ENUM: 'VALUE_ADDED_TO_ENUM'
47+
VALUE_ADDED_TO_ENUM: 'VALUE_ADDED_TO_ENUM',
48+
TYPE_ADDED_TO_UNION: 'TYPE_ADDED_TO_UNION',
4849
};
4950

5051
export type BreakingChange = {
@@ -86,7 +87,8 @@ export function findDangerousChanges(
8687
): Array<DangerousChange> {
8788
return [
8889
...findArgChanges(oldSchema, newSchema).dangerousChanges,
89-
...findValuesAddedToEnums(oldSchema, newSchema)
90+
...findValuesAddedToEnums(oldSchema, newSchema),
91+
...findTypesAddedToUnions(oldSchema, newSchema)
9092
];
9193
}
9294

@@ -509,6 +511,40 @@ export function findTypesRemovedFromUnions(
509511
return typesRemovedFromUnion;
510512
}
511513

514+
/**
515+
* Given two schemas, returns an Array containing descriptions of any dangerous
516+
* changes in the newSchema related to adding types to a union type.
517+
*/
518+
export function findTypesAddedToUnions(
519+
oldSchema: GraphQLSchema,
520+
newSchema: GraphQLSchema
521+
): Array<DangerousChange> {
522+
const oldTypeMap = oldSchema.getTypeMap();
523+
const newTypeMap = newSchema.getTypeMap();
524+
525+
const typesAddedToUnion = [];
526+
Object.keys(newTypeMap).forEach(typeName => {
527+
const oldType = oldTypeMap[typeName];
528+
const newType = newTypeMap[typeName];
529+
if (!(oldType instanceof GraphQLUnionType) ||
530+
!(newType instanceof GraphQLUnionType)) {
531+
return;
532+
}
533+
const typeNamesInOldUnion = Object.create(null);
534+
oldType.getTypes().forEach(type => {
535+
typeNamesInOldUnion[type.name] = true;
536+
});
537+
newType.getTypes().forEach(type => {
538+
if (!typeNamesInOldUnion[type.name]) {
539+
typesAddedToUnion.push({
540+
type: DangerousChangeType.TYPE_ADDED_TO_UNION,
541+
description: `${type.name} was added to union type ${typeName}.`
542+
});
543+
}
544+
});
545+
});
546+
return typesAddedToUnion;
547+
}
512548
/**
513549
* Given two schemas, returns an Array containing descriptions of any breaking
514550
* changes in the newSchema related to removing values from an enum type.

0 commit comments

Comments
 (0)