Skip to content

Commit

Permalink
Expand @deprecated to Object types
Browse files Browse the repository at this point in the history
  • Loading branch information
fotoetienne committed Jan 6, 2023
1 parent 7a609a2 commit 442e57b
Show file tree
Hide file tree
Showing 12 changed files with 310 additions and 12 deletions.
14 changes: 14 additions & 0 deletions src/type/__tests__/definition-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,20 @@ describe('Type System: Objects', () => {
});
});

it('defines a deprecated object type', () => {
const DeprecatedType = new GraphQLObjectType({
name: 'foo',
fields: {
bar: {
type: ScalarType,
},
},
deprecationReason: 'A terrible reason',
});

expect(DeprecatedType.deprecationReason).to.equal('A terrible reason');
});

it('accepts an Object type with a field function', () => {
const objType = new GraphQLObjectType({
name: 'SomeObject',
Expand Down
194 changes: 192 additions & 2 deletions src/type/__tests__/introspection-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,17 @@ describe('Introspection', () => {
},
{
name: 'types',
args: [],
args: [
{
name: 'includeDeprecated',
type: {
kind: 'SCALAR',
name: 'Boolean',
ofType: null,
},
defaultValue: 'false',
},
],
type: {
kind: 'NON_NULL',
name: null,
Expand Down Expand Up @@ -286,7 +296,17 @@ describe('Introspection', () => {
},
{
name: 'possibleTypes',
args: [],
args: [
{
name: 'includeDeprecated',
type: {
kind: 'SCALAR',
name: 'Boolean',
ofType: null,
},
defaultValue: 'false',
},
],
type: {
kind: 'LIST',
name: null,
Expand Down Expand Up @@ -372,6 +392,28 @@ describe('Introspection', () => {
isDeprecated: false,
deprecationReason: null,
},
{
name: 'isDeprecated',
args: [],
type: {
kind: 'SCALAR',
name: 'Boolean',
ofType: null,
},
isDeprecated: false,
deprecationReason: null,
},
{
name: 'deprecationReason',
args: [],
type: {
kind: 'SCALAR',
name: 'String',
ofType: null,
},
isDeprecated: false,
deprecationReason: null,
},
],
inputFields: null,
interfaces: [],
Expand Down Expand Up @@ -956,6 +998,7 @@ describe('Introspection', () => {
'ARGUMENT_DEFINITION',
'INPUT_FIELD_DEFINITION',
'ENUM_VALUE',
'OBJECT',
],
args: [
{
Expand Down Expand Up @@ -1231,6 +1274,153 @@ describe('Introspection', () => {
});
});

it('identifies deprecated objects', () => {
const schema = buildSchema(`
type Query {
dragon: [Dragon]
}
type Dragon @deprecated(reason: "No longer known to exist") {
name: String
}
`);

const source = `
{
__schema {
types(includeDeprecated: true) {
name
isDeprecated
deprecationReason
}
}
dragon: __type(name: "Dragon") {
name
isDeprecated
deprecationReason
}
}
`;

interface IntrospectionResponse {
__schema: {
types: [
{ name: string; isDeprecated: boolean; deprecationReason: string },
];
};
dragon: { name: string; isDeprecated: boolean; deprecationReason: string };
}

const resp = graphqlSync({ schema, source })
.data as unknown as IntrospectionResponse;

expect(resp.__schema.types).to.deep.include.members([
{
name: 'Dragon',
isDeprecated: true,
deprecationReason: 'No longer known to exist',
},
]);
expect(resp.dragon).to.deep.equal({
name: 'Dragon',
isDeprecated: true,
deprecationReason: 'No longer known to exist',
});
});

it('respects the includeDeprecated parameter for types', () => {
const schema = buildSchema(`
type Query {
dragon: [Dragon]
}
type Dragon @deprecated(reason: "No longer known to exist") {
name: String
}
`);

const source = `
{
__schema {
trueTypes: types(includeDeprecated: true) {
name
}
falseTypes: types(includeDeprecated: false) {
name
}
omittedTypes: types {
name
}
}
}
`;

interface IntrospectionResponse {
__schema: {
trueTypes: [{ name: string }];
falseTypes: [{ name: string }];
omittedTypes: [{ name: string }];
};
}

const response = graphqlSync({ schema, source })
.data as unknown as IntrospectionResponse;
expect(response.__schema.trueTypes).to.deep.include.members([
{ name: 'Dragon' },
]);
expect(response.__schema.falseTypes).to.not.deep.include.members([
{ name: 'Dragon' },
]);
expect(response.__schema.omittedTypes).to.not.deep.include.members([
{ name: 'Dragon' },
]);
});

it('respects the includeDeprecated parameter for possibleTypes', () => {
const schema = buildSchema(`
type Query {
animals: [Animal]
}
interface Animal {
name: String
}
type Dog implements Animal {
name: String
}
type Dragon implements Animal @deprecated(reason: "No longer known to exist") {
name: String
}
`);

const source = `
{
animal: __type(name: "Animal") {
trueTypes: possibleTypes(includeDeprecated: true) {
name
}
falseTypes: possibleTypes(includeDeprecated: false) {
name
}
omittedTypes: possibleTypes {
name
}
}
}
`;

const result = graphqlSync({ schema, source });
const animal = result.data?.animal;
// @ts-expect-error
expect(animal.trueTypes).to.deep.include.members([{ name: 'Dragon' }]);
// @ts-expect-error
expect(animal.falseTypes).to.not.deep.include.members([{ name: 'Dragon' }]);
// @ts-expect-error
expect(animal.omittedTypes).to.not.deep.include.members([
{ name: 'Dragon' },
]);
});

it('identifies deprecated args', () => {
const schema = buildSchema(`
type Query {
Expand Down
8 changes: 8 additions & 0 deletions src/type/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,10 @@ export type GraphQLNamedOutputType =
| GraphQLUnionType
| GraphQLEnumType;

export function getDeprecationReason(type: GraphQLNamedType) {
return 'deprecationReason' in type ? type.deprecationReason : undefined;
}

export function isNamedType(type: unknown): type is GraphQLNamedType {
return (
isScalarType(type) ||
Expand Down Expand Up @@ -707,6 +711,7 @@ export class GraphQLObjectType<TSource = any, TContext = any> {
extensions: Readonly<GraphQLObjectTypeExtensions<TSource, TContext>>;
astNode: Maybe<ObjectTypeDefinitionNode>;
extensionASTNodes: ReadonlyArray<ObjectTypeExtensionNode>;
deprecationReason: Maybe<string>;

private _fields: ThunkObjMap<GraphQLField<TSource, TContext>>;
private _interfaces: ThunkReadonlyArray<GraphQLInterfaceType>;
Expand All @@ -718,6 +723,7 @@ export class GraphQLObjectType<TSource = any, TContext = any> {
this.extensions = toObjMap(config.extensions);
this.astNode = config.astNode;
this.extensionASTNodes = config.extensionASTNodes ?? [];
this.deprecationReason = config.deprecationReason;

this._fields = () => defineFieldMap(config);
this._interfaces = () => defineInterfaces(config);
Expand Down Expand Up @@ -751,6 +757,7 @@ export class GraphQLObjectType<TSource = any, TContext = any> {
extensions: this.extensions,
astNode: this.astNode,
extensionASTNodes: this.extensionASTNodes,
deprecationReason: this.deprecationReason,
};
}

Expand Down Expand Up @@ -853,6 +860,7 @@ export interface GraphQLObjectTypeConfig<TSource, TContext> {
extensions?: Maybe<Readonly<GraphQLObjectTypeExtensions<TSource, TContext>>>;
astNode?: Maybe<ObjectTypeDefinitionNode>;
extensionASTNodes?: Maybe<ReadonlyArray<ObjectTypeExtensionNode>>;
deprecationReason?: Maybe<string>;
}

interface GraphQLObjectTypeNormalizedConfig<TSource, TContext>
Expand Down
1 change: 1 addition & 0 deletions src/type/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ export const GraphQLDeprecatedDirective: GraphQLDirective =
DirectiveLocation.ARGUMENT_DEFINITION,
DirectiveLocation.INPUT_FIELD_DEFINITION,
DirectiveLocation.ENUM_VALUE,
DirectiveLocation.OBJECT,
],
args: {
reason: {
Expand Down
33 changes: 29 additions & 4 deletions src/type/introspection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
GraphQLType,
} from './definition.js';
import {
getDeprecationReason,
GraphQLEnumType,
GraphQLList,
GraphQLNonNull,
Expand Down Expand Up @@ -46,8 +47,14 @@ export const __Schema: GraphQLObjectType = new GraphQLObjectType({
types: {
description: 'A list of all types supported by this server.',
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(__Type))),
resolve(schema) {
return Object.values(schema.getTypeMap());
args: {
includeDeprecated: { type: GraphQLBoolean, defaultValue: false },
},
resolve(schema, { includeDeprecated }) {
const types = Object.values(schema.getTypeMap());
return includeDeprecated
? types
: types.filter((type) => getDeprecationReason(type) == null);
},
},
queryType: {
Expand Down Expand Up @@ -282,9 +289,15 @@ export const __Type: GraphQLObjectType = new GraphQLObjectType({
},
possibleTypes: {
type: new GraphQLList(new GraphQLNonNull(__Type)),
resolve(type, _args, _context, { schema }) {
args: {
includeDeprecated: { type: GraphQLBoolean, defaultValue: false },
},
resolve(type, { includeDeprecated }, _context, { schema }) {
if (isAbstractType(type)) {
return schema.getPossibleTypes(type);
const possibleTypes = schema.getPossibleTypes(type);
return includeDeprecated
? possibleTypes
: possibleTypes.filter((t) => t.deprecationReason == null);
}
},
},
Expand Down Expand Up @@ -323,6 +336,18 @@ export const __Type: GraphQLObjectType = new GraphQLObjectType({
type: __Type,
resolve: (type) => ('ofType' in type ? type.ofType : undefined),
},
isDeprecated: {
type: GraphQLBoolean,
resolve: (type) =>
'deprecationReason' in type
? type.deprecationReason != null
: undefined,
},
deprecationReason: {
type: GraphQLString,
resolve: (type) =>
'deprecationReason' in type ? type.deprecationReason : undefined,
},
} as GraphQLFieldConfigMap<GraphQLType, unknown>),
});

Expand Down
11 changes: 11 additions & 0 deletions src/utilities/__tests__/buildASTSchema-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,10 @@ describe('Schema Builder', () => {
field4(oldArg: String @deprecated(reason: "Why not?"), arg: String): String
field5(arg: MyInput): String
}
type DeprecatedObject @deprecated(reason: "It ain't") {
fields1: Boolean
}
`;
expect(cycleSDL(sdl)).to.equal(sdl);

Expand Down Expand Up @@ -662,6 +666,13 @@ describe('Schema Builder', () => {
deprecationReason: 'Because I said so',
});

const deprecatedObject = assertObjectType(
schema.getType('DeprecatedObject'),
);
expect(deprecatedObject).to.include({
deprecationReason: "It ain't",
});

const inputFields = assertInputObjectType(
schema.getType('MyInput'),
).getFields();
Expand Down
Loading

0 comments on commit 442e57b

Please sign in to comment.