mongoose-query-parser
Advanced tools
Comparing version 1.2.1 to 1.3.0
@@ -19,3 +19,3 @@ { | ||
"--grep", | ||
"/^Tester/" | ||
"/^${fileBasenameNoExtension}/" | ||
], | ||
@@ -22,0 +22,0 @@ "console": "integratedTerminal" |
@@ -59,6 +59,15 @@ export interface ParserOptions { | ||
/** | ||
* cast populate query to object like: | ||
* populate=field1.p1,field1.p2,field2 | ||
* cast populate query to object | ||
* see mongoose doc here: https://mongoosejs.com/docs/populate.html#deep-populate | ||
* considering the following schemas: | ||
* Users => { _id, name:string, email:string, friends: [{ref: 'User'}] } | ||
* Posts => { createdBy: {ref: 'User'}, likedBy: [{ref: 'User'}], contents: string, title: string } | ||
* Example 1: | ||
* populate=createdBy.name,createdBy.email,likedBy | ||
* => | ||
* [{path: 'field1', select: 'p1 p2'}, {path: 'field2'}] | ||
* [{path: 'createdBy', select: 'name email'}, {path: 'likedBy'}] | ||
* Example 2 (deep populate): | ||
* populate=createdBy:friends.name,createdBy:friends.email,createdBy.name,createdBy.email | ||
* => | ||
* [{path: 'createdBy', select: 'name email', populate: {path: 'friends', select: 'name email'}}] | ||
* @param val | ||
@@ -65,0 +74,0 @@ */ |
@@ -119,5 +119,6 @@ "use strict"; | ||
for (var i in obj) { | ||
if (!obj.hasOwnProperty(i)) | ||
if (!obj.hasOwnProperty(i)) { | ||
continue; | ||
if (typeof obj[i] == "object") { | ||
} | ||
if (typeof obj[i] == 'object') { | ||
this.excludeFilterKeys(obj[i], blacklist); | ||
@@ -236,32 +237,52 @@ } | ||
/** | ||
* cast populate query to object like: | ||
* populate=field1.p1,field1.p2,field2 | ||
* cast populate query to object | ||
* see mongoose doc here: https://mongoosejs.com/docs/populate.html#deep-populate | ||
* considering the following schemas: | ||
* Users => { _id, name:string, email:string, friends: [{ref: 'User'}] } | ||
* Posts => { createdBy: {ref: 'User'}, likedBy: [{ref: 'User'}], contents: string, title: string } | ||
* Example 1: | ||
* populate=createdBy.name,createdBy.email,likedBy | ||
* => | ||
* [{path: 'field1', select: 'p1 p2'}, {path: 'field2'}] | ||
* [{path: 'createdBy', select: 'name email'}, {path: 'likedBy'}] | ||
* Example 2 (deep populate): | ||
* populate=createdBy:friends.name,createdBy:friends.email,createdBy.name,createdBy.email | ||
* => | ||
* [{path: 'createdBy', select: 'name email', populate: {path: 'friends', select: 'name email'}}] | ||
* @param val | ||
*/ | ||
MongooseQueryParser.prototype.castPopulate = function (val) { | ||
return val | ||
.split(',') | ||
.map(function (qry) { | ||
var _a = qry.split('.', 2), p = _a[0], s = _a[1]; | ||
return s ? { path: p, select: s } : { path: p }; | ||
}).reduce(function (prev, curr, key) { | ||
// consolidate population array | ||
var path = curr.path; | ||
var select = curr.select; | ||
var found = false; | ||
prev.forEach(function (e) { | ||
if (e.path === path) { | ||
found = true; | ||
if (select) { | ||
e.select = e.select ? (e.select + ' ' + select) : select; | ||
} | ||
var ls = val.split(',').map(function (s) { return s.split(':'); }); | ||
var populates = []; | ||
var buildPopulate = function (prop, pObj) { | ||
var _a; | ||
var _b = prop.split('.', 2), path = _b[0], select = _b[1]; | ||
if (!pObj) { | ||
pObj = populates.find(function (p) { return p.path == path; }); | ||
if (!pObj) { | ||
// create new populate query object | ||
pObj = { path: path }; | ||
populates.push(pObj); | ||
} | ||
}); | ||
if (!found) { | ||
prev.push(curr); | ||
} | ||
return prev; | ||
}, []); | ||
else { | ||
if (((_a = pObj.populate) === null || _a === void 0 ? void 0 : _a.path) !== path) { | ||
// create deep populate | ||
pObj.populate = { path: path }; | ||
} | ||
pObj = pObj.populate; | ||
} | ||
if (select) { | ||
pObj.select = pObj.select ? (pObj.select + ' ' + select) : select; | ||
} | ||
return pObj; | ||
}; | ||
for (var _i = 0, ls_1 = ls; _i < ls_1.length; _i++) { | ||
var s = ls_1[_i]; | ||
var pObj = undefined; | ||
for (var _a = 0, s_1 = s; _a < s_1.length; _a++) { | ||
var prop = s_1[_a]; | ||
pObj = buildPopulate(prop, pObj); | ||
} | ||
} | ||
return populates; | ||
}; | ||
@@ -268,0 +289,0 @@ /** |
@@ -11,38 +11,2 @@ "use strict"; | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -139,13 +103,25 @@ var mocha_1 = require("@testdeck/mocha"); | ||
Tester.prototype.populateParse = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var parser, qry, parsed; | ||
return __generator(this, function (_a) { | ||
parser = new _1.MongooseQueryParser(); | ||
qry = '_id=1&populate=serviceSalesOrders,customer.category,customer.name'; | ||
parsed = parser.parse(qry); | ||
chai_1.assert.isOk(parsed.populate.length === 2); | ||
return [2 /*return*/]; | ||
}); | ||
}); | ||
var parser = new _1.MongooseQueryParser(); | ||
var qry = '_id=1&populate=serviceSalesOrders,customer.category,customer.name'; | ||
var parsed = parser.parse(qry); | ||
chai_1.assert.isOk(parsed.populate.length === 2); | ||
}; | ||
Tester.prototype.deepPopulateParse = function () { | ||
var parser = new _1.MongooseQueryParser(); | ||
var qry = '_id=1&populate=p1,p2:p3.p4,p2:p3.p5,p6:p7'; | ||
var parsed = parser.parse(qry); | ||
chai_1.assert.isNotEmpty(parsed.populate); | ||
chai_1.assert.isTrue(parsed.populate.length === 3); | ||
for (var _i = 0, _a = parsed.populate; _i < _a.length; _i++) { | ||
var p = _a[_i]; | ||
if (p.path === 'p2') { | ||
chai_1.assert.isTrue(p.populate.path === 'p3'); | ||
chai_1.assert.isTrue(p.populate.select.includes('p4')); | ||
chai_1.assert.isTrue(p.populate.select.includes('p5')); | ||
} | ||
if (p.path === 'p6') { | ||
chai_1.assert.isTrue(p.populate.path === 'p7'); | ||
} | ||
} | ||
}; | ||
Tester.prototype.builtInCastersTest = function () { | ||
@@ -247,5 +223,11 @@ var parser = new _1.MongooseQueryParser(); | ||
__metadata("design:paramtypes", []), | ||
__metadata("design:returntype", Promise) | ||
__metadata("design:returntype", void 0) | ||
], Tester.prototype, "populateParse", null); | ||
__decorate([ | ||
mocha_1.test('should parse deep populate'), | ||
__metadata("design:type", Function), | ||
__metadata("design:paramtypes", []), | ||
__metadata("design:returntype", void 0) | ||
], Tester.prototype, "deepPopulateParse", null); | ||
__decorate([ | ||
mocha_1.test('should parse built in casters'), | ||
@@ -275,3 +257,3 @@ __metadata("design:type", Function), | ||
Tester = __decorate([ | ||
mocha_1.suite('Tester') | ||
mocha_1.suite('test.spec') | ||
], Tester); | ||
@@ -278,0 +260,0 @@ return Tester; |
{ | ||
"name": "mongoose-query-parser", | ||
"version": "1.2.1", | ||
"version": "1.3.0", | ||
"description": "Convert url query string to MongooseJs friendly query object including advanced filtering, sorting, population, string template, type casting and many more...", | ||
@@ -40,2 +40,3 @@ "main": "./lib/index.js", | ||
"mocha": "^8.4.0", | ||
"mongoose": "^6.2.10", | ||
"rimraf": "^3.0.2", | ||
@@ -42,0 +43,0 @@ "ts-node": "^10.0.0", |
@@ -18,3 +18,3 @@ # mongoose-query-parser | ||
## Installation | ||
``` | ||
```sh | ||
npm install mongoose-query-parser --save | ||
@@ -26,3 +26,3 @@ ``` | ||
### API | ||
``` | ||
```js | ||
import { MongooseQueryParser } from 'mongoose-query-parser'; | ||
@@ -56,16 +56,15 @@ | ||
const parsed = parser.parse('${vip}&status=${sentStatus}×tamp>2017-10-01&author.firstName=/john/i&limit=100&skip=50&sort=-timestamp&select=name&populate=children.firstName,children.lastName', predefined); | ||
{ | ||
select: { name : 1 }, | ||
populate: [{ path: 'children', select: 'firstName lastName' }], | ||
sort: { timestamp: -1 }, | ||
skip: 50, | ||
limit: 100, | ||
filter: { | ||
name: {{ $in: ['Google', 'Microsoft', 'NodeJs'] }}, | ||
status: 'sent', | ||
timestamp: { '$gt': 2017-09-30T14:00:00.000Z }, | ||
'author.firstName': /john/i | ||
} | ||
} | ||
// { | ||
// select: { name : 1 }, | ||
// populate: [{ path: 'children', select: 'firstName lastName' }], | ||
// sort: { timestamp: -1 }, | ||
// skip: 50, | ||
// limit: 100, | ||
// filter: { | ||
// name: {{ $in: ['Google', 'Microsoft', 'NodeJs'] }}, | ||
// status: 'sent', | ||
// timestamp: { '$gt': 2017-09-30T14:00:00.000Z }, | ||
// 'author.firstName': /john/i | ||
// } | ||
// } | ||
``` | ||
@@ -111,13 +110,20 @@ | ||
- Useful to populate sub-document(s) in query. Works with `MongooseJS`. Please see [Mongoose Populate](http://mongoosejs.com/docs/populate.html) for more details | ||
- Allows to populate only selected fields | ||
- Supports deep populate with delimiter ":" | ||
- Below example & `test-populate.spec.ts` for more details | ||
- See [Mongoose Docs](https://mongoosejs.com/docs/populate.html#deep-populate) | ||
- Allows to populate with only selected fields | ||
- Default operator key is `populate` | ||
```js | ||
parser.parse('populate=class,school.name'); | ||
parser.parse('populate=createdBy:friends.name,createdBy.name,likedBy.name'); | ||
// { | ||
// populate: [{ | ||
// path: 'class' | ||
// path: 'createdBy', | ||
// select: 'name', | ||
// populate: { | ||
// path: 'name', | ||
// } | ||
// }, { | ||
// path: 'school', | ||
// select: 'name' | ||
// path: 'likedBy', | ||
// select: 'name', | ||
// }] | ||
@@ -124,0 +130,0 @@ // } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
61554
14
1108
336
13