Vulcan/packages/vulcan-core/lib/modules/default_resolvers.js

128 lines
4.7 KiB
JavaScript
Raw Normal View History

/*
Default list, single, and total resolvers
*/
import { Utils, debug, debugGroup, debugGroupEnd, Connectors } from 'meteor/vulcan:lib';
import { createError } from 'apollo-errors';
2017-09-15 11:14:09 +02:00
const defaultOptions = {
2018-01-29 10:09:31 +09:00
cacheMaxAge: 300,
};
2018-06-02 18:49:53 +09:00
// note: for some reason changing resolverOptions to "options" throws error
export const getDefaultResolvers = (collectionName, resolverOptions = defaultOptions) => {
2018-06-02 18:49:53 +09:00
// TODO: find more reliable way to get type name from collection name
const typeName = collectionName.slice(0, -1);
2018-06-06 09:07:13 +09:00
return {
// resolver for returning a list of documents based on a set of query terms
multi: {
2018-06-02 18:49:53 +09:00
description: `A list of ${typeName} documents matching a set of query terms`,
2018-06-05 12:12:04 +09:00
async resolver(root, { input = {} }, context, { cacheControl }) {
const { terms = {}, enableCache = false } = input;
2018-06-06 09:07:13 +09:00
2018-01-29 10:09:31 +09:00
debug('');
2018-06-02 18:49:53 +09:00
debugGroup(`--------------- start \x1b[35m${typeName} list\x1b[0m resolver ---------------`);
2018-01-06 13:46:31 +01:00
debug(`Options: ${JSON.stringify(resolverOptions)}`);
2018-04-24 10:21:20 +09:00
debug(`Terms: ${JSON.stringify(terms)}`);
if (cacheControl && enableCache) {
2017-12-08 20:54:23 +09:00
const maxAge = resolverOptions.cacheMaxAge || defaultOptions.cacheMaxAge;
cacheControl.setCacheHint({ maxAge });
}
2017-09-15 11:14:09 +02:00
// get currentUser and Users collection from context
const { currentUser, Users } = context;
2017-09-15 11:14:09 +02:00
// get collection based on collectionName argument
const collection = context[collectionName];
// get selector and options from terms and perform Mongo query
let { selector, options } = await collection.getParameters(terms, {}, context);
options.skip = terms.offset;
debug({ selector, options });
const docs = await Connectors.find(collection, selector, options);
// if collection has a checkAccess function defined, remove any documents that doesn't pass the check
2018-01-29 10:09:31 +09:00
const viewableDocs = collection.checkAccess
? _.filter(docs, doc => collection.checkAccess(currentUser, doc))
: docs;
// take the remaining documents and remove any fields that shouldn't be accessible
const restrictedDocs = Users.restrictViewableFields(currentUser, collection, viewableDocs);
// prime the cache
restrictedDocs.forEach(doc => collection.loader.prime(doc._id, doc));
debug(`\x1b[33m=> ${restrictedDocs.length} documents returned\x1b[0m`);
debugGroupEnd();
2018-06-02 18:49:53 +09:00
debug(`--------------- end \x1b[35m${typeName} list\x1b[0m resolver ---------------`);
2018-01-29 10:09:31 +09:00
debug('');
2018-06-05 11:51:25 +09:00
// get total count of documents matching the selector
const totalCount = await Connectors.count(collection, selector);
// return results
2018-06-05 11:51:25 +09:00
return { results: restrictedDocs, totalCount };
},
},
// resolver for returning a single document queried based on id or slug
single: {
2018-06-02 18:49:53 +09:00
description: `A single ${typeName} document fetched by ID or slug`,
2018-06-05 12:12:04 +09:00
async resolver(root, { input = {} }, context, { cacheControl }) {
const { selector = {}, enableCache = false } = input;
const { documentId, slug } = selector;
2018-06-05 12:12:04 +09:00
2018-01-29 10:09:31 +09:00
debug('');
2018-06-02 18:49:53 +09:00
debugGroup(`--------------- start \x1b[35m${typeName} single\x1b[0m resolver ---------------`);
2018-01-06 13:46:31 +01:00
debug(`Options: ${JSON.stringify(resolverOptions)}`);
debug(`DocumentId: ${documentId}, Slug: ${slug}`);
if (cacheControl && enableCache) {
2017-12-08 20:54:23 +09:00
const maxAge = resolverOptions.cacheMaxAge || defaultOptions.cacheMaxAge;
cacheControl.setCacheHint({ maxAge });
}
2017-09-15 11:14:09 +02:00
const { currentUser, Users } = context;
const collection = context[collectionName];
// don't use Dataloader if doc is selected by slug
2018-01-29 10:09:31 +09:00
const doc = documentId
? await collection.loader.load(documentId)
2018-06-06 09:07:13 +09:00
: slug
? await Connectors.get(collection, { slug })
: await Connectors.get(collection);
if (!doc) {
const MissingDocumentError = createError('app.missing_document', { message: 'app.missing_document' });
throw new MissingDocumentError({ data: { documentId, slug } });
}
// if collection has a checkAccess function defined, use it to perform a check on the current document
// (will throw an error if check doesn't pass)
if (collection.checkAccess) {
Utils.performCheck(collection.checkAccess, currentUser, doc, collection, documentId);
}
const restrictedDoc = Users.restrictViewableFields(currentUser, collection, doc);
2017-09-15 11:14:09 +02:00
debugGroupEnd();
2018-06-02 18:49:53 +09:00
debug(`--------------- end \x1b[35m${typeName} single\x1b[0m resolver ---------------`);
2018-01-29 10:09:31 +09:00
debug('');
2017-09-15 11:14:09 +02:00
// filter out disallowed properties and return resulting document
2018-06-05 11:51:25 +09:00
return { result: restrictedDoc };
},
},
2018-01-29 10:09:31 +09:00
};
};