Skip to content

Commit

Permalink
object
Browse files Browse the repository at this point in the history
  • Loading branch information
TuvalSimha committed Nov 13, 2023
1 parent 1a8c523 commit 2c68101
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 2 deletions.
47 changes: 47 additions & 0 deletions packages/core/__tests__/diff/directive-usage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,4 +405,51 @@ describe('directive-usage', () => {
expect(change.message).toEqual("Directive 'external' was removed from Scalar type 'Foo'");
});
});

describe('object-level directives', () => {
test('added directive', async () => {
const a = buildSchema(/* GraphQL */ `
directive @external on OBJECT
type Foo {
a: String
}
`);
const b = buildSchema(/* GraphQL */ `
directive @external on OBJECT
type Foo @external {
a: String
}
`);

const changes = await diff(a, b);
console.log('changes', changes);
const change = findFirstChangeByPath(changes, 'Foo.external');

expect(change.criticality.level).toEqual(CriticalityLevel.Dangerous);
expect(change.type).toEqual('DIRECTIVE_USAGE_OBJECT_ADDED');
expect(change.message).toEqual("Directive 'external' was added to Object type 'Foo'");
});
test('removed directive', async () => {
const a = buildSchema(/* GraphQL */ `
directive @external on OBJECT
type Foo @external {
a: String
}
`);
const b = buildSchema(/* GraphQL */ `
directive @external on OBJECT
type Foo {
a: String
}
`);

const changes = await diff(a, b);
console.log('changes', changes);
const change = findFirstChangeByPath(changes, 'Foo.external');

expect(change.criticality.level).toEqual(CriticalityLevel.Breaking);
expect(change.type).toEqual('DIRECTIVE_USAGE_OBJECT_REMOVED');
expect(change.message).toEqual("Directive 'external' was removed from Object type 'Foo'");
});
});
});
20 changes: 20 additions & 0 deletions packages/core/src/diff/changes/change.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export enum ChangeType {
DirectiveUsageFieldRemoved = 'DIRECTIVE_USAGE_FIELD_REMOVED',
DirectiveUsageScalarAdded = 'DIRECTIVE_USAGE_SCALAR_ADDED',
DirectiveUsageScalarRemoved = 'DIRECTIVE_USAGE_SCALAR_REMOVED',
DirectiveUsageObjectAdded = 'DIRECTIVE_USAGE_OBJECT_ADDED',
DirectiveUsageObjectRemoved = 'DIRECTIVE_USAGE_OBJECT_REMOVED',
}

export enum CriticalityLevel {
Expand Down Expand Up @@ -701,6 +703,22 @@ export type DirectiveUsageScalarRemovedChange = {
};
};

export type DirectiveUsageObjectAddedChange = {
type: ChangeType.DirectiveUsageObjectAdded;
meta: {
objectName: string;
addedDirectiveName: string;
};
};

export type DirectiveUsageObjectRemovedChange = {
type: ChangeType.DirectiveUsageObjectRemoved;
meta: {
objectName: string;
removedDirectiveName: string;
};
};

type Changes = {
[ChangeType.TypeAdded]: TypeAddedChange;
[ChangeType.TypeRemoved]: TypeRemovedChange;
Expand Down Expand Up @@ -788,6 +806,8 @@ type Changes = {
[ChangeType.DirectiveUsageFieldRemoved]: DirectiveUsageFieldRemovedChange;
[ChangeType.DirectiveUsageScalarAdded]: DirectiveUsageScalarAddedChange;
[ChangeType.DirectiveUsageScalarRemoved]: DirectiveUsageScalarRemovedChange;
[ChangeType.DirectiveUsageObjectAdded]: DirectiveUsageObjectAddedChange;
[ChangeType.DirectiveUsageObjectRemoved]: DirectiveUsageObjectRemovedChange;
};

export type SerializableChange = Changes[keyof Changes];
66 changes: 65 additions & 1 deletion packages/core/src/diff/changes/object.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { GraphQLInterfaceType, GraphQLObjectType } from 'graphql';
import { ConstDirectiveNode, GraphQLInterfaceType, GraphQLObjectType } from 'graphql';
import {
Change,
ChangeType,
CriticalityLevel,
DirectiveUsageObjectAddedChange,
DirectiveUsageObjectRemovedChange,
ObjectTypeInterfaceAddedChange,
ObjectTypeInterfaceRemovedChange,
} from './change.js';
Expand Down Expand Up @@ -68,3 +70,65 @@ export function objectTypeInterfaceRemoved(
},
});
}

function buildObjectDiractiveUsageRemovedMessage(args: DirectiveUsageObjectRemovedChange['meta']) {
return `Directive '${args.removedDirectiveName}' was removed from Object type '${args.objectName}'`;
}

export function objectDiractiveUsageRemovedFromMeta(args: DirectiveUsageObjectRemovedChange) {
return {
type: ChangeType.DirectiveUsageObjectRemoved,
criticality: {
level: CriticalityLevel.Breaking,
reason:
'Removing a directive from an object type can cause existing queries that use this directive to error.',
},
message: buildObjectDiractiveUsageRemovedMessage(args.meta),
meta: args.meta,
path: [args.meta.objectName, args.meta.removedDirectiveName].join('.'),
} as const;
}

export function objectDiractiveUsageRemoved(
oldObject: GraphQLObjectType,
directive: ConstDirectiveNode,
): Change<ChangeType.DirectiveUsageObjectRemoved> {
return objectDiractiveUsageRemovedFromMeta({
type: ChangeType.DirectiveUsageObjectRemoved,
meta: {
objectName: oldObject.name,
removedDirectiveName: directive.name.value,
},
});
}

function buildObjectDiractiveUsageAddedMessage(args: DirectiveUsageObjectAddedChange['meta']) {
return `Directive '${args.addedDirectiveName}' was added to Object type '${args.objectName}'`;
}

export function objectDiractiveUsageAddedFromMeta(args: DirectiveUsageObjectAddedChange) {
return {
type: ChangeType.DirectiveUsageObjectAdded,
criticality: {
level: CriticalityLevel.Dangerous,
reason:
'Adding a directive to an object type can cause existing queries that use this directive to error.',
},
message: buildObjectDiractiveUsageAddedMessage(args.meta),
meta: args.meta,
path: [args.meta.objectName, args.meta.addedDirectiveName].join('.'),
} as const;
}

export function objectDiractiveUsageAdded(
newObject: GraphQLObjectType,
directive: ConstDirectiveNode,
): Change<ChangeType.DirectiveUsageObjectAdded> {
return objectDiractiveUsageAddedFromMeta({
type: ChangeType.DirectiveUsageObjectAdded,
meta: {
objectName: newObject.name,
addedDirectiveName: directive.name.value,
},
});
}
16 changes: 15 additions & 1 deletion packages/core/src/diff/object.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { GraphQLObjectType } from 'graphql';
import { compareLists } from '../utils/compare.js';
import { fieldAdded, fieldRemoved } from './changes/field.js';
import { objectTypeInterfaceAdded, objectTypeInterfaceRemoved } from './changes/object.js';
import {
objectDiractiveUsageAdded,
objectDiractiveUsageRemoved,
objectTypeInterfaceAdded,
objectTypeInterfaceRemoved,
} from './changes/object.js';
import { changesInField } from './field.js';
import { AddChange } from './schema.js';

Expand Down Expand Up @@ -36,4 +41,13 @@ export function changesInObject(
changesInField(oldType, f.oldVersion, f.newVersion, addChange);
},
});

compareLists(oldType.astNode?.directives || [], newType.astNode?.directives || [], {
onAdded(diractive) {
addChange(objectDiractiveUsageAdded(newType, diractive));
},
onRemoved(diractive) {
addChange(objectDiractiveUsageRemoved(newType, diractive));
},
});
}

0 comments on commit 2c68101

Please sign in to comment.