Advertisement
Guest User

Untitled

a guest
Jul 29th, 2016
60
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.42 KB | None | 0 0
  1. 'use strict';
  2.  
  3. // npm packages
  4. const Joi = require('joi');
  5. const _ = require('lodash');
  6. const Async = require('async');
  7. const Promise = require('bluebird');
  8. const Debug = require('debug');
  9. const boom = require('boom');
  10.  
  11. // custom modules
  12. const qHelpers = require('./queryParserHelpers');
  13. const qSchemas = require('./queryParserSchemas');
  14.  
  15. // unpack helpers
  16. const extractModelProps = qHelpers.extractModelProps;
  17. const collectionFetcher = qHelpers.collectionFetcher;
  18. const typesFromModelGleamer = qHelpers.typesFromModelGleamer;
  19. const schemaBuilder = qHelpers.schemaBuilder;
  20.  
  21. // unpack schemas
  22. const schemaTypeMap = qSchemas.schemaTypeMap;
  23. const querierSort = qSchemas.querierSort;
  24. const paginationSchema = qSchemas.paginationSchema;
  25. const querierFilter = qSchemas.querierFilter;
  26.  
  27. /**
  28. * This function builds a waterline-query from a
  29. * strongloop-style `query` object before executing the query
  30. * and returning a promise that resolves or rejects. It is used
  31. * from within route handlers
  32. * @param {object} model Waterline ORM model
  33. * @param {object} query Query parameter passed in from route handler `request.query.filter`
  34. * @return {promise} returns a promise that `resolve`s or `reject`s based on whether schema checks pass or other error
  35. */
  36. module.exports = (model, query) => {
  37. const pr = model;
  38. const collectionFields = collectionFetcher(pr);
  39. const modelProps = extractModelProps(pr);
  40.  
  41. let where = query.where === undefined ? {} : query.where;
  42.  
  43.  
  44. let include = query.include;
  45. let order = query.order;
  46. let populates = query.populates;
  47. let sort = query.sort;
  48. let skip = query.skip;
  49. let limit = query.limit;
  50. let pagination = query.pagination === undefined ? {} : query.pagination;
  51.  
  52. populates = include || populates || null;
  53. sort = order || sort || null;
  54.  
  55. const populatesSchema = Joi.array().items(
  56. Joi.string().valid(collectionFields)
  57. ).default([]);
  58.  
  59. return new Promise((resolve,reject) => {
  60.  
  61. Async.auto({
  62. setCondition: (cb) => {
  63. if (!_.isObject(where)) {
  64. return cb(null, {});
  65. }
  66.  
  67. typesFromModelGleamer(model, where, (err, keyTypes) => {
  68. if (where.or) {
  69. keyTypes.or = 'array';
  70. }
  71.  
  72. schemaBuilder(keyTypes, schemaTypeMap, where, (err, condSchema) => {
  73. condSchema.validate(where, (err, value) => {
  74. if (err) {
  75. return cb(boom.badRequest('where clause validation failure', err)); //eslint-disable-line
  76. }
  77.  
  78. return cb(null, value);
  79. });
  80. });
  81. });
  82. },
  83. where: ['setCondition', (cb, results) => {
  84. if (where.or && where.or instanceof Array) {
  85. where.or.map(e => {
  86. // filter out keys of objects in or which arent props of model
  87. Object.keys(e).filter(k => modelProps.indexOf())
  88. });
  89. }
  90. }],
  91.  
  92. populate: ['setCondition', (cb, results) => {
  93. }],
  94.  
  95. sort: ['setCondition', (cb, results) => {
  96. }],
  97.  
  98. pagination: ['setCondition', (cb, results) => {
  99. }],
  100.  
  101. buildQuery: ['setCondition', (cb, results) => {
  102.  
  103. let condition = results.setCondition;
  104. let replacedOperator = {};
  105. let replacedCondition = {};
  106. let query;
  107. let lookupMap = { gt: '>', lt: '<', gte: '>=', lte: '<=' };
  108.  
  109. if (!_.isEmpty(condition)) {
  110.  
  111. // TODO: the following two lines are questionable
  112. let keysArray = Object.keys(condition);
  113. let conditionKey = condition[keysArray];
  114.  
  115. // if conditionKey is an object, and there is not an OR condition in there
  116. if (_.isObject(conditionKey) && keysArray[0].toLowerCase() !== 'or') {
  117.  
  118. // generate new conditions
  119. _.each(conditionKey, (value, key) => {
  120. key = lookupMap[key] || key;
  121. replacedOperator[key] = value;
  122. });
  123.  
  124. Async.forEachOf(condition,(value,key,cbk)=> {
  125. replacedCondition[key] = replacedOperator;
  126. cbk();
  127. });
  128.  
  129. query = model.find(replacedCondition);
  130. } else {
  131. query = model.find(condition);
  132. }
  133.  
  134. } else {
  135. query = model.find({});
  136. }
  137.  
  138. // sort
  139. if (_.isString(sort)) {
  140.  
  141. let sortArr = sort.split(' ');
  142. let sortObj = {
  143. field: sortArr[0],
  144. order: sortArr[1]
  145. };
  146.  
  147. querierSort.validate(sortObj, (err, value) => {
  148. if (err) {
  149. return reject(boom.badRequest('sort filter validation error', err));
  150. }
  151. let sortString = `${value.field} ${value.order}`;
  152.  
  153. query.sort(sortString);
  154. });
  155. }
  156.  
  157. if (_.isObject(pagination)) {
  158.  
  159. const paginationSchemas = Joi.object().keys({
  160. page: Joi.number().integer().positive().min(1),
  161. limit: Joi.number().integer().positive().min(1)
  162. });
  163. // { page: x, limit: y } pagination
  164. paginationSchemas.validate(pagination, (err, value) => {
  165. if (err) {
  166. return reject(boom.badRequest('pagination validation error', err));
  167. }
  168.  
  169. query.paginate(value);
  170. });
  171.  
  172. } else {
  173.  
  174. // skip, limit pagination
  175. Debug('limit', limit); // eslint-disable-line
  176.  
  177. if (_.isNumber(limit)) {
  178. query.limit(limit);
  179. }
  180. if (_.isNumber(skip)) {
  181. query.skip(skip);
  182. }
  183. }
  184.  
  185. return cb(null, query);
  186. }],
  187. setPopulate: ['buildQuery', (cb, results) => {
  188.  
  189. let query = results.buildQuery;
  190. if (_.isEmpty(populates)) {
  191. return cb(null, query);
  192. }
  193.  
  194. if (_.isString(populates)) {
  195. // make populates an array if it is not
  196. populates = populates.split();
  197. }
  198.  
  199. populatesSchema.validate(populates, (err, values) => {
  200. if (err) {
  201. return cb(err);
  202. }
  203. Async.each(values, (val, eachCb) => {
  204. query.populate(val);
  205. return eachCb();
  206. }, () => {
  207. cb(null, query);
  208. });
  209. });
  210.  
  211. }],
  212. execQuery: ['setPopulate', (cb, results) => results.setPopulate.exec(cb)]
  213. }, (err, results) => (err) ? reject(err) : resolve(results.execQuery));
  214. });
  215. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement