2017-04-15 12:02:16 +09:00
|
|
|
import { Mongo } from 'meteor/mongo';
|
2017-03-16 01:25:08 +08:00
|
|
|
import SimpleSchema from 'simpl-schema';
|
2016-12-12 10:41:50 +09:00
|
|
|
import { GraphQLSchema } from './graphql.js';
|
2016-12-12 11:34:28 +09:00
|
|
|
import { Utils } from './utils.js';
|
2016-12-18 19:04:11 +09:00
|
|
|
import { runCallbacks } from './callbacks.js';
|
2016-08-08 11:18:21 +09:00
|
|
|
|
2017-04-15 12:02:16 +09:00
|
|
|
export const Collections = [];
|
|
|
|
|
2017-03-16 01:25:08 +08:00
|
|
|
SimpleSchema.extendOptions([
|
|
|
|
'viewableBy',
|
|
|
|
'insertableBy',
|
|
|
|
'editableBy',
|
2017-03-27 10:53:44 +09:00
|
|
|
'resolveAs',
|
2017-03-16 01:25:08 +08:00
|
|
|
]);
|
2016-10-29 14:17:57 +09:00
|
|
|
|
2015-05-10 13:37:42 +09:00
|
|
|
/**
|
2017-03-31 11:40:29 +09:00
|
|
|
* @summary replacement for Collection2's attachSchema
|
2015-05-10 13:37:42 +09:00
|
|
|
* @class Mongo.Collection
|
|
|
|
*/
|
2017-04-03 16:24:19 +09:00
|
|
|
Mongo.Collection.prototype.attachSchema = function (schemaOrFields) {
|
|
|
|
if (schemaOrFields instanceof SimpleSchema) {
|
|
|
|
this.simpleSchema = () => schemaOrFields;
|
|
|
|
} else {
|
|
|
|
this.simpleSchema().extend(schemaOrFields)
|
|
|
|
}
|
|
|
|
}
|
2015-05-10 13:37:42 +09:00
|
|
|
|
2015-04-24 09:28:50 +09:00
|
|
|
/**
|
2017-03-31 11:40:29 +09:00
|
|
|
* @summary Add an additional field (or an array of fields) to a schema.
|
2015-05-18 18:32:54 +09:00
|
|
|
* @param {Object|Object[]} field
|
2015-04-24 09:28:50 +09:00
|
|
|
*/
|
2015-05-18 18:32:54 +09:00
|
|
|
Mongo.Collection.prototype.addField = function (fieldOrFieldArray) {
|
2015-04-24 09:28:50 +09:00
|
|
|
|
2017-01-21 16:56:54 +09:00
|
|
|
const collection = this;
|
|
|
|
const schema = collection.simpleSchema()._schema;
|
|
|
|
const fieldSchema = {};
|
2015-05-01 18:22:00 +02:00
|
|
|
|
2017-01-21 16:56:54 +09:00
|
|
|
const fieldArray = Array.isArray(fieldOrFieldArray) ? fieldOrFieldArray : [fieldOrFieldArray];
|
2015-05-18 18:32:54 +09:00
|
|
|
|
2017-01-21 16:56:54 +09:00
|
|
|
// loop over fields and add them to schema (or extend existing fields)
|
2015-05-18 18:32:54 +09:00
|
|
|
fieldArray.forEach(function (field) {
|
2017-01-21 16:56:54 +09:00
|
|
|
const newField = {...schema[field.fieldName], ...field.fieldSchema};
|
|
|
|
fieldSchema[field.fieldName] = newField;
|
2015-05-18 18:32:54 +09:00
|
|
|
});
|
2015-04-24 09:28:50 +09:00
|
|
|
|
|
|
|
// add field schema to collection schema
|
|
|
|
collection.attachSchema(fieldSchema);
|
2015-05-01 18:22:00 +02:00
|
|
|
};
|
2015-04-27 09:55:29 +09:00
|
|
|
|
2015-04-27 10:30:47 +09:00
|
|
|
/**
|
2016-04-09 09:41:20 +09:00
|
|
|
* @summary Remove a field from a schema.
|
2015-04-27 10:30:47 +09:00
|
|
|
* @param {String} fieldName
|
|
|
|
*/
|
2015-05-10 13:37:42 +09:00
|
|
|
Mongo.Collection.prototype.removeField = function (fieldName) {
|
2015-04-27 10:30:47 +09:00
|
|
|
|
|
|
|
var collection = this;
|
|
|
|
var schema = _.omit(collection.simpleSchema()._schema, fieldName);
|
|
|
|
|
|
|
|
// add field schema to collection schema
|
|
|
|
collection.attachSchema(schema, {replace: true});
|
2015-05-01 18:22:00 +02:00
|
|
|
};
|
2015-04-27 10:30:47 +09:00
|
|
|
|
2015-04-27 09:55:29 +09:00
|
|
|
/**
|
2017-03-12 10:25:29 +09:00
|
|
|
* @summary Add a default view function.
|
|
|
|
* @param {Function} view
|
2015-04-27 09:55:29 +09:00
|
|
|
*/
|
2017-03-05 10:33:34 +00:00
|
|
|
Mongo.Collection.prototype.addDefaultView = function (view) {
|
|
|
|
this.defaultView = view;
|
|
|
|
};
|
|
|
|
|
2017-03-12 10:25:29 +09:00
|
|
|
/**
|
|
|
|
* @summary Add a named view function.
|
|
|
|
* @param {String} viewName
|
|
|
|
* @param {Function} view
|
|
|
|
*/
|
2017-03-05 10:33:34 +00:00
|
|
|
Mongo.Collection.prototype.addView = function (viewName, view) {
|
|
|
|
this.views[viewName] = view;
|
|
|
|
};
|
|
|
|
|
2017-03-18 15:59:31 +09:00
|
|
|
// see https://github.com/dburles/meteor-collection-helpers/blob/master/collection-helpers.js
|
|
|
|
Mongo.Collection.prototype.helpers = function(helpers) {
|
|
|
|
var self = this;
|
|
|
|
|
|
|
|
if (self._transform && ! self._helpers)
|
|
|
|
throw new Meteor.Error("Can't apply helpers to '" +
|
|
|
|
self._name + "' a transform function already exists!");
|
|
|
|
|
|
|
|
if (! self._helpers) {
|
|
|
|
self._helpers = function Document(doc) { return _.extend(this, doc); };
|
|
|
|
self._transform = function(doc) {
|
|
|
|
return new self._helpers(doc);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
_.each(helpers, function(helper, key) {
|
|
|
|
self._helpers.prototype[key] = helper;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2016-12-12 10:24:34 +09:00
|
|
|
export const createCollection = options => {
|
2016-11-21 16:18:08 +09:00
|
|
|
|
2017-03-29 15:49:07 +09:00
|
|
|
const {collectionName, typeName, schema, resolvers, mutations, generateGraphQLSchema = true, dbCollectionName } = options;
|
2017-03-12 10:25:29 +09:00
|
|
|
|
2016-11-21 16:18:08 +09:00
|
|
|
// initialize new Mongo collection
|
2017-04-15 12:02:16 +09:00
|
|
|
const collection = collectionName === 'Users' ? Meteor.users : new Mongo.Collection(dbCollectionName ? dbCollectionName : collectionName.toLowerCase());
|
2016-11-21 16:18:08 +09:00
|
|
|
|
|
|
|
// decorate collection with options
|
|
|
|
collection.options = options;
|
|
|
|
|
|
|
|
// add typeName
|
2017-03-12 10:25:29 +09:00
|
|
|
collection.typeName = typeName;
|
2016-11-21 16:18:08 +09:00
|
|
|
|
2017-03-05 10:33:34 +00:00
|
|
|
// add views
|
|
|
|
collection.views = [];
|
|
|
|
|
2017-03-12 10:25:29 +09:00
|
|
|
if (schema) {
|
2016-11-27 19:12:54 +09:00
|
|
|
// attach schema to collection
|
2017-03-12 10:25:29 +09:00
|
|
|
collection.attachSchema(new SimpleSchema(schema));
|
2016-11-27 19:12:54 +09:00
|
|
|
}
|
2016-11-21 16:18:08 +09:00
|
|
|
|
|
|
|
// add collection to resolver context
|
|
|
|
const context = {};
|
2017-03-12 10:25:29 +09:00
|
|
|
context[Utils.capitalize(collectionName)] = collection;
|
2016-12-12 10:41:50 +09:00
|
|
|
GraphQLSchema.addToContext(context);
|
2016-11-21 16:18:08 +09:00
|
|
|
|
2017-03-12 10:25:29 +09:00
|
|
|
if (generateGraphQLSchema){
|
2017-03-16 01:25:08 +08:00
|
|
|
|
2017-03-12 10:25:29 +09:00
|
|
|
// add collection to list of dynamically generated GraphQL schemas
|
|
|
|
GraphQLSchema.addCollection(collection);
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------- Queries -------------------------------- //
|
2017-03-16 01:25:08 +08:00
|
|
|
|
2017-03-12 10:25:29 +09:00
|
|
|
if (resolvers) {
|
|
|
|
const queryResolvers = {};
|
|
|
|
// list
|
|
|
|
if (resolvers.list) { // e.g. ""
|
|
|
|
GraphQLSchema.addQuery(`${resolvers.list.name}(terms: JSON, offset: Int, limit: Int): [${typeName}]`);
|
2017-04-07 16:06:33 +09:00
|
|
|
queryResolvers[resolvers.list.name] = resolvers.list.resolver.bind(resolvers.list);
|
2017-03-12 10:25:29 +09:00
|
|
|
}
|
|
|
|
// single
|
|
|
|
if (resolvers.single) {
|
|
|
|
GraphQLSchema.addQuery(`${resolvers.single.name}(documentId: String, slug: String): ${typeName}`);
|
2017-04-07 16:06:33 +09:00
|
|
|
queryResolvers[resolvers.single.name] = resolvers.single.resolver.bind(resolvers.single);
|
2017-03-12 10:25:29 +09:00
|
|
|
}
|
|
|
|
// total
|
|
|
|
if (resolvers.total) {
|
|
|
|
GraphQLSchema.addQuery(`${resolvers.total.name}(terms: JSON): Int`);
|
|
|
|
queryResolvers[resolvers.total.name] = resolvers.total.resolver;
|
|
|
|
}
|
|
|
|
GraphQLSchema.addResolvers({ Query: { ...queryResolvers } });
|
2016-11-27 19:12:54 +09:00
|
|
|
}
|
2016-11-21 16:18:08 +09:00
|
|
|
|
2017-03-12 10:25:29 +09:00
|
|
|
// ------------------------------------- Mutations -------------------------------- //
|
|
|
|
|
|
|
|
if (mutations) {
|
2017-03-13 10:10:20 +09:00
|
|
|
const mutationResolvers = {};
|
2017-03-12 10:25:29 +09:00
|
|
|
// new
|
|
|
|
if (mutations.new) { // e.g. "moviesNew(document: moviesInput) : Movie"
|
|
|
|
GraphQLSchema.addMutation(`${mutations.new.name}(document: ${collectionName}Input) : ${typeName}`);
|
2017-03-13 10:10:20 +09:00
|
|
|
mutationResolvers[mutations.new.name] = mutations.new.mutation.bind(mutations.new);
|
2017-03-12 10:25:29 +09:00
|
|
|
}
|
|
|
|
// edit
|
|
|
|
if (mutations.edit) { // e.g. "moviesEdit(documentId: String, set: moviesInput, unset: moviesUnset) : Movie"
|
|
|
|
GraphQLSchema.addMutation(`${mutations.edit.name}(documentId: String, set: ${collectionName}Input, unset: ${collectionName}Unset) : ${typeName}`);
|
2017-03-13 10:10:20 +09:00
|
|
|
mutationResolvers[mutations.edit.name] = mutations.edit.mutation.bind(mutations.edit);
|
2017-03-12 10:25:29 +09:00
|
|
|
}
|
|
|
|
// remove
|
|
|
|
if (mutations.remove) { // e.g. "moviesRemove(documentId: String) : Movie"
|
|
|
|
GraphQLSchema.addMutation(`${mutations.remove.name}(documentId: String) : ${typeName}`);
|
2017-03-13 10:10:20 +09:00
|
|
|
mutationResolvers[mutations.remove.name] = mutations.remove.mutation.bind(mutations.remove);
|
2017-03-12 10:25:29 +09:00
|
|
|
}
|
2017-03-13 10:10:20 +09:00
|
|
|
GraphQLSchema.addResolvers({ Mutation: { ...mutationResolvers } });
|
2016-11-27 19:12:54 +09:00
|
|
|
}
|
2016-11-21 16:18:08 +09:00
|
|
|
}
|
2017-03-16 01:25:08 +08:00
|
|
|
|
2016-12-18 19:04:11 +09:00
|
|
|
// ------------------------------------- Parameters -------------------------------- //
|
|
|
|
|
2017-03-18 15:59:31 +09:00
|
|
|
collection.getParameters = (terms = {}, apolloClient, currentUser) => {
|
2016-12-18 19:04:11 +09:00
|
|
|
|
2016-12-20 09:27:16 +09:00
|
|
|
// console.log(terms)
|
2016-12-18 19:04:11 +09:00
|
|
|
|
|
|
|
let parameters = {
|
|
|
|
selector: {},
|
|
|
|
options: {}
|
|
|
|
};
|
|
|
|
|
2017-03-05 10:33:34 +00:00
|
|
|
if (collection.defaultView) {
|
|
|
|
parameters = Utils.deepExtend(true, parameters, collection.defaultView(terms, apolloClient));
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle view option
|
|
|
|
if (terms.view && collection.views[terms.view]) {
|
|
|
|
const view = collection.views[terms.view];
|
|
|
|
parameters = Utils.deepExtend(true, parameters, view(terms, apolloClient));
|
|
|
|
}
|
|
|
|
|
2016-12-18 19:04:11 +09:00
|
|
|
// iterate over posts.parameters callbacks
|
2017-04-19 12:19:17 +09:00
|
|
|
parameters = runCallbacks(`${collectionName.toLowerCase()}.parameters`, parameters, _.clone(terms), apolloClient);
|
2016-12-18 19:04:11 +09:00
|
|
|
|
2017-03-27 10:53:44 +09:00
|
|
|
// extend sort to sort posts by _id to break ties
|
2017-03-18 15:59:31 +09:00
|
|
|
// NOTE: always do this last to avoid overriding another sort
|
2017-03-27 10:53:44 +09:00
|
|
|
parameters = Utils.deepExtend(true, parameters, {options: {sort: {_id: -1}}});
|
2017-03-18 15:59:31 +09:00
|
|
|
|
|
|
|
// limit number of items to 200
|
2017-03-23 15:50:35 +09:00
|
|
|
parameters.options.limit = (terms.limit < 1 || terms.limit > 200) ? 200 : terms.limit;
|
2017-03-18 15:59:31 +09:00
|
|
|
|
|
|
|
// limit fields to viewable fields
|
|
|
|
if (currentUser) {
|
|
|
|
parameters.options.fields = currentUser.getViewableFields(collection);
|
|
|
|
}
|
2016-12-18 19:04:11 +09:00
|
|
|
|
2016-12-20 09:27:16 +09:00
|
|
|
// console.log(parameters);
|
2016-12-18 19:04:11 +09:00
|
|
|
|
|
|
|
return parameters;
|
|
|
|
}
|
|
|
|
|
2017-04-15 12:02:16 +09:00
|
|
|
Collections.push(collection);
|
|
|
|
|
2016-11-21 16:18:08 +09:00
|
|
|
return collection;
|
2017-04-15 12:02:16 +09:00
|
|
|
}
|