UNPKG

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