diff --git a/LinkDirective.js b/LinkDirective.js index aa51bd1..e452c8b 100644 --- a/LinkDirective.js +++ b/LinkDirective.js @@ -1,100 +1,106 @@ -import { SchemaDirectiveVisitor } from 'graphql-tools'; -import { GraphQLList, GraphQLObjectType, GraphQLNonNull } from 'graphql/type'; +import { mapSchema, getDirectives } from '@graphql-tools/utils'; +import { GraphQLList, GraphQLObjectType, GraphQLNonNull } from 'graphql'; import { Mongo } from 'meteor/mongo'; import { setupMongoDirective } from './MongoDirective'; -export default class LinkDirective extends SchemaDirectiveVisitor { - visitFieldDefinition(field, details) { - const { objectType } = details; - const { args } = this; +export default function linkDirectiveTransformer(schema) { + return mapSchema(schema, { + [mapSchema.MAP_FIELD_DEFINITION]: (field, fieldName, typeName) => { + const directives = getDirectives(schema, field); + const linkDirective = directives.link; + + if (linkDirective) { + const objectType = schema.getType(typeName); + + if (!objectType._mongoCollectionName) { + throw new Meteor.Error( + 'collection-not-found', + `You are trying to set the link: ${fieldName} but your object type does not have @mongo directive set-up` + ); + } - if (!objectType._mongoCollectionName) { - throw new Meteor.Error( - 'collection-not-found', - `You are trying to set the link: ${ - field.name - } but your object type does not have @mongo directive set-up` - ); - } + const isArrayField = field.type instanceof GraphQLList; + let referencedType; - const isArrayField = field.type instanceof GraphQLList; - let referencedType; + if (isArrayField) { + referencedType = field.type.ofType; + } else { + referencedType = field.type; + } - if (isArrayField) { - referencedType = field.type.ofType; - } else { - referencedType = field.type; - } + if (referencedType instanceof GraphQLNonNull) { + referencedType = referencedType.ofType; + } else { + if (!(referencedType instanceof GraphQLObjectType)) { + throw new Meteor.Error( + 'invalid-type', + `You are trying to attach a link on a invalid type. @link directive only works with GraphQLObjectType ` + ); + } + } - if (referencedType instanceof GraphQLNonNull) { - referencedType = referencedType.ofType; - } else { - if (!(referencedType instanceof GraphQLObjectType)) { - throw new Meteor.Error( - 'invalid-type', - `You are trying to attach a link on a invalid type. @link directive only works with GraphQLObjectType ` - ); - } - } + let referencedCollectionName = referencedType._mongoCollectionName; + if (!referencedCollectionName) { + const objectNodeDirectives = referencedType.astNode.directives; + const mongoDirective = objectNodeDirectives.find(directive => { + return directive.name.value === 'mongo'; + }); - let referencedCollectionName = referencedType._mongoCollectionName; - if (!referencedCollectionName) { - const objectNodeDirectives = referencedType.astNode.directives; - const mongoDirective = objectNodeDirectives.find(directive => { - return directive.name.value === 'mongo'; - }); + if (mongoDirective) { + const nameArgument = mongoDirective.arguments.find( + argument => argument.name.value === 'name' + ); - if (mongoDirective) { - const nameArgument = mongoDirective.arguments.find( - argument => argument.name.value === 'name' - ); + setupMongoDirective(referencedType, { + name: nameArgument.value.value, + }); - setupMongoDirective(referencedType, { - name: nameArgument.value.value, - }); + referencedCollectionName = nameArgument.value.value; + } else { + throw new Meteor.Error( + 'invalid-collection', + `The referenced type does not have a collection setup using @mongo directive` + ); + } + } - referencedCollectionName = nameArgument.value.value; - } else { - throw new Meteor.Error( - 'invalid-collection', - `The referenced type does not have a collection setup using @mongo directive` - ); - } - } + const thisCollectionName = objectType._mongoCollectionName; - const thisCollectionName = objectType._mongoCollectionName; + const referencedCollection = Mongo.Collection.get(referencedCollectionName); + const thisCollection = Mongo.Collection.get(thisCollectionName); - const referencedCollection = Mongo.Collection.get(referencedCollectionName); - const thisCollection = Mongo.Collection.get(thisCollectionName); + let config = {}; + if (linkDirective.to) { + config = Object.assign({}, linkDirective); + config.inversedBy = linkDirective.to; + delete config.to; + } else { + if (linkDirective.field) { + config = Object.assign( + { + type: isArrayField ? 'many' : 'one', + field: linkDirective.field, + index: true, + }, + linkDirective + ); + } else { + throw new Meteor.Error( + `invalid-args`, + `You have provided invalid arguments for this link in ${thisCollectionName}. The "field" property is missing.` + ); + } + } - let config = {}; - if (args.to) { - config = Object.assign({}, args); - config.inversedBy = args.to; - delete config.to; - } else { - if (args.field) { - config = Object.assign( - { - type: isArrayField ? 'many' : 'one', - field: args.field, - index: true, + thisCollection.addLinks({ + [fieldName]: { + collection: referencedCollection, + ...config, }, - args - ); - } else { - throw new Meteor.Error( - `invalid-args`, - `You have provided invalid arguments for this link in ${thisCollectionName}. The "field" property is missing.` - ); + }); } + + return field; } - - thisCollection.addLinks({ - [field.name]: { - collection: referencedCollection, - ...config, - }, - }); - } + }); } diff --git a/MapToDirective.js b/MapToDirective.js index e2ba73d..6795c9b 100644 --- a/MapToDirective.js +++ b/MapToDirective.js @@ -1,5 +1,5 @@ -import { SchemaDirectiveVisitor } from 'graphql-tools'; -import { GraphQLScalarType, GraphQLObjectType } from 'graphql/type'; +import { mapSchema, getDirectives } from '@graphql-tools/utils'; +import { GraphQLScalarType } from 'graphql'; import { Mongo } from 'meteor/mongo'; function resolve(path, obj) { @@ -7,41 +7,46 @@ function resolve(path, obj) { return prev ? prev[curr] : undefined; }, obj || self); } -export default class MapToDirective extends SchemaDirectiveVisitor { - visitFieldDefinition(field, details) { - const { objectType } = details; - const { args } = this; - if (!objectType._mongoCollectionName) { - throw new Meteor.Error( - 'collection-not-found', - `You are trying to set mapTo: ${ - field.name - } but your object type does not have @mongo directive set-up` - ); - } +export default function mapToDirectiveTransformer(schema) { + return mapSchema(schema, { + [mapSchema.MAP_FIELD_DEFINITION]: (field, fieldName, typeName) => { + const directives = getDirectives(schema, field); + const mapDirective = directives.map; + + if (mapDirective && mapDirective.to) { + const objectType = schema.getType(typeName); + + if (!objectType._mongoCollectionName) { + throw new Meteor.Error( + 'collection-not-found', + `You are trying to set mapTo: ${fieldName} but your object type does not have @mongo directive set-up` + ); + } - const isScalar = field.type instanceof GraphQLScalarType; - if (!isScalar) { - throw new Meteor.Error( - 'collection-not-found', - `You are trying to set the mapTo directive on a non-scalar on field ${ - field.name - }` - ); - } + const isScalar = field.type instanceof GraphQLScalarType; + if (!isScalar) { + throw new Meteor.Error( + 'collection-not-found', + `You are trying to set the mapTo directive on a non-scalar on field ${fieldName}` + ); + } - const collection = Mongo.Collection.get(objectType._mongoCollectionName); + const collection = Mongo.Collection.get(objectType._mongoCollectionName); - collection.addReducers({ - [field.name]: { - body: { - [args.to]: 1, - }, - reduce(obj) { - return resolve(args.to, obj); - }, - }, - }); - } + collection.addReducers({ + [fieldName]: { + body: { + [mapDirective.to]: 1, + }, + reduce(obj) { + return resolve(mapDirective.to, obj); + }, + }, + }); + } + + return field; + } + }); } diff --git a/MongoDirective.js b/MongoDirective.js index aee2e61..c021041 100644 --- a/MongoDirective.js +++ b/MongoDirective.js @@ -1,20 +1,19 @@ -import { SchemaDirectiveVisitor } from 'graphql-tools'; +import { mapSchema, getDirectives } from '@graphql-tools/utils'; import { Mongo } from 'meteor/mongo'; -export default class MongoDirective extends SchemaDirectiveVisitor { - /** - * @param {GraphQLObjectType} type - */ - visitObject(type) { - if (type._mongoCollectionName) { - // it has already been setup by a link directive somewhere - return; +export default function mongoDirectiveTransformer(schema) { + return mapSchema(schema, { + [mapSchema.MAP_OBJECT_TYPE]: (type) => { + const directives = getDirectives(schema, type); + const mongoDirective = directives.mongo; + + if (mongoDirective && mongoDirective.name) { + setupMongoDirective(type, { name: mongoDirective.name }); + } + + return type; } - - setupMongoDirective(type, this.args); - } - - visitFieldDefinition() {} + }); } export function setupMongoDirective(type, args) { diff --git a/index.js b/index.js index 86457e8..d732d63 100644 --- a/index.js +++ b/index.js @@ -1,18 +1,18 @@ import directiveDefinitions from './directiveDefinitions'; -import LinkDirective from './LinkDirective'; -import MapToDirective from './MapToDirective'; -import MongoDirective from './MongoDirective'; +import linkDirectiveTransformer from './LinkDirective'; +import mapToDirectiveTransformer from './MapToDirective'; +import mongoDirectiveTransformer from './MongoDirective'; -const directives = { - mongo: MongoDirective, - link: LinkDirective, - map: MapToDirective, +const transformers = { + mongo: mongoDirectiveTransformer, + link: linkDirectiveTransformer, + map: mapToDirectiveTransformer, }; export { - directives, + transformers, directiveDefinitions, - LinkDirective, - MapToDirective, - MongoDirective, + linkDirectiveTransformer, + mapToDirectiveTransformer, + mongoDirectiveTransformer, }; diff --git a/package.js b/package.js index 1e2563d..95ab08b 100644 --- a/package.js +++ b/package.js @@ -13,8 +13,12 @@ Package.describe({ documentation: 'README.md', }); +// @graphql-tools/utils is provided as a peer dependency from the main package.json +// This ensures all packages use the same GraphQL-related packages to avoid +// "Cannot use GraphQLSchema from another module or realm" errors + Package.onUse(function(api) { - api.versionsFrom('1.3'); + api.versionsFrom(['1.3', '3.0']); api.use('ecmascript'); api.mainModule('index.js', 'server'); });