UNPKG

26.5 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 NamedBaseOperation = /** @class */ (function (_super) {
136 __extends(NamedBaseOperation, _super);
137 function NamedBaseOperation(params, owneryQuery, options, name) {
138 var _this = _super.call(this, params, owneryQuery, options) || this;
139 _this.name = name;
140 return _this;
141 }
142 return NamedBaseOperation;
143 }(BaseOperation));
144 var GroupOperation = /** @class */ (function (_super) {
145 __extends(GroupOperation, _super);
146 function GroupOperation(params, owneryQuery, options, children) {
147 var _this = _super.call(this, params, owneryQuery, options) || this;
148 _this.children = children;
149 return _this;
150 }
151 /**
152 */
153 GroupOperation.prototype.reset = function () {
154 this.success = false;
155 this.done = false;
156 for (var i = 0, length_2 = this.children.length; i < length_2; i++) {
157 this.children[i].reset();
158 }
159 };
160 /**
161 */
162 GroupOperation.prototype.childrenNext = function (item, key, owner) {
163 var done = true;
164 var success = true;
165 for (var i = 0, length_3 = this.children.length; i < length_3; i++) {
166 var childOperation = this.children[i];
167 childOperation.next(item, key, owner);
168 if (!childOperation.success) {
169 success = false;
170 }
171 if (childOperation.done) {
172 if (!childOperation.success) {
173 break;
174 }
175 }
176 else {
177 done = false;
178 }
179 }
180 // console.log("DONE", this.params, done, success);
181 this.done = done;
182 this.success = success;
183 };
184 return GroupOperation;
185 }(BaseOperation));
186 var NamedGroupOperation = /** @class */ (function (_super) {
187 __extends(NamedGroupOperation, _super);
188 function NamedGroupOperation(params, owneryQuery, options, children, name) {
189 var _this = _super.call(this, params, owneryQuery, options, children) || this;
190 _this.name = name;
191 return _this;
192 }
193 return NamedGroupOperation;
194 }(GroupOperation));
195 var QueryOperation = /** @class */ (function (_super) {
196 __extends(QueryOperation, _super);
197 function QueryOperation() {
198 return _super !== null && _super.apply(this, arguments) || this;
199 }
200 /**
201 */
202 QueryOperation.prototype.next = function (item, key, parent) {
203 this.childrenNext(item, key, parent);
204 };
205 return QueryOperation;
206 }(GroupOperation));
207 var NestedOperation = /** @class */ (function (_super) {
208 __extends(NestedOperation, _super);
209 function NestedOperation(keyPath, params, owneryQuery, options, children) {
210 var _this = _super.call(this, params, owneryQuery, options, children) || this;
211 _this.keyPath = keyPath;
212 /**
213 */
214 _this._nextNestedValue = function (value, key, owner) {
215 _this.childrenNext(value, key, owner);
216 return !_this.done;
217 };
218 return _this;
219 }
220 /**
221 */
222 NestedOperation.prototype.next = function (item, key, parent) {
223 walkKeyPathValues(item, this.keyPath, this._nextNestedValue, 0, key, parent);
224 };
225 return NestedOperation;
226 }(GroupOperation));
227 var createTester = function (a, compare) {
228 if (a instanceof Function) {
229 return a;
230 }
231 if (a instanceof RegExp) {
232 return function (b) {
233 var result = typeof b === "string" && a.test(b);
234 a.lastIndex = 0;
235 return result;
236 };
237 }
238 var comparableA = comparable(a);
239 return function (b) { return compare(comparableA, comparable(b)); };
240 };
241 var EqualsOperation = /** @class */ (function (_super) {
242 __extends(EqualsOperation, _super);
243 function EqualsOperation() {
244 return _super !== null && _super.apply(this, arguments) || this;
245 }
246 EqualsOperation.prototype.init = function () {
247 this._test = createTester(this.params, this.options.compare);
248 };
249 EqualsOperation.prototype.next = function (item, key, parent) {
250 if (this._test(item, key, parent) &&
251 (!parent || parent.hasOwnProperty(key))) {
252 this.done = true;
253 this.success = true;
254 }
255 };
256 return EqualsOperation;
257 }(BaseOperation));
258 var createEqualsOperation = function (params, owneryQuery, options) { return new EqualsOperation(params, owneryQuery, options); };
259 var NopeOperation = /** @class */ (function (_super) {
260 __extends(NopeOperation, _super);
261 function NopeOperation() {
262 return _super !== null && _super.apply(this, arguments) || this;
263 }
264 NopeOperation.prototype.next = function () {
265 this.done = true;
266 this.success = false;
267 };
268 return NopeOperation;
269 }(BaseOperation));
270 var numericalOperationCreator = function (createNumericalOperation) { return function (params, owneryQuery, options, name) {
271 if (params == null) {
272 return new NopeOperation(params, owneryQuery, options);
273 }
274 return createNumericalOperation(params, owneryQuery, options, name);
275 }; };
276 var numericalOperation = function (createTester) {
277 return numericalOperationCreator(function (params, owneryQuery, options) {
278 var typeofParams = typeof comparable(params);
279 var test = createTester(params);
280 return new EqualsOperation(function (b) {
281 return typeof comparable(b) === typeofParams && test(b);
282 }, owneryQuery, options);
283 });
284 };
285 var createNamedOperation = function (name, params, parentQuery, options) {
286 var operationCreator = options.operations[name];
287 if (!operationCreator) {
288 throw new Error("Unsupported operation: " + name);
289 }
290 return operationCreator(params, parentQuery, options, name);
291 };
292 var containsOperation = function (query) {
293 for (var key in query) {
294 if (key.charAt(0) === "$")
295 return true;
296 }
297 return false;
298 };
299 var createNestedOperation = function (keyPath, nestedQuery, owneryQuery, options) {
300 if (containsOperation(nestedQuery)) {
301 var _a = createQueryOperations(nestedQuery, options), selfOperations = _a[0], nestedOperations = _a[1];
302 if (nestedOperations.length) {
303 throw new Error("Property queries must contain only operations, or exact objects.");
304 }
305 return new NestedOperation(keyPath, nestedQuery, owneryQuery, options, selfOperations);
306 }
307 return new NestedOperation(keyPath, nestedQuery, owneryQuery, options, [
308 new EqualsOperation(nestedQuery, owneryQuery, options)
309 ]);
310 };
311 var createQueryOperation = function (query, owneryQuery, _a) {
312 if (owneryQuery === void 0) { owneryQuery = null; }
313 var _b = _a === void 0 ? {} : _a, compare = _b.compare, operations = _b.operations;
314 var options = {
315 compare: compare || equals,
316 operations: Object.assign({}, operations || {})
317 };
318 var _c = createQueryOperations(query, options), selfOperations = _c[0], nestedOperations = _c[1];
319 var ops = [];
320 if (selfOperations.length) {
321 ops.push(new NestedOperation([], query, owneryQuery, options, selfOperations));
322 }
323 ops.push.apply(ops, nestedOperations);
324 if (ops.length === 1) {
325 return ops[0];
326 }
327 return new QueryOperation(query, owneryQuery, options, ops);
328 };
329 var createQueryOperations = function (query, options) {
330 var selfOperations = [];
331 var nestedOperations = [];
332 if (!isVanillaObject(query)) {
333 selfOperations.push(new EqualsOperation(query, query, options));
334 return [selfOperations, nestedOperations];
335 }
336 for (var key in query) {
337 if (key.charAt(0) === "$") {
338 var op = createNamedOperation(key, query[key], query, options);
339 // probably just a flag for another operation (like $options)
340 if (op != null) {
341 selfOperations.push(op);
342 }
343 }
344 else {
345 nestedOperations.push(createNestedOperation(key.split("."), query[key], query, options));
346 }
347 }
348 return [selfOperations, nestedOperations];
349 };
350 var createOperationTester = function (operation) { return function (item, key, owner) {
351 operation.reset();
352 operation.next(item, key, owner);
353 return operation.success;
354 }; };
355 var createQueryTester = function (query, options) {
356 if (options === void 0) { options = {}; }
357 return createOperationTester(createQueryOperation(query, null, options));
358 };
359
360 var $Ne = /** @class */ (function (_super) {
361 __extends($Ne, _super);
362 function $Ne() {
363 return _super !== null && _super.apply(this, arguments) || this;
364 }
365 $Ne.prototype.init = function () {
366 this._test = createTester(this.params, this.options.compare);
367 };
368 $Ne.prototype.reset = function () {
369 _super.prototype.reset.call(this);
370 this.success = true;
371 };
372 $Ne.prototype.next = function (item) {
373 if (this._test(item)) {
374 this.done = true;
375 this.success = false;
376 }
377 };
378 return $Ne;
379 }(NamedBaseOperation));
380 // https://docs.mongodb.com/manual/reference/operator/query/elemMatch/
381 var $ElemMatch = /** @class */ (function (_super) {
382 __extends($ElemMatch, _super);
383 function $ElemMatch() {
384 return _super !== null && _super.apply(this, arguments) || this;
385 }
386 $ElemMatch.prototype.init = function () {
387 this._queryOperation = createQueryOperation(this.params, this.owneryQuery, this.options);
388 };
389 $ElemMatch.prototype.reset = function () {
390 this._queryOperation.reset();
391 };
392 $ElemMatch.prototype.next = function (item, key, owner) {
393 this._queryOperation.reset();
394 if (isArray(owner)) {
395 this._queryOperation.next(item, key, owner);
396 this.done =
397 this.done || this._queryOperation.done || key === owner.length - 1;
398 this.success = this.success || this._queryOperation.success;
399 }
400 else {
401 this.done = true;
402 this.success = false;
403 }
404 };
405 return $ElemMatch;
406 }(NamedBaseOperation));
407 var $Not = /** @class */ (function (_super) {
408 __extends($Not, _super);
409 function $Not() {
410 return _super !== null && _super.apply(this, arguments) || this;
411 }
412 $Not.prototype.init = function () {
413 this._queryOperation = createQueryOperation(this.params, this.owneryQuery, this.options);
414 };
415 $Not.prototype.reset = function () {
416 this._queryOperation.reset();
417 };
418 $Not.prototype.next = function (item, key, owner) {
419 this._queryOperation.next(item, key, owner);
420 this.done = this._queryOperation.done;
421 this.success = !this._queryOperation.success;
422 };
423 return $Not;
424 }(NamedBaseOperation));
425 var $Or = /** @class */ (function (_super) {
426 __extends($Or, _super);
427 function $Or() {
428 return _super !== null && _super.apply(this, arguments) || this;
429 }
430 $Or.prototype.init = function () {
431 var _this = this;
432 this._ops = this.params.map(function (op) {
433 return createQueryOperation(op, null, _this.options);
434 });
435 };
436 $Or.prototype.reset = function () {
437 this.done = false;
438 this.success = false;
439 for (var i = 0, length_1 = this._ops.length; i < length_1; i++) {
440 this._ops[i].reset();
441 }
442 };
443 $Or.prototype.next = function (item, key, owner) {
444 var done = false;
445 var success = false;
446 for (var i = 0, length_2 = this._ops.length; i < length_2; i++) {
447 var op = this._ops[i];
448 op.next(item, key, owner);
449 if (op.success) {
450 done = true;
451 success = op.success;
452 break;
453 }
454 }
455 this.success = success;
456 this.done = done;
457 };
458 return $Or;
459 }(NamedBaseOperation));
460 var $Nor = /** @class */ (function (_super) {
461 __extends($Nor, _super);
462 function $Nor() {
463 return _super !== null && _super.apply(this, arguments) || this;
464 }
465 $Nor.prototype.next = function (item, key, owner) {
466 _super.prototype.next.call(this, item, key, owner);
467 this.success = !this.success;
468 };
469 return $Nor;
470 }($Or));
471 var $In = /** @class */ (function (_super) {
472 __extends($In, _super);
473 function $In() {
474 return _super !== null && _super.apply(this, arguments) || this;
475 }
476 $In.prototype.init = function () {
477 var _this = this;
478 this._testers = this.params.map(function (value) {
479 if (containsOperation(value)) {
480 throw new Error("cannot nest $ under " + _this.constructor.name.toLowerCase());
481 }
482 return createTester(value, _this.options.compare);
483 });
484 };
485 $In.prototype.next = function (item, key, owner) {
486 var done = false;
487 var success = false;
488 for (var i = 0, length_3 = this._testers.length; i < length_3; i++) {
489 var test = this._testers[i];
490 if (test(item)) {
491 done = true;
492 success = true;
493 break;
494 }
495 }
496 this.success = success;
497 this.done = done;
498 };
499 return $In;
500 }(NamedBaseOperation));
501 var $Nin = /** @class */ (function (_super) {
502 __extends($Nin, _super);
503 function $Nin() {
504 return _super !== null && _super.apply(this, arguments) || this;
505 }
506 $Nin.prototype.next = function (item, key, owner) {
507 _super.prototype.next.call(this, item, key, owner);
508 this.success = !this.success;
509 };
510 return $Nin;
511 }($In));
512 var $Exists = /** @class */ (function (_super) {
513 __extends($Exists, _super);
514 function $Exists() {
515 return _super !== null && _super.apply(this, arguments) || this;
516 }
517 $Exists.prototype.next = function (item, key, owner) {
518 if (owner.hasOwnProperty(key) === this.params) {
519 this.done = true;
520 this.success = true;
521 }
522 };
523 return $Exists;
524 }(NamedBaseOperation));
525 var $And = /** @class */ (function (_super) {
526 __extends($And, _super);
527 function $And(params, owneryQuery, options, name) {
528 return _super.call(this, params, owneryQuery, options, params.map(function (query) { return createQueryOperation(query, owneryQuery, options); }), name) || this;
529 }
530 $And.prototype.next = function (item, key, owner) {
531 this.childrenNext(item, key, owner);
532 };
533 return $And;
534 }(NamedGroupOperation));
535 var $eq = function (params, owneryQuery, options) {
536 return new EqualsOperation(params, owneryQuery, options);
537 };
538 var $ne = function (params, owneryQuery, options, name) { return new $Ne(params, owneryQuery, options, name); };
539 var $or = function (params, owneryQuery, options, name) { return new $Or(params, owneryQuery, options, name); };
540 var $nor = function (params, owneryQuery, options, name) { return new $Nor(params, owneryQuery, options, name); };
541 var $elemMatch = function (params, owneryQuery, options, name) { return new $ElemMatch(params, owneryQuery, options, name); };
542 var $nin = function (params, owneryQuery, options, name) { return new $Nin(params, owneryQuery, options, name); };
543 var $in = function (params, owneryQuery, options, name) { return new $In(params, owneryQuery, options, name); };
544 var $lt = numericalOperation(function (params) { return function (b) { return b < params; }; });
545 var $lte = numericalOperation(function (params) { return function (b) { return b <= params; }; });
546 var $gt = numericalOperation(function (params) { return function (b) { return b > params; }; });
547 var $gte = numericalOperation(function (params) { return function (b) { return b >= params; }; });
548 var $mod = function (_a, owneryQuery, options) {
549 var mod = _a[0], equalsValue = _a[1];
550 return new EqualsOperation(function (b) { return comparable(b) % mod === equalsValue; }, owneryQuery, options);
551 };
552 var $exists = function (params, owneryQuery, options, name) { return new $Exists(params, owneryQuery, options, name); };
553 var $regex = function (pattern, owneryQuery, options) {
554 return new EqualsOperation(new RegExp(pattern, owneryQuery.$options), owneryQuery, options);
555 };
556 var $not = function (params, owneryQuery, options, name) { return new $Not(params, owneryQuery, options, name); };
557 var $type = function (clazz, owneryQuery, options) {
558 return new EqualsOperation(function (b) { return (b != null ? b instanceof clazz || b.constructor === clazz : false); }, owneryQuery, options);
559 };
560 var $and = function (params, ownerQuery, options, name) { return new $And(params, ownerQuery, options, name); };
561 var $all = $and;
562 var $size = function (params, ownerQuery, options) { return new EqualsOperation(function (b) { return b && b.length === params; }, ownerQuery, options); };
563 var $options = function () { return null; };
564 var $where = function (params, ownerQuery, options) {
565 var test;
566 if (isFunction(params)) {
567 test = params;
568 }
569 else if (!process.env.CSP_ENABLED) {
570 test = new Function("obj", "return " + params);
571 }
572 else {
573 throw new Error("In CSP mode, sift does not support strings in \"$where\" condition");
574 }
575 return new EqualsOperation(function (b) { return test.bind(b)(b); }, ownerQuery, options);
576 };
577
578 var defaultOperations = /*#__PURE__*/Object.freeze({
579 __proto__: null,
580 $eq: $eq,
581 $ne: $ne,
582 $or: $or,
583 $nor: $nor,
584 $elemMatch: $elemMatch,
585 $nin: $nin,
586 $in: $in,
587 $lt: $lt,
588 $lte: $lte,
589 $gt: $gt,
590 $gte: $gte,
591 $mod: $mod,
592 $exists: $exists,
593 $regex: $regex,
594 $not: $not,
595 $type: $type,
596 $and: $and,
597 $all: $all,
598 $size: $size,
599 $options: $options,
600 $where: $where
601 });
602
603 var createDefaultQueryOperation = function (query, ownerQuery, _a) {
604 var _b = _a === void 0 ? {} : _a, compare = _b.compare, operations = _b.operations;
605 return createQueryOperation(query, ownerQuery, {
606 compare: compare,
607 operations: Object.assign({}, defaultOperations, operations || {})
608 });
609 };
610 var createDefaultQueryTester = function (query, options) {
611 if (options === void 0) { options = {}; }
612 var op = createDefaultQueryOperation(query, null, options);
613 return createOperationTester(op);
614 };
615
616 exports.$all = $all;
617 exports.$and = $and;
618 exports.$elemMatch = $elemMatch;
619 exports.$eq = $eq;
620 exports.$exists = $exists;
621 exports.$gt = $gt;
622 exports.$gte = $gte;
623 exports.$in = $in;
624 exports.$lt = $lt;
625 exports.$lte = $lte;
626 exports.$mod = $mod;
627 exports.$ne = $ne;
628 exports.$nin = $nin;
629 exports.$nor = $nor;
630 exports.$not = $not;
631 exports.$options = $options;
632 exports.$or = $or;
633 exports.$regex = $regex;
634 exports.$size = $size;
635 exports.$type = $type;
636 exports.$where = $where;
637 exports.EqualsOperation = EqualsOperation;
638 exports.createDefaultQueryOperation = createDefaultQueryOperation;
639 exports.createEqualsOperation = createEqualsOperation;
640 exports.createOperationTester = createOperationTester;
641 exports.createQueryOperation = createQueryOperation;
642 exports.createQueryTester = createQueryTester;
643 exports.default = createDefaultQueryTester;
644
645 Object.defineProperty(exports, '__esModule', { value: true });
646
647})));
648//# sourceMappingURL=index.js.map