fastify-mongoose-rest
Version:
Rest API generator tools for fastify and mongoose
115 lines (96 loc) • 3.26 kB
JavaScript
const util = require('util');
/**
* Creates search handler
*
* @param {Object} Model Mongoose model
* @param {Object} options
* @param {Object} options.post Use post as source of parameters
* @param {Object} options.findOne Determine if id is required in parameters
*/
function createSearchHandler(Model, options) {
return (routeOptions = {}) => async (request, reply) => {
// Selects source according to options. Defaults on query string but uses body
// if options.post is true.
let source = request.query;
if (options && options.post === true && request.body) {
source = request.body;
}
let queryParameters = source.query || source.q;
if (queryParameters && typeof queryParameters !== 'object') {
queryParameters = JSON.parse(queryParameters);
}
if (routeOptions && routeOptions.filter && typeof routeOptions.filter === 'function') {
queryParameters = {
...queryParameters,
...routeOptions.filter(request, reply),
};
}
// QUERY
let query;
let countQuery;
if (options && options.findOne === true) {
if (!request.params.id) {
throw new Error('Id is required parameter.');
}
query = Model.findOne({ _id: request.params.id });
countQuery = Model.findOne({ _id: request.params.id });
} else {
query = Model.find(queryParameters);
countQuery = Model.find(queryParameters);
}
// POPULATE
let { populate } = source;
if (populate) {
// If populate starts with '{', let's assume it's object and try to parse it
if (typeof populate === 'string' && populate.trim().startsWith('{')) {
populate = JSON.parse(populate);
}
// Populate has to have keys, otherwise it will throw an error
if (Object.keys(populate).length > 0) {
query.populate(populate);
}
}
// PROJECTION
let projection = source.projection || source.select || false;
if (projection) {
if (typeof projection === 'string' && projection.trim().startsWith('{')) {
projection = JSON.parse(projection);
}
query.projection(projection);
}
// SKIP
let skip = source.skip || source.page || source.p || 0;
if (skip) {
if (typeof skip !== 'number') {
skip = parseInt(skip, 10);
}
query.skip(skip);
}
// LIMIT
let limit = source.limit || source.pageSize;
if (limit) {
if (typeof limit !== 'number') {
limit = parseInt(limit, 10);
}
query.limit(limit);
}
// SORT
let { sort } = source;
if (sort) {
// If populate starts with '{', let's assume it's object and try to parse it
if (typeof sort === 'string' && sort.trim().startsWith('{')) {
sort = JSON.parse(sort);
}
query.sort(sort);
}
let result = await query.exec();
const count = await countQuery.countDocuments();
reply.header('X-Total-Count', count);
if (routeOptions.projection && typeof routeOptions.projection === 'function') {
const projectionFunc = util.promisify(routeOptions.projection);
result = await projectionFunc(request, result);
}
return reply.send(result);
};
}
module.exports = createSearchHandler;