UNPKG

24.8 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (global = global || self, factory(global.sift = {}));
5}(this, (function (exports) { 'use strict';
6
7 /*! *****************************************************************************
8 Copyright (c) Microsoft Corporation.
9
10 Permission to use, copy, modify, and/or distribute this software for any
11 purpose with or without fee is hereby granted.
12
13 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
14 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15 AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
16 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
18 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 PERFORMANCE OF THIS SOFTWARE.
20 ***************************************************************************** */
21 /* global Reflect, Promise */
22
23 var extendStatics = function(d, b) {
24 extendStatics = Object.setPrototypeOf ||
25 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
26 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
27 return extendStatics(d, b);
28 };
29
30 function __extends(d, b) {
31 extendStatics(d, b);
32 function __() { this.constructor = d; }
33 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
34 }
35
36 var typeChecker = function (type) {
37 var typeString = "[object " + type + "]";
38 return function (value) {
39 return getClassName(value) === typeString;
40 };
41 };
42 var getClassName = function (value) { return Object.prototype.toString.call(value); };
43 var comparable = function (value) {
44 if (value instanceof Date) {
45 return value.getTime();
46 }
47 else if (isArray(value)) {
48 return value.map(comparable);
49 }
50 else if (value && typeof value.toJSON === "function") {
51 return value.toJSON();
52 }
53 return value;
54 };
55 var isArray = typeChecker("Array");
56 var isObject = typeChecker("Object");
57 var isFunction = typeChecker("Function");
58 var isVanillaObject = function (value) {
59 return (value &&
60 (value.constructor === Object ||
61 value.constructor === Array ||
62 value.constructor.toString() === "function Object() { [native code] }" ||
63 value.constructor.toString() === "function Array() { [native code] }") &&
64 !value.toJSON);
65 };
66 var equals = function (a, b) {
67 if (a == null && a == b) {
68 return true;
69 }
70 if (a === b) {
71 return true;
72 }
73 if (Object.prototype.toString.call(a) !== Object.prototype.toString.call(b)) {
74 return false;
75 }
76 if (isArray(a)) {
77 if (a.length !== b.length) {
78 return false;
79 }
80 for (var i = 0, length_1 = a.length; i < length_1; i++) {
81 if (!equals(a[i], b[i]))
82 return false;
83 }
84 return true;
85 }
86 else if (isObject(a)) {
87 if (Object.keys(a).length !== Object.keys(b).length) {
88 return false;
89 }
90 for (var key in a) {
91 if (!equals(a[key], b[key]))
92 return false;
93 }
94 return true;
95 }
96 return false;
97 };
98
99 /**
100 * Walks through each value given the context - used for nested operations. E.g:
101 * { "person.address": { $eq: "blarg" }}
102 */
103 var walkKeyPathValues = function (item, keyPath, next, depth, key, owner) {
104 var currentKey = keyPath[depth];
105 // if array, then try matching. Might fall through for cases like:
106 // { $eq: [1, 2, 3] }, [ 1, 2, 3 ].
107 if (isArray(item) && isNaN(Number(currentKey))) {
108 for (var i = 0, length_1 = item.length; i < length_1; i++) {
109 // if FALSE is returned, then terminate walker. For operations, this simply
110 // means that the search critera was met.
111 if (!walkKeyPathValues(item[i], keyPath, next, depth, i, item)) {
112 return false;
113 }
114 }
115 }
116 if (depth === keyPath.length || item == null) {
117 return next(item, key, owner);
118 }
119 return walkKeyPathValues(item[currentKey], keyPath, next, depth + 1, currentKey, item);
120 };
121 var BaseOperation = /** @class */ (function () {
122 function BaseOperation(params, owneryQuery, options) {
123 this.params = params;
124 this.owneryQuery = owneryQuery;
125 this.options = options;
126 this.init();
127 }
128 BaseOperation.prototype.init = function () { };
129 BaseOperation.prototype.reset = function () {
130 this.done = false;
131 this.success = false;
132 };
133 return BaseOperation;
134 }());
135 var GroupOperation = /** @class */ (function (_super) {
136 __extends(GroupOperation, _super);
137 function GroupOperation(params, owneryQuery, options, _children) {
138 var _this = _super.call(this, params, owneryQuery, options) || this;
139 _this._children = _children;
140 return _this;
141 }
142 /**
143 */
144 GroupOperation.prototype.reset = function () {
145 this.success = false;
146 this.done = false;
147 for (var i = 0, length_2 = this._children.length; i < length_2; i++) {
148 this._children[i].reset();
149 }
150 };
151 /**
152 */
153 GroupOperation.prototype.childrenNext = function (item, key, owner) {
154 var done = true;
155 var success = true;
156 for (var i = 0, length_3 = this._children.length; i < length_3; i++) {
157 var childOperation = this._children[i];
158 childOperation.next(item, key, owner);
159 if (!childOperation.success) {
160 success = false;
161 }
162 if (childOperation.done) {
163 if (!childOperation.success) {
164 break;
165 }
166 }
167 else {
168 done = false;
169 }
170 }
171 // console.log("DONE", this.params, done, success);
172 this.done = done;
173 this.success = success;
174 };
175 return GroupOperation;
176 }(BaseOperation));
177 var QueryOperation = /** @class */ (function (_super) {
178 __extends(QueryOperation, _super);
179 function QueryOperation() {
180 return _super !== null && _super.apply(this, arguments) || this;
181 }
182 /**
183 */
184 QueryOperation.prototype.next = function (item, key, parent) {
185 this.childrenNext(item, key, parent);
186 };
187 return QueryOperation;
188 }(GroupOperation));
189 var NestedOperation = /** @class */ (function (_super) {
190 __extends(NestedOperation, _super);
191 function NestedOperation(keyPath, params, owneryQuery, options, children) {
192 var _this = _super.call(this, params, owneryQuery, options, children) || this;
193 _this.keyPath = keyPath;
194 /**
195 */
196 _this._nextNestedValue = function (value, key, owner) {
197 _this.childrenNext(value, key, owner);
198 return !_this.done;
199 };
200 return _this;
201 }
202 /**
203 */
204 NestedOperation.prototype.next = function (item, key, parent) {
205 walkKeyPathValues(item, this.keyPath, this._nextNestedValue, 0, key, parent);
206 };
207 return NestedOperation;
208 }(GroupOperation));
209 var createTester = function (a, compare) {
210 if (a instanceof Function) {
211 return a;
212 }
213 if (a instanceof RegExp) {
214 return function (b) {
215 var result = typeof b === "string" && a.test(b);
216 a.lastIndex = 0;
217 return result;
218 };
219 }
220 var comparableA = comparable(a);
221 return function (b) { return compare(comparableA, comparable(b)); };
222 };
223 var EqualsOperation = /** @class */ (function (_super) {
224 __extends(EqualsOperation, _super);
225 function EqualsOperation() {
226 return _super !== null && _super.apply(this, arguments) || this;
227 }
228 EqualsOperation.prototype.init = function () {
229 this._test = createTester(this.params, this.options.compare);
230 };
231 EqualsOperation.prototype.next = function (item, key, parent) {
232 if (this._test(item, key, parent)) {
233 this.done = true;
234 this.success = true;
235 }
236 };
237 return EqualsOperation;
238 }(BaseOperation));
239 var createEqualsOperation = function (params, owneryQuery, options) { return new EqualsOperation(params, owneryQuery, options); };
240 var NopeOperation = /** @class */ (function (_super) {
241 __extends(NopeOperation, _super);
242 function NopeOperation() {
243 return _super !== null && _super.apply(this, arguments) || this;
244 }
245 NopeOperation.prototype.next = function () {
246 this.done = true;
247 this.success = false;
248 };
249 return NopeOperation;
250 }(BaseOperation));
251 var numericalOperationCreator = function (createNumericalOperation) { return function (params, owneryQuery, options) {
252 if (params == null) {
253 return new NopeOperation(params, owneryQuery, options);
254 }
255 return createNumericalOperation(params, owneryQuery, options);
256 }; };
257 var numericalOperation = function (createTester) {
258 return numericalOperationCreator(function (params, owneryQuery, options) {
259 var typeofParams = typeof comparable(params);
260 var test = createTester(params);
261 return new EqualsOperation(function (b) {
262 return typeof comparable(b) === typeofParams && test(b);
263 }, owneryQuery, options);
264 });
265 };
266 var createOperation = function (name, params, parentQuery, options) {
267 var operationCreator = options.operations[name];
268 if (!operationCreator) {
269 throw new Error("Unsupported operation: " + name);
270 }
271 return operationCreator(params, parentQuery, options);
272 };
273 var containsOperation = function (query) {
274 for (var key in query) {
275 if (key.charAt(0) === "$")
276 return true;
277 }
278 return false;
279 };
280 var createNestedOperation = function (keyPath, nestedQuery, owneryQuery, options) {
281 if (containsOperation(nestedQuery)) {
282 var _a = createQueryOperations(nestedQuery, options), selfOperations = _a[0], nestedOperations = _a[1];
283 if (nestedOperations.length) {
284 throw new Error("Property queries must contain only operations, or exact objects.");
285 }
286 return new NestedOperation(keyPath, nestedQuery, owneryQuery, options, selfOperations);
287 }
288 return new NestedOperation(keyPath, nestedQuery, owneryQuery, options, [
289 new EqualsOperation(nestedQuery, owneryQuery, options)
290 ]);
291 };
292 var createQueryOperation = function (query, owneryQuery, options) {
293 var _a = createQueryOperations(query, options), selfOperations = _a[0], nestedOperations = _a[1];
294 var ops = [];
295 if (selfOperations.length) {
296 ops.push(new NestedOperation([], query, owneryQuery, options, selfOperations));
297 }
298 ops.push.apply(ops, nestedOperations);
299 if (ops.length === 1) {
300 return ops[0];
301 }
302 return new QueryOperation(query, owneryQuery, options, ops);
303 };
304 var createQueryOperations = function (query, options) {
305 var selfOperations = [];
306 var nestedOperations = [];
307 if (!isVanillaObject(query)) {
308 selfOperations.push(new EqualsOperation(query, query, options));
309 return [selfOperations, nestedOperations];
310 }
311 for (var key in query) {
312 if (key.charAt(0) === "$") {
313 var op = createOperation(key, query[key], query, options);
314 // probably just a flag for another operation (like $options)
315 if (op != null) {
316 selfOperations.push(op);
317 }
318 }
319 else {
320 nestedOperations.push(createNestedOperation(key.split("."), query[key], query, options));
321 }
322 }
323 return [selfOperations, nestedOperations];
324 };
325 var createQueryTester = function (query, _a) {
326 var _b = _a === void 0 ? {} : _a, compare = _b.compare, operations = _b.operations;
327 var operation = createQueryOperation(query, null, {
328 compare: compare || equals,
329 operations: Object.assign({}, operations || {})
330 });
331 return function (item, key, owner) {
332 operation.reset();
333 operation.next(item, key, owner);
334 return operation.success;
335 };
336 };
337
338 var $Ne = /** @class */ (function (_super) {
339 __extends($Ne, _super);
340 function $Ne() {
341 return _super !== null && _super.apply(this, arguments) || this;
342 }
343 $Ne.prototype.init = function () {
344 this._test = createTester(this.params, this.options.compare);
345 };
346 $Ne.prototype.reset = function () {
347 _super.prototype.reset.call(this);
348 this.success = true;
349 };
350 $Ne.prototype.next = function (item) {
351 if (this._test(item)) {
352 this.done = true;
353 this.success = false;
354 }
355 };
356 return $Ne;
357 }(BaseOperation));
358 // https://docs.mongodb.com/manual/reference/operator/query/elemMatch/
359 var $ElemMatch = /** @class */ (function (_super) {
360 __extends($ElemMatch, _super);
361 function $ElemMatch() {
362 return _super !== null && _super.apply(this, arguments) || this;
363 }
364 $ElemMatch.prototype.init = function () {
365 this._queryOperation = createQueryOperation(this.params, this.owneryQuery, this.options);
366 };
367 $ElemMatch.prototype.reset = function () {
368 this._queryOperation.reset();
369 };
370 $ElemMatch.prototype.next = function (item, key, owner) {
371 this._queryOperation.reset();
372 if (isArray(owner)) {
373 this._queryOperation.next(item, key, owner);
374 this.done = this._queryOperation.done || key === owner.length - 1;
375 this.success = this._queryOperation.success;
376 }
377 else {
378 this.done = true;
379 this.success = false;
380 }
381 };
382 return $ElemMatch;
383 }(BaseOperation));
384 var $Not = /** @class */ (function (_super) {
385 __extends($Not, _super);
386 function $Not() {
387 return _super !== null && _super.apply(this, arguments) || this;
388 }
389 $Not.prototype.init = function () {
390 this._queryOperation = createQueryOperation(this.params, this.owneryQuery, this.options);
391 };
392 $Not.prototype.reset = function () {
393 this._queryOperation.reset();
394 };
395 $Not.prototype.next = function (item, key, owner) {
396 this._queryOperation.next(item, key, owner);
397 this.done = this._queryOperation.done;
398 this.success = !this._queryOperation.success;
399 };
400 return $Not;
401 }(BaseOperation));
402 var $Or = /** @class */ (function (_super) {
403 __extends($Or, _super);
404 function $Or() {
405 return _super !== null && _super.apply(this, arguments) || this;
406 }
407 $Or.prototype.init = function () {
408 var _this = this;
409 this._ops = this.params.map(function (op) {
410 return createQueryOperation(op, null, _this.options);
411 });
412 };
413 $Or.prototype.reset = function () {
414 this.done = false;
415 this.success = false;
416 for (var i = 0, length_1 = this._ops.length; i < length_1; i++) {
417 this._ops[i].reset();
418 }
419 };
420 $Or.prototype.next = function (item, key, owner) {
421 var done = false;
422 var success = false;
423 for (var i = 0, length_2 = this._ops.length; i < length_2; i++) {
424 var op = this._ops[i];
425 op.next(item, key, owner);
426 if (op.success) {
427 done = true;
428 success = op.success;
429 break;
430 }
431 }
432 this.success = success;
433 this.done = done;
434 };
435 return $Or;
436 }(BaseOperation));
437 var $Nor = /** @class */ (function (_super) {
438 __extends($Nor, _super);
439 function $Nor() {
440 return _super !== null && _super.apply(this, arguments) || this;
441 }
442 $Nor.prototype.next = function (item, key, owner) {
443 _super.prototype.next.call(this, item, key, owner);
444 this.success = !this.success;
445 };
446 return $Nor;
447 }($Or));
448 var $In = /** @class */ (function (_super) {
449 __extends($In, _super);
450 function $In() {
451 return _super !== null && _super.apply(this, arguments) || this;
452 }
453 $In.prototype.init = function () {
454 var _this = this;
455 this._testers = this.params.map(function (value) {
456 if (containsOperation(value)) {
457 throw new Error("cannot nest $ under " + _this.constructor.name.toLowerCase());
458 }
459 return createTester(value, _this.options.compare);
460 });
461 };
462 $In.prototype.next = function (item, key, owner) {
463 var done = false;
464 var success = false;
465 for (var i = 0, length_3 = this._testers.length; i < length_3; i++) {
466 var test = this._testers[i];
467 if (test(item)) {
468 done = true;
469 success = true;
470 break;
471 }
472 }
473 this.success = success;
474 this.done = done;
475 };
476 return $In;
477 }(BaseOperation));
478 var $Nin = /** @class */ (function (_super) {
479 __extends($Nin, _super);
480 function $Nin() {
481 return _super !== null && _super.apply(this, arguments) || this;
482 }
483 $Nin.prototype.next = function (item, key, owner) {
484 _super.prototype.next.call(this, item, key, owner);
485 this.success = !this.success;
486 };
487 return $Nin;
488 }($In));
489 var $Exists = /** @class */ (function (_super) {
490 __extends($Exists, _super);
491 function $Exists() {
492 return _super !== null && _super.apply(this, arguments) || this;
493 }
494 $Exists.prototype.next = function (item, key, owner) {
495 if (owner.hasOwnProperty(key) === this.params) {
496 this.done = true;
497 this.success = true;
498 }
499 };
500 return $Exists;
501 }(BaseOperation));
502 var $And = /** @class */ (function (_super) {
503 __extends($And, _super);
504 function $And(params, owneryQuery, options) {
505 return _super.call(this, params, owneryQuery, options, params.map(function (query) { return createQueryOperation(query, owneryQuery, options); })) || this;
506 }
507 $And.prototype.next = function (item, key, owner) {
508 this.childrenNext(item, key, owner);
509 };
510 return $And;
511 }(GroupOperation));
512 var $eq = function (params, owneryQuery, options) {
513 return new EqualsOperation(params, owneryQuery, options);
514 };
515 var $ne = function (params, owneryQuery, options) {
516 return new $Ne(params, owneryQuery, options);
517 };
518 var $or = function (params, owneryQuery, options) { return new $Or(params, owneryQuery, options); };
519 var $nor = function (params, owneryQuery, options) { return new $Nor(params, owneryQuery, options); };
520 var $elemMatch = function (params, owneryQuery, options) { return new $ElemMatch(params, owneryQuery, options); };
521 var $nin = function (params, owneryQuery, options) {
522 return new $Nin(params, owneryQuery, options);
523 };
524 var $in = function (params, owneryQuery, options) {
525 return new $In(params, owneryQuery, options);
526 };
527 var $lt = numericalOperation(function (params) { return function (b) { return b < params; }; });
528 var $lte = numericalOperation(function (params) { return function (b) { return b <= params; }; });
529 var $gt = numericalOperation(function (params) { return function (b) { return b > params; }; });
530 var $gte = numericalOperation(function (params) { return function (b) { return b >= params; }; });
531 var $mod = function (_a, owneryQuery, options) {
532 var mod = _a[0], equalsValue = _a[1];
533 return new EqualsOperation(function (b) { return comparable(b) % mod === equalsValue; }, owneryQuery, options);
534 };
535 var $exists = function (params, owneryQuery, options) { return new $Exists(params, owneryQuery, options); };
536 var $regex = function (pattern, owneryQuery, options) {
537 return new EqualsOperation(new RegExp(pattern, owneryQuery.$options), owneryQuery, options);
538 };
539 var $not = function (params, owneryQuery, options) {
540 return new $Not(params, owneryQuery, options);
541 };
542 var $type = function (clazz, owneryQuery, options) {
543 return new EqualsOperation(function (b) { return (b != null ? b instanceof clazz || b.constructor === clazz : false); }, owneryQuery, options);
544 };
545 var $and = function (params, ownerQuery, options) { return new $And(params, ownerQuery, options); };
546 var $all = $and;
547 var $size = function (params, ownerQuery, options) { return new EqualsOperation(function (b) { return b && b.length === params; }, ownerQuery, options); };
548 var $options = function () { return null; };
549 var $where = function (params, ownerQuery, options) {
550 var test;
551 if (isFunction(params)) {
552 test = params;
553 }
554 else if (!process.env.CSP_ENABLED) {
555 test = new Function("obj", "return " + params);
556 }
557 else {
558 throw new Error("In CSP mode, sift does not support strings in \"$where\" condition");
559 }
560 return new EqualsOperation(function (b) { return test.bind(b)(b); }, ownerQuery, options);
561 };
562
563 var defaultOperations = /*#__PURE__*/Object.freeze({
564 __proto__: null,
565 $eq: $eq,
566 $ne: $ne,
567 $or: $or,
568 $nor: $nor,
569 $elemMatch: $elemMatch,
570 $nin: $nin,
571 $in: $in,
572 $lt: $lt,
573 $lte: $lte,
574 $gt: $gt,
575 $gte: $gte,
576 $mod: $mod,
577 $exists: $exists,
578 $regex: $regex,
579 $not: $not,
580 $type: $type,
581 $and: $and,
582 $all: $all,
583 $size: $size,
584 $options: $options,
585 $where: $where
586 });
587
588 var createDefaultQueryTester = function (query, _a) {
589 var _b = _a === void 0 ? {} : _a, compare = _b.compare, operations = _b.operations;
590 return createQueryTester(query, {
591 compare: compare,
592 operations: Object.assign({}, defaultOperations, operations)
593 });
594 };
595
596 exports.$all = $all;
597 exports.$and = $and;
598 exports.$elemMatch = $elemMatch;
599 exports.$eq = $eq;
600 exports.$exists = $exists;
601 exports.$gt = $gt;
602 exports.$gte = $gte;
603 exports.$in = $in;
604 exports.$lt = $lt;
605 exports.$lte = $lte;
606 exports.$mod = $mod;
607 exports.$ne = $ne;
608 exports.$nin = $nin;
609 exports.$nor = $nor;
610 exports.$not = $not;
611 exports.$options = $options;
612 exports.$or = $or;
613 exports.$regex = $regex;
614 exports.$size = $size;
615 exports.$type = $type;
616 exports.$where = $where;
617 exports.EqualsOperation = EqualsOperation;
618 exports.createEqualsOperation = createEqualsOperation;
619 exports.createQueryTester = createQueryTester;
620 exports.default = createDefaultQueryTester;
621
622 Object.defineProperty(exports, '__esModule', { value: true });
623
624})));
625//# sourceMappingURL=index.js.map