UNPKG

@hatchpad/restmon

Version:

NodeJS package that allows mongoose models to handle rest-like parameters and cursors.

207 lines (186 loc) 6.2 kB
module.exports = function(secret) { var RestmonCursor = require('./RestmonCursor')(secret); var RestmonQuery = function(restmon, mongooseQuery) { this.restmon_ = restmon; this.mongooseQuery = mongooseQuery; }; var convertSortByString = function(sort) { var splitStr, trimmedArr, sortBy; sortBy = {}; splitStr = sort.split(','); trimmedArr = []; splitStr.forEach(function(str) { trimmedArr.push(str.trim()); }); trimmedArr.forEach(function(sortClause) { if (sortClause[0] === '+') { sortBy[sortClause.substr(1, sortClause.length - 1)] = 1; } else if (sortClause[0] === '-') { sortBy[sortClause.substr(1, sortClause.length - 1)] = -1; } else { sortBy[sortClause] = 1; } }); return sortBy; }; RestmonQuery.prototype.sort = function(sort) { var key, property, finalSort, sortBy; sortBy = typeof(sort) == 'string' ? convertSortByString(sort) : sort; finalSort = {}; this.sort_ = sortBy; for (key in sortBy) { if (this.restmon_.sortables_.indexOf(key) < 0) { throw new Error('attemped to sort by a non-sortable field'); } if (this.restmon_.isIgnoreCase(key)) { finalSort['_' + key] = sortBy[key]; } else { finalSort[key] = sortBy[key]; } } this.mongooseQuery = this.mongooseQuery.sort(finalSort); return this; }; RestmonQuery.prototype.limit = function(lim) { this.mongooseQuery = this.mongooseQuery.limit(lim); return this; }; RestmonQuery.prototype.populate = function(populate, select, model, match, options) { this.mongooseQuery = this.mongooseQuery.populate(populate, select, model, match, options); return this; }; RestmonQuery.prototype.select = function(select) { this.mongooseQuery = this.mongooseQuery.select(select); return this; }; var buildCursorQuery = function(cursor, queryDirection) { var i, query, appendQueryKey, naturalDirection, sortBy, sortByKeys, key; naturalDirection = queryDirection === 'before' ? -1 : 1; sortBy = this.sort_ || {}; query = {}; sortByKeys = []; for(key in sortBy) { sortByKeys.push(key); } if (sortByKeys.length == 0) { query[this.restmon_.config_.id] = naturalDirection > 0 ? {$gt: cursor.get(this.restmon_.config_.id)} : {$lt: cursor.get(this.restmon_.config_.id)}; return query; } query.$or = []; appendQueryKey = function(queryOr, idx) { var sortProp, and, or, part, part2, field, fieldValue, rawField; part = {}; part2 = null; field = sortByKeys[idx]; if (this.restmon_.isIgnoreCase(field)) { rawField = '_' + field; fieldValue = cursor.get(field) ? cursor.get(field).toLowerCase() : cursor.get(field); } else { rawField = field; fieldValue = cursor.get(field); } if (fieldValue === undefined) { fieldValue = null; } sortProp = sortBy[field]; if (sortProp * naturalDirection > 0) { if (fieldValue === null) { part[rawField] = {$ne: fieldValue}; } else { part[rawField] = {$gt: fieldValue}; } } else { if (fieldValue === null) { part = null; } else { part[rawField] = {$lt: fieldValue}; part2 = {}; part2[rawField] = {$eq: null}; } } if (part) { queryOr.push(part); } if (part2) { queryOr.push(part2); } and = {$and: []}; queryOr.push(and); part = {}; part[rawField] = {$eq: fieldValue}; and.$and.push(part); if (idx == sortByKeys.length - 1) { part = {}; if (sortProp * naturalDirection > 0) { part[this.restmon_.config_.id] = {$gt: cursor.get(this.restmon_.config_.id)}; } else { part[this.restmon_.config_.id] = {$lt: cursor.get(this.restmon_.config_.id)}; } and.$and.push(part); return query; } else { or = {$or: []}; and.$and.push(or); return appendQueryKey.bind(this)(or.$or, idx + 1); } }; return appendQueryKey.bind(this)(query.$or, 0); }; RestmonQuery.prototype.after = function(cursor) { var cursorObj = new RestmonCursor(cursor); this.mongooseQuery._conditions.$and.push( buildCursorQuery.bind(this)(cursorObj, 'after') ); return this; }; RestmonQuery.prototype.before = function(cursor) { var cursorObj = new RestmonCursor(cursor); this.mongooseQuery._conditions.$and.push( buildCursorQuery.bind(this)(cursorObj, 'before') ); return this; }; RestmonQuery.prototype.since = function(timestamp) { var sinceClause = {}; sinceClause[this.restmon_.config_.updated] = {$gt: timestamp}; this.mongooseQuery._conditions.$and.push(sinceClause); return this; }; RestmonQuery.prototype.until = function(timestamp) { var sinceClause = {}; sinceClause[this.restmon_.config_.updated] = {$lt: timestamp}; this.mongooseQuery._conditions.$and.push(sinceClause); return this; }; RestmonQuery.prototype.exec = function(cb) { var response = {_meta: {}}; var i; return this.mongooseQuery.exec(function(err, data) { if (data && Array.isArray(data)) { response.data = data; if (data.length > 0) { response._meta.first = this.restmon_.getCursor(data[0]).encode(); response._meta.last = this.restmon_.getCursor(data[data.length - 1]).encode(); } for (i = 0; i < data.length; i++) { if (!response._meta.freshest || data[i][this.restmon_.config_.updated] > response._meta.freshest) { response._meta.freshest = data[i][this.restmon_.config_.updated]; } if (!response._meta.stalest || data[i][this.restmon_.config_.updated] < response._meta.stalest) { response._meta.stalest = data[i][this.restmon_.config_.updated]; } } } else { response.data = data; } if (cb) { cb(err, response); } }.bind(this)); }; return RestmonQuery; };