Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
schema transform functions take a schema as an argument and return a schema, possibly modifying it a schema transform function can be templated, i.e. one can create a function that takes certain arguments, such as the names of directives that annotate fields of interest, and return a schema transform function that modifies the schema based on the specified annotating directives this allows one to reuse a schema transform function across projects, allowing for the customization of the schema transform function on a per use basis schema transform functionc can be called directly on a schema to modify it before use -- makeExecutableSchema can now also be passed an array of schema transform functions, with makeExecutableSchema responsible for performing all schema transformations prior to returning. Eventually, all schema visitor examples can be rewritten using the schema transform functional API addresses #1234
- Loading branch information
Showing
5 changed files
with
171 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import { | ||
GraphQLObjectType, | ||
GraphQLSchema, | ||
printSchema, | ||
} from 'graphql'; | ||
|
||
import { makeExecutableSchema } from '@graphql-tools/schema'; | ||
import { | ||
SchemaTransform, | ||
mapSchema, | ||
MapperKind, | ||
getDirectives, | ||
} from '@graphql-tools/utils'; | ||
|
||
const typeDefs = ` | ||
directive @schemaDirective(role: String) on SCHEMA | ||
directive @schemaExtensionDirective(role: String) on SCHEMA | ||
directive @queryTypeDirective on OBJECT | ||
directive @queryTypeExtensionDirective on OBJECT | ||
directive @queryFieldDirective on FIELD_DEFINITION | ||
directive @enumTypeDirective on ENUM | ||
directive @enumTypeExtensionDirective on ENUM | ||
directive @enumValueDirective on ENUM_VALUE | ||
directive @dateDirective(tz: String) on SCALAR | ||
directive @dateExtensionDirective(tz: String) on SCALAR | ||
directive @interfaceDirective on INTERFACE | ||
directive @interfaceExtensionDirective on INTERFACE | ||
directive @interfaceFieldDirective on FIELD_DEFINITION | ||
directive @inputTypeDirective on INPUT_OBJECT | ||
directive @inputTypeExtensionDirective on INPUT_OBJECT | ||
directive @inputFieldDirective on INPUT_FIELD_DEFINITION | ||
directive @mutationTypeDirective on OBJECT | ||
directive @mutationTypeExtensionDirective on OBJECT | ||
directive @mutationArgumentDirective on ARGUMENT_DEFINITION | ||
directive @mutationMethodDirective on FIELD_DEFINITION | ||
directive @objectTypeDirective on OBJECT | ||
directive @objectTypeExtensionDirective on OBJECT | ||
directive @objectFieldDirective on FIELD_DEFINITION | ||
directive @unionDirective on UNION | ||
directive @unionExtensionDirective on UNION | ||
schema @schemaDirective(role: "admin") { | ||
query: Query | ||
mutation: Mutation | ||
} | ||
extend schema @schemaExtensionDirective(role: "admin") | ||
type Query @queryTypeDirective { | ||
people: [Person] @queryFieldDirective | ||
} | ||
extend type Query @queryTypeExtensionDirective | ||
enum Gender @enumTypeDirective { | ||
NONBINARY @enumValueDirective | ||
FEMALE | ||
MALE | ||
} | ||
extend enum Gender @enumTypeExtensionDirective | ||
scalar Date @dateDirective(tz: "utc") | ||
extend scalar Date @dateExtensionDirective(tz: "utc") | ||
interface Named @interfaceDirective { | ||
name: String! @interfaceFieldDirective | ||
} | ||
extend interface Named @interfaceExtensionDirective | ||
input PersonInput @inputTypeDirective { | ||
name: String! @inputFieldDirective | ||
gender: Gender | ||
} | ||
extend input PersonInput @inputTypeExtensionDirective | ||
type Mutation @mutationTypeDirective { | ||
addPerson( | ||
input: PersonInput @mutationArgumentDirective | ||
): Person @mutationMethodDirective | ||
} | ||
extend type Mutation @mutationTypeExtensionDirective | ||
type Person implements Named @objectTypeDirective { | ||
id: ID! @objectFieldDirective | ||
name: String! | ||
} | ||
extend type Person @objectTypeExtensionDirective | ||
union WhateverUnion @unionDirective = Person | Query | Mutation | ||
extend union WhateverUnion @unionExtensionDirective`; | ||
|
||
describe('@directives', () => { | ||
test('can be iterated with mapSchema', () => { | ||
const visited: Set<GraphQLObjectType> = new Set(); | ||
|
||
function addTypeToSetDirective(directiveNames: Array<string>): SchemaTransform { | ||
return schema => mapSchema(schema, { | ||
[MapperKind.OBJECT_TYPE]: type => { | ||
const directives = getDirectives(schema, type); | ||
Object.keys(directives).forEach(directiveName => { | ||
if (directiveNames.includes(directiveName)) { | ||
expect(type.name).toBe(schema.getQueryType().name); | ||
visited.add(type); | ||
} | ||
}); | ||
return undefined; | ||
} | ||
}) | ||
} | ||
|
||
makeExecutableSchema({ | ||
typeDefs, | ||
schemaTransforms: [ | ||
addTypeToSetDirective(['queryTypeDirective', 'queryTypeExtensionDirective']) | ||
] | ||
}); | ||
|
||
expect(visited.size).toBe(1); | ||
}); | ||
|
||
test('can visit the schema directly', () => { | ||
const visited: Array<GraphQLSchema> = []; | ||
|
||
function recordDirectiveUses(directiveNames: Array<string>): SchemaTransform { | ||
return schema => { | ||
const directives = getDirectives(schema, schema); | ||
Object.keys(directives).forEach(directiveName => { | ||
if (directiveNames.includes(directiveName)) { | ||
visited.push(schema); | ||
} | ||
}); | ||
return schema; | ||
} | ||
} | ||
|
||
const schema = makeExecutableSchema({ | ||
typeDefs, | ||
schemaTransforms: [ | ||
recordDirectiveUses(['schemaDirective', 'schemaExtensionDirective']) | ||
] | ||
}); | ||
|
||
const printedSchema = printSchema(makeExecutableSchema({ typeDefs })); | ||
expect(printSchema(schema)).toEqual(printedSchema); | ||
|
||
expect(visited.length).toBe(2); | ||
expect(printSchema(visited[0])).toEqual(printedSchema); | ||
expect(printSchema(visited[1])).toEqual(printedSchema); | ||
}); | ||
}); |