PageSourceSearch

https://irkduma.ru/bitrix/js/ui/dexie/dist/dexie.bitrix.bundle.js?1591677336196311

js irkduma.ru collected 2026-09-29 19:09:46 UTC 196,311 bytes, 5,006 lines download raw bytes

1(function (exports) {
2   'use strict';
3
4   /*
5    * Dexie.js - a minimalistic wrapper for IndexedDB
6    * ===============================================
7    *
8    * By David Fahlander, [email protected]
9    *
10    * Version 2.0.4, Fri May 25 2018
11    *
12    * http://dexie.org
13    *
14    * Apache License Version 2.0, January 2004, http://www.apache.org/licenses/
15    */
16
17   /**
18    * Modify list for integration with Bitrix Framework:
19    * - removed integration with third-party package builders;
20    * - add check variables before using them, see tags: 28122018;
21    * - add alternative Promise check for Bitrix Cli, see tags: 02032020;
22    * - add export for work in Bitrix CoreJS extensions;
23    */
24   var keys = Object.keys;
25   var isArray = Array.isArray;
26
27   var _global = typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : global;
28
29   function extend(obj, extension) {
30     if (babelHelpers.typeof(extension) !== 'object') return obj;
31     keys(extension).forEach(function (key) {
32       obj[key] = extension[key];
33     });
34     return obj;
35   }
36
37   var getProto = Object.getPrototypeOf;
38   var _hasOwn = {}.hasOwnProperty;
39
40   function hasOwn(obj, prop) {
41     return _hasOwn.call(obj, prop);
42   }
43
44   function props(proto, extension) {
45     if (typeof extension === 'function') extension = extension(getProto(proto)); // tag start 28122018
46
47     if (babelHelpers.typeof(extension) !== 'object') return; // tag end 28122018
48
49     keys(extension).forEach(function (key) {
50       setProp(proto, key, extension[key]);
51     });
52   }
53
54   var defineProperty = Object.defineProperty;
55
56   function setProp(obj, prop, functionOrGetSet, options) {
57     defineProperty(obj, prop, extend(functionOrGetSet && hasOwn(functionOrGetSet, "get") && typeof functionOrGetSet.get === 'function' ? {
58       get: functionOrGetSet.get,
59       set: functionOrGetSet.set,
60       configurable: true
61     } : {
62       value: functionOrGetSet,
63       configurable: true,
64       writable: true
65     }, options));
66   }
67
68   function derive(Child) {
69     return {
70       from: function from(Parent) {
71         Child.prototype = Object.create(Parent.prototype);
72         setProp(Child.prototype, "constructor", Child);
73         return {
74           extend: props.bind(null, Child.prototype)
75         };
76       }
77     };
78   }
79
80   var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
81
82   function getPropertyDescriptor(obj, prop) {
83     var pd = getOwnPropertyDescriptor(obj, prop),
84         proto;
85     return pd || (proto = getProto(obj)) && getPropertyDescriptor(proto, prop);
86   }
87
88   var _slice = [].slice;
89
90   function slice(args, start, end) {
91     return _slice.call(args, start, end);
92   }
93
94   function override(origFunc, overridedFactory) {
95     return overridedFactory(origFunc);
96   }
97
98   function assert(b) {
99     if (!b) throw new Error("Assertion Failed");
100   }
101
102   function asap(fn) {
103     if (_global.setImmediate) setImmediate(fn);else setTimeout(fn, 0);
104   }
105   /** Generate an object (hash map) based on given array.
106    * @param extractor Function taking an array item and its index and returning an array of 2 items ([key, value]) to
107    *        instert on the resulting object for each item in the array. If this function returns a falsy value, the
108    *        current item wont affect the resulting object.
109    */
110
111
112   function arrayToObject(array, extractor) {
113     return array.reduce(function (result, item, i) {
114       var nameAndValue = extractor(item, i);
115       if (nameAndValue) result[nameAndValue[0]] = nameAndValue[1];
116       return result;
117     }, {});
118   }
119
120   function trycatcher(fn, reject) {
121     return function () {
122       try {
123         fn.apply(this, arguments);
124       } catch (e) {
125         reject(e);
126       }
127     };
128   }
129
130   function tryCatch(fn, onerror, args) {
131     try {
132       fn.apply(null, args);
133     } catch (ex) {
134       onerror && onerror(ex);
135     }
136   }
137
138   function getByKeyPath(obj, keyPath) {
139     // http://www.w3.org/TR/IndexedDB/#steps-for-extracting-a-key-from-a-value-using-a-key-path
140     if (hasOwn(obj, keyPath)) return obj[keyPath]; // This line is moved from last to first for optimization purpose.
141
142     if (!keyPath) return obj;
143
144     if (typeof keyPath !== 'string') {
145       var rv = [];
146
147       for (var i = 0, l = keyPath.length; i < l; ++i) {
148         var val = getByKeyPath(obj, keyPath[i]);
149         rv.push(val);
150       }
151
152       return rv;
153     }
154
155     var period = keyPath.indexOf('.');
156
157     if (period !== -1) {
158       var innerObj = obj[keyPath.substr(0, period)];
159       return innerObj === undefined ? undefined : getByKeyPath(innerObj, keyPath.substr(period + 1));
160     }
161
162     return undefined;
163   }
164
165   function setByKeyPath(obj, keyPath, value) {
166     if (!obj || keyPath === undefined) return;
167     if ('isFrozen' in Object && Object.isFrozen(obj)) return;
168
169     if (typeof keyPath !== 'string' && 'length' in keyPath) {
170       assert(typeof value !== 'string' && 'length' in value);
171
172       for (var i = 0, l = keyPath.length; i < l; ++i) {
173         setByKeyPath(obj, keyPath[i], value[i]);
174       }
175     } else {
176       var period = keyPath.indexOf('.');
177
178       if (period !== -1) {
179         var currentKeyPath = keyPath.substr(0, period);
180         var remainingKeyPath = keyPath.substr(period + 1);
181         if (remainingKeyPath === "") {
182           if (value === undefined) delete obj[currentKeyPath];else obj[currentKeyPath] = value;
183         } else {
184           var innerObj = obj[currentKeyPath];
185           if (!innerObj) innerObj = obj[currentKeyPath] = {};
186           setByKeyPath(innerObj, remainingKeyPath, value);
187         }
188       } else {
189         if (value === undefined) delete obj[keyPath];else obj[keyPath] = value;
190       }
191     }
192   }
193
194   function delByKeyPath(obj, keyPath) {
195     if (typeof keyPath === 'string') setByKeyPath(obj, keyPath, undefined);else if ('length' in keyPath) [].map.call(keyPath, function (kp) {
196       setByKeyPath(obj, kp, undefined);
197     });
198   }
199
200   function shallowClone(obj) {
201     var rv = {};
202
203     for (var m in obj) {
204       if (hasOwn(obj, m)) rv[m] = obj[m];
205     }
206
207     return rv;
208   }
209
210   var concat = [].concat;
211
212   function flatten(a) {
213     return concat.apply([], a);
214   } //https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
215
216
217   var intrinsicTypes = "Boolean,String,Date,RegExp,Blob,File,FileList,ArrayBuffer,DataView,Uint8ClampedArray,ImageData,Map,Set".split(',').concat(flatten([8, 16, 32, 64].map(function (num) {
218     return ["Int", "Uint", "Float"].map(function (t) {
219       return t + num + "Array";
220     });
221   }))).filter(function (t) {
222     return _global[t];
223   }).map(function (t) {
224     return _global[t];
225   });
226
227   function deepClone(any) {
228     if (!any || babelHelpers.typeof(any) !== 'object') return any;
229     var rv;
230
231     if (isArray(any)) {
232       rv = [];
233
234       for (var i = 0, l = any.length; i < l; ++i) {
235         rv.push(deepClone(any[i]));
236       }
237     } else if (intrinsicTypes.indexOf(any.constructor) >= 0) {
238       rv = any;
239     } else {
240       rv = any.constructor ? Object.create(any.constructor.prototype) : {};
241
242       for (var prop in any) {
243         if (hasOwn(any, prop)) {
244           rv[prop] = deepClone(any[prop]);
245         }
246       }
247     }
248
249     return rv;
250   }
251
252   function getObjectDiff(a, b, rv, prfx) {
253     // Compares objects a and b and produces a diff object.
254     rv = rv || {};
255     prfx = prfx || '';
256     keys(a).forEach(function (prop) {
257       if (!hasOwn(b, prop)) rv[prfx + prop] = undefined; // Property removed
258       else {
259           var ap = a[prop],
260               bp = b[prop];
261           if (babelHelpers.typeof(ap) === 'object' && babelHelpers.typeof(bp) === 'object' && ap && bp && // Now compare constructors are same (not equal because wont work in Safari)
262           '' + ap.constructor === '' + bp.constructor) // Same type of object but its properties may have changed
263             getObjectDiff(ap, bp, rv, prfx + prop + ".");else if (ap !== bp) rv[prfx + prop] = b[prop]; // Primitive value changed
264         }
265     });
266     keys(b).forEach(function (prop) {
267       if (!hasOwn(a, prop)) {
268         rv[prfx + prop] = b[prop]; // Property added
269       }
270     });
271     return rv;
272   } // If first argument is iterable or array-like, return it as an array
273
274
275   var iteratorSymbol = typeof Symbol !== 'undefined' && Symbol.iterator;
276   var getIteratorOf = iteratorSymbol ? function (x) {
277     var i;
278     return x != null && (i = x[iteratorSymbol]) && i.apply(x);
279   } : function () {
280     return null;
281   };
282   var NO_CHAR_ARRAY = {}; // Takes one or several arguments and returns an array based on the following criteras:
283   // * If several arguments provided, return arguments converted to an array in a way that
284   //   still allows javascript engine to optimize the code.
285   // * If single argument is an array, return a clone of it.
286   // * If this-pointer equals NO_CHAR_ARRAY, don't accept strings as valid iterables as a special
287   //   case to the two bullets below.
288   // * If single argument is an iterable, convert it to an array and return the resulting array.
289   // * If single argument is array-like (has length of type number), convert it to an array.
290
291   function getArrayOf(arrayLike) {
292     var i, a, x, it;
293
294     if (arguments.length === 1) {
295       if (isArray(arrayLike)) return arrayLike.slice();
296       if (this === NO_CHAR_ARRAY && typeof arrayLike === 'string') return [arrayLike];
297
298       if (it = getIteratorOf(arrayLike)) {
299         a = [];
300
301         while (x = it.next(), !x.done) {
302           a.push(x.value);
303         }
304
305         return a;
306       }
307
308       if (arrayLike == null) return [arrayLike];
309       i = arrayLike.length;
310
311       if (typeof i === 'number') {
312         a = new Array(i);
313
314         while (i--) {
315           a[i] = arrayLike[i];
316         }
317
318         return a;
319       }
320
321       return [arrayLike];
322     }
323
324     i = arguments.length;
325     a = new Array(i);
326
327     while (i--) {
328       a[i] = arguments[i];
329     }
330
331     return a;
332   } // By default, debug will be true only if platform is a web platform and its page is served from localhost.
333   // When debug = true, error's stacks will contain asyncronic long stacks.
334
335
336   var debug = typeof location !== 'undefined' && // By default, use debug mode if served from localhost.
337   /^(http|https):\/\/(localhost|127\.0\.0\.1)/.test(location.href);
338
339   function setDebug(value, filter) {
340     debug = value;
341     libraryFilter = filter;
342   }
343
344   var libraryFilter = function libraryFilter() {
345     return true;
346   };
347
348   var NEEDS_THROW_FOR_STACK = !new Error("").stack;
349
350   function getErrorWithStack() {
351
352     if (NEEDS_THROW_FOR_STACK) try {
353       throw new Error(); // Fallback if above line don't throw.
354     } catch (e) {
355       return e;
356     }
357     return new Error();
358   }
359
360   function prettyStack(exception, numIgnoredFrames) {
361     var stack = exception.stack;
362     if (!stack) return "";
363     numIgnoredFrames = numIgnoredFrames || 0;
364     if (stack.indexOf(exception.name) === 0) numIgnoredFrames += (exception.name + exception.message).split('\n').length;
365     return stack.split('\n').slice(numIgnoredFrames).filter(libraryFilter).map(function (frame) {
366       return "\n" + frame;
367     }).join('');
368   }
369
370   function deprecated(what, fn) {
371     return function () {
372       console.warn(what + " is deprecated. See https://github.com/dfahlander/Dexie.js/wiki/Deprecations. " + prettyStack(getErrorWithStack(), 1));
373       return fn.apply(this, arguments);
374     };
375   }
376
377   var dexieErrorNames = ['Modify', 'Bulk', 'OpenFailed', 'VersionChange', 'Schema', 'Upgrade', 'InvalidTable', 'MissingAPI', 'NoSuchDatabase', 'InvalidArgument', 'SubTransaction', 'Unsupported', 'Internal', 'DatabaseClosed', 'PrematureCommit', 'ForeignAwait'];
378   var idbDomErrorNames = ['Unknown', 'Constraint', 'Data', 'TransactionInactive', 'ReadOnly', 'Version', 'NotFound', 'InvalidState', 'InvalidAccess', 'Abort', 'Timeout', 'QuotaExceeded', 'Syntax', 'DataClone'];
379   var errorList = dexieErrorNames.concat(idbDomErrorNames);
380   var defaultTexts = {
381     VersionChanged: "Database version changed by other database connection",
382     DatabaseClosed: "Database has been closed",
383     Abort: "Transaction aborted",
384     TransactionInactive: "Transaction has already completed or failed"
385   }; //
386   // DexieError - base class of all out exceptions.
387   //
388
389   function DexieError(name, msg) {
390     // Reason we don't use ES6 classes is because:
391     // 1. It bloats transpiled code and increases size of minified code.
392     // 2. It doesn't give us much in this case.
393     // 3. It would require sub classes to call super(), which
394     //    is not needed when deriving from Error.
395     this._e = getErrorWithStack();
396     this.name = name;
397     this.message = msg;
398   }
399
400   derive(DexieError).from(Error).extend({
401     stack: {
402       get: function get() {
403         return this._stack || (this._stack = this.name + ": " + this.message + prettyStack(this._e, 2));
404       }
405     },
406     toString: function toString() {
407       return this.name + ": " + this.message;
408     }
409   });
410
411   function getMultiErrorMessage(msg, failures) {
412     return msg + ". Errors: " + failures.map(function (f) {
413       return f.toString();
414     }).filter(function (v, i, s) {
415       return s.indexOf(v) === i;
416     }) // Only unique error strings
417     .join('\n');
418   } //
419   // ModifyError - thrown in Collection.modify()
420   // Specific constructor because it contains members failures and failedKeys.
421   //
422
423
424   function ModifyError(msg, failures, successCount, failedKeys) {
425     this._e = getErrorWithStack();
426     this.failures = failures;
427     this.failedKeys = failedKeys;
428     this.successCount = successCount;
429   }
430
431   derive(ModifyError).from(DexieError);
432
433   function BulkError(msg, failures) {
434     this._e = getErrorWithStack();
435     this.name = "BulkError";
436     this.failures = failures;
437     this.message = getMultiErrorMessage(msg, failures);
438   }
439
440   derive(BulkError).from(DexieError); //
441   //
442   // Dynamically generate error names and exception classes based
443   // on the names in errorList.
444   //
445   //
446   // Map of {ErrorName -> ErrorName + "Error"}
447
448   var errnames = errorList.reduce(function (obj, name) {
449     return obj[name] = name + "Error", obj;
450   }, {}); // Need an alias for DexieError because we're gonna create subclasses with the same name.
451
452   var BaseException = DexieError; // Map of {ErrorName -> exception constructor}
453
454   var exceptions = errorList.reduce(function (obj, name) {
455     // Let the name be "DexieError" because this name may
456     // be shown in call stack and when debugging. DexieError is
457     // the most true name because it derives from DexieError,
458     // and we cannot change Function.name programatically without
459     // dynamically create a Function object, which would be considered
460     // 'eval-evil'.
461     var fullName = name + "Error";
462
463     function DexieError(msgOrInner, inner) {
464       this._e = getErrorWithStack();
465       this.name = fullName;
466
467       if (!msgOrInner) {
468         this.message = defaultTexts[name] || fullName;
469         this.inner = null;
470       } else if (typeof msgOrInner === 'string') {
471         this.message = msgOrInner;
472         this.inner = inner || null;
473       } else if (babelHelpers.typeof(msgOrInner) === 'object') {
474         this.message = msgOrInner.name + " " + msgOrInner.message;
475         this.inner = msgOrInner;
476       }
477     }
478
479     derive(DexieError).from(BaseException);
480     obj[name] = DexieError;
481     return obj;
482   }, {}); // Use ECMASCRIPT standard exceptions where applicable:
483
484   exceptions.Syntax = SyntaxError;
485   exceptions.Type = TypeError;
486   exceptions.Range = RangeError;
487   var exceptionMap = idbDomErrorNames.reduce(function (obj, name) {
488     obj[name + "Error"] = exceptions[name];
489     return obj;
490   }, {});
491
492   function mapError(domError, message) {
493     if (!domError || domError instanceof DexieError || domError instanceof TypeError || domError instanceof SyntaxError || !domError.name || !exceptionMap[domError.name]) return domError;
494     var rv = new exceptionMap[domError.name](message || domError.message, domError);
495
496     if ("stack" in domError) {
497       // Derive stack from inner exception if it has a stack
498       setProp(rv, "stack", {
499         get: function get() {
500           return this.inner.stack;
501         }
502       });
503     }
504
505     return rv;
506   }
507
508   var fullNameExceptions = errorList.reduce(function (obj, name) {
509     if (["Syntax", "Type", "Range"].indexOf(name) === -1) obj[name + "Error"] = exceptions[name];
510     return obj;
511   }, {});
512   fullNameExceptions.ModifyError = ModifyError;
513   fullNameExceptions.DexieError = DexieError;
514   fullNameExceptions.BulkError = BulkError;
515
516   function nop() {}
517
518   function mirror(val) {
519     return val;
520   }
521
522   function pureFunctionChain(f1, f2) {
523     // Enables chained events that takes ONE argument and returns it to the next function in chain.
524     // This pattern is used in the hook("reading") event.
525     if (f1 == null || f1 === mirror) return f2;
526     return function (val) {
527       return f2(f1(val));
528     };
529   }
530
531   function callBoth(on1, on2) {
532     return function () {
533       on1.apply(this, arguments);
534       on2.apply(this, arguments);
535     };
536   }
537
538   function hookCreatingChain(f1, f2) {
539     // Enables chained events that takes several arguments and may modify first argument by making a modification and then returning the same instance.
540     // This pattern is used in the hook("creating") event.
541     if (f1 === nop) return f2;
542     return function () {
543       var res = f1.apply(this, arguments);
544       if (res !== undefined) arguments[0] = res;
545       var onsuccess = this.onsuccess,
546           // In case event listener has set this.onsuccess
547       onerror = this.onerror; // In case event listener has set this.onerror
548
549       this.onsuccess = null;
550       this.onerror = null;
551       var res2 = f2.apply(this, arguments);
552       if (onsuccess) this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;
553       if (onerror) this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
554       return res2 !== undefined ? res2 : res;
555     };
556   }
557
558   function hookDeletingChain(f1, f2) {
559     if (f1 === nop) return f2;
560     return function () {
561       f1.apply(this, arguments);
562       var onsuccess = this.onsuccess,
563           // In case event listener has set this.onsuccess
564       onerror = this.onerror; // In case event listener has set this.onerror
565
566       this.onsuccess = this.onerror = null;
567       f2.apply(this, arguments);
568       if (onsuccess) this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;
569       if (onerror) this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
570     };
571   }
572
573   function hookUpdatingChain(f1, f2) {
574     if (f1 === nop) return f2;
575     return function (modifications) {
576       var res = f1.apply(this, arguments);
577       extend(modifications, res); // If f1 returns new modifications, extend caller's modifications with the result before calling next in chain.
578
579       var onsuccess = this.onsuccess,
580           // In case event listener has set this.onsuccess
581       onerror = this.onerror; // In case event listener has set this.onerror
582
583       this.onsuccess = null;
584       this.onerror = null;
585       var res2 = f2.apply(this, arguments);
586       if (onsuccess) this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;
587       if (onerror) this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
588       return res === undefined ? res2 === undefined ? undefined : res2 : extend(res, res2);
589     };
590   }
591
592   function reverseStoppableEventChain(f1, f2) {
593     if (f1 === nop) return f2;
594     return function () {
595       if (f2.apply(this, arguments) === false) return false;
596       return f1.apply(this, arguments);
597     };
598   }
599
600   function promisableChain(f1, f2) {
601     if (f1 === nop) return f2;
602     return function () {
603       var res = f1.apply(this, arguments);
604
605       if (res && typeof res.then === 'function') {
606         var thiz = this,
607             i = arguments.length,
608             args = new Array(i);
609
610         while (i--) {
611           args[i] = arguments[i];
612         }
613
614         return res.then(function () {
615           return f2.apply(thiz, args);
616         });
617       }
618
619       return f2.apply(this, arguments);
620     };
621   }
622   /*
623    * Copyright (c) 2014-2017 David Fahlander
624    * Apache License Version 2.0, January 2004, http://www.apache.org/licenses/LICENSE-2.0
625    */
626   //
627   // Promise and Zone (PSD) for Dexie library
628   //
629   // I started out writing this Promise class by copying promise-light (https://github.com/taylorhakes/promise-light) by
630   // https://github.com/taylorhakes - an A+ and ECMASCRIPT 6 compliant Promise implementation.
631   //
632   // In previous versions this was fixed by not calling setTimeout when knowing that the resolve() or reject() came from another
633   // tick. In Dexie v1.4.0, I've rewritten the Promise class entirely. Just some fragments of promise-light is left. I use
634   // another strategy now that simplifies everything a lot: to always execute callbacks in a new micro-task, but have an own micro-task
635   // engine that is indexedDB compliant across all browsers.
636   // Promise class has also been optimized a lot with inspiration from bluebird - to avoid closures as much as possible.
637   // Also with inspiration from bluebird, asyncronic stacks in debug mode.
638   //
639   // Specific non-standard features of this Promise class:
640   // * Custom zone support (a.k.a. PSD) with ability to keep zones also when using native promises as well as
641   //   native async / await.
642   // * Promise.follow() method built upon the custom zone engine, that allows user to track all promises created from current stack frame
643   //   and below + all promises that those promises creates or awaits.
644   // * Detect any unhandled promise in a PSD-scope (PSD.onunhandled).
645   //
646   // David Fahlander, https://github.com/dfahlander
647   //
648   // Just a pointer that only this module knows about.
649   // Used in Promise constructor to emulate a private constructor.
650
651
652   var INTERNAL = {}; // Async stacks (long stacks) must not grow infinitely.
653
654   var LONG_STACKS_CLIP_LIMIT = 100;
655   var MAX_LONG_STACKS = 20;
656   var ZONE_ECHO_LIMIT = 7;
657
658   var nativePromiseInstanceAndProto = function () {
659     try {
660       // Be able to patch native async functions
661       return new Function("let F=async ()=>{},p=F();return [p,Object.getPrototypeOf(p),Promise.resolve(),F.constructor];")();
662     } catch (e) {
663       var P = _global.Promise;
664       return P ? [P.resolve(), P.prototype, P.resolve()] : [];
665     }
666   }();
667
668   var resolvedNativePromise = nativePromiseInstanceAndProto[0];
669   var nativePromiseProto = nativePromiseInstanceAndProto[1];
670   var resolvedGlobalPromise = nativePromiseInstanceAndProto[2];
671   var nativePromiseThen = nativePromiseProto && nativePromiseProto.then;
672   var NativePromise = resolvedNativePromise && resolvedNativePromise.constructor;
673   var AsyncFunction = nativePromiseInstanceAndProto[3];
674   var patchGlobalPromise = !!resolvedGlobalPromise;
675   var stack_being_generated = false;
676   /* The default function used only for the very first promise in a promise chain.
677      As soon as then promise is resolved or rejected, all next tasks will be executed in micro ticks
678      emulated in this module. For indexedDB compatibility, this means that every method needs to
679      execute at least one promise before doing an indexedDB operation. Dexie will always call
680      db.ready().then() for every operation to make sure the indexedDB event is started in an
681      indexedDB-compatible emulated micro task loop.
682   */
683
684   var schedulePhysicalTick = resolvedGlobalPromise ? function () {
685     resolvedGlobalPromise.then(physicalTick);
686   } : _global.setImmediate ? // setImmediate supported. Those modern platforms also supports Function.bind().
687   setImmediate.bind(null, physicalTick) : _global.MutationObserver ? // MutationObserver supported
688   function () {
689     var hiddenDiv = document.createElement("div");
690     new MutationObserver(function () {
691       physicalTick();
692       hiddenDiv = null;
693     }).observe(hiddenDiv, {
694       attributes: true
695     });
696     hiddenDiv.setAttribute('i', '1');
697   } : // No support for setImmediate or MutationObserver. No worry, setTimeout is only called
698   // once time. Every tick that follows will be our emulated micro tick.
699   // Could have uses setTimeout.bind(null, 0, physicalTick) if it wasnt for that FF13 and below has a bug
700   function () {
701     setTimeout(physicalTick, 0);
702   }; // Configurable through Promise.scheduler.
703   // Don't export because it would be unsafe to let unknown
704   // code call it unless they do try..catch within their callback.
705   // This function can be retrieved through getter of Promise.scheduler though,
706   // but users must not do Promise.scheduler = myFuncThatThrowsException
707
708   var asap$1 = function asap$1(callback, args) {
709     microtickQueue.push([callback, args]);
710
711     if (needsNewPhysicalTick) {
712       schedulePhysicalTick();
713       needsNewPhysicalTick = false;
714     }
715   };
716
717   var isOutsideMicroTick = true;
718   var needsNewPhysicalTick = true;
719   var unhandledErrors = [];
720   var rejectingErrors = [];
721   var currentFulfiller = null;
722   var rejectionMapper = mirror; // Remove in next major when removing error mapping of DOMErrors and DOMExceptions
723
724   var globalPSD = {
725     id: 'global',
726     global: true,
727     ref: 0,
728     unhandleds: [],
729     onunhandled: globalError,
730     pgp: false,
731     env: {},
732     finalize: function finalize() {
733       this.unhandleds.forEach(function (uh) {
734         try {
735           globalError(uh[0], uh[1]);
736         } catch (e) {}
737       });
738     }
739   };
740   var PSD = globalPSD;
741   var microtickQueue = []; // Callbacks to call in this or next physical tick.
742
743   var numScheduledCalls = 0; // Number of listener-calls left to do in this physical tick.
744
745   var tickFinalizers = []; // Finalizers to call when there are no more async calls scheduled within current physical tick.
746
747   function Promise(fn) {
748     if (babelHelpers.typeof(this) !== 'object') throw new TypeError('Promises must be constructed via new');
749     this._listeners = [];
750     this.onuncatched = nop; // Deprecate in next major. Not needed. Better to use global error handler.
751     // A library may set `promise._lib = true;` after promise is created to make resolve() or reject()
752     // execute the microtask engine implicitely within the call to resolve() or reject().
753     // To remain A+ compliant, a library must only set `_lib=true` if it can guarantee that the stack
754     // only contains library code when calling resolve() or reject().
755     // RULE OF THUMB: ONLY set _lib = true for promises explicitely resolving/rejecting directly from
756     // global scope (event handler, timer etc)!
757
758     this._lib = false; // Current async scope
759
760     var psd = this._PSD = PSD;
761
762     if (debug) {
763       this._stackHolder = getErrorWithStack();
764       this._prev = null;
765       this._numPrev = 0; // Number of previous promises (for long stacks)
766     }
767
768     if (typeof fn !== 'function') {
769       if (fn !== INTERNAL) throw new TypeError('Not a function'); // Private constructor (INTERNAL, state, value).
770       // Used internally by Promise.resolve() and Promise.reject().
771
772       this._state = arguments[1];
773       this._value = arguments[2];
774       if (this._state === false) handleRejection(this, this._value); // Map error, set stack and addPossiblyUnhandledError().
775
776       return;
777     }
778
779     this._state = null; // null (=pending), false (=rejected) or true (=resolved)
780
781     this._value = null; // error or result
782
783     ++psd.ref; // Refcounting current scope
784
785     executePromiseTask(this, fn);
786   } // Prepare a property descriptor to put onto Promise.prototype.then
787
788
789   var thenProp = {
790     get: function get() {
791       var psd = PSD,
792           microTaskId = totalEchoes;
793
794       function then(onFulfilled, onRejected) {
795         var _this = this;
796
797         var possibleAwait = !psd.global && (psd !== PSD || microTaskId !== totalEchoes);
798         if (possibleAwait) decrementExpectedAwaits();
799         var rv = new Promise(function (resolve, reject) {
800           propagateToListener(_this, new Listener(nativeAwaitCompatibleWrap(onFulfilled, psd, possibleAwait), nativeAwaitCompatibleWrap(onRejected, psd, possibleAwait), resolve, reject, psd));
801         });
802         debug && linkToPreviousPromise(rv, this);
803         return rv;
804       }
805
806       then.prototype = INTERNAL; // For idempotense, see setter below.
807
808       return then;
809     },
810     // Be idempotent and allow another framework (such as zone.js or another instance of a Dexie.Promise module) to replace Promise.prototype.then
811     // and when that framework wants to restore the original property, we must identify that and restore the original property descriptor.
812     set: function set(value) {
813       setProp(this, 'then', value && value.prototype === INTERNAL ? thenProp : // Restore to original property descriptor.
814       {
815         get: function get() {
816           return value; // Getter returning provided value (behaves like value is just changed)
817         },
818         set: thenProp.set // Keep a setter that is prepared to restore original.
819
820       });
821     }
822   };
823   props(Promise.prototype, {
824     then: thenProp,
825     _then: function _then(onFulfilled, onRejected) {
826       // A little tinier version of then() that don't have to create a resulting promise.
827       propagateToListener(this, new Listener(null, null, onFulfilled, onRejected, PSD));
828     },
829     catch: function _catch(onRejected) {
830       if (arguments.length === 1) return this.then(null, onRejected); // First argument is the Error type to catch
831
832       var type = arguments[0],
833           handler = arguments[1];
834       return typeof type === 'function' ? this.then(null, function (err) {
835         // Catching errors by its constructor type (similar to java / c++ / c#)
836         // Sample: promise.catch(TypeError, function (e) { ... });
837         return err instanceof type ? handler(err) : PromiseReject(err);
838       }) : this.then(null, function (err) {
839         // Catching errors by the error.name property. Makes sense for indexedDB where error type
840         // is always DOMError but where e.name tells the actual error type.
841         // Sample: promise.catch('ConstraintError', function (e) { ... });
842         return err && err.name === type ? handler(err) : PromiseReject(err);
843       });
844     },
845     finally: function _finally(onFinally) {
846       return this.then(function (value) {
847         onFinally();
848         return value;
849       }, function (err) {
850         onFinally();
851         return PromiseReject(err);
852       });
853     },
854     stack: {
855       get: function get() {
856         if (this._stack) return this._stack;
857
858         try {
859           stack_being_generated = true;
860           var stacks = getStack(this, [], MAX_LONG_STACKS);
861           var stack = stacks.join("\nFrom previous: ");
862           if (this._state !== null) this._stack = stack; // Stack may be updated on reject.
863
864           return stack;
865         } finally {
866           stack_being_generated = false;
867         }
868       }
869     },
870     timeout: function timeout(ms, msg) {
871       var _this = this;
872
873       return ms < Infinity ? new Promise(function (resolve, reject) {
874         var handle = setTimeout(function () {
875           return reject(new exceptions.Timeout(msg));
876         }, ms);
877
878         _this.then(resolve, reject).finally(clearTimeout.bind(null, handle));
879       }) : this;
880     }
881   });
882   if (typeof Symbol !== 'undefined' && Symbol.toStringTag) setProp(Promise.prototype, Symbol.toStringTag, 'Promise'); // Now that Promise.prototype is defined, we have all it takes to set globalPSD.env.
883   // Environment globals snapshotted on leaving global zone
884
885   globalPSD.env = snapShot();
886
887   function Listener(onFulfilled, onRejected, resolve, reject, zone) {
888     this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
889     this.onRejected = typeof onRejected === 'function' ? onRejected : null;
890     this.resolve = resolve;
891     this.reject = reject;
892     this.psd = zone;
893   } // Promise Static Properties
894
895
896   props(Promise, {
897     all: function all() {
898       var values = getArrayOf.apply(null, arguments) // Supports iterables, implicit arguments and array-like.
899       .map(onPossibleParallellAsync); // Handle parallell async/awaits
900
901       return new Promise(function (resolve, reject) {
902         if (values.length === 0) resolve([]);
903         var remaining = values.length;
904         values.forEach(function (a, i) {
905           return Promise.resolve(a).then(function (x) {
906             values[i] = x;
907             if (! --remaining) resolve(values);
908           }, reject);
909         });
910       });
911     },
912     resolve: function resolve(value) {
913       if (value instanceof Promise) return value;
914       if (value && typeof value.then === 'function') return new Promise(function (resolve, reject) {
915         value.then(resolve, reject);
916       });
917       var rv = new Promise(INTERNAL, true, value);
918       linkToPreviousPromise(rv, currentFulfiller);
919       return rv;
920     },
921     reject: PromiseReject,
922     race: function race() {
923       var values = getArrayOf.apply(null, arguments).map(onPossibleParallellAsync);
924       return new Promise(function (resolve, reject) {
925         values.map(function (value) {
926           return Promise.resolve(value).then(resolve, reject);
927         });
928       });
929     },
930     PSD: {
931       get: function get() {
932         return PSD;
933       },
934       set: function set(value) {
935         return PSD = value;
936       }
937     },
938     //totalEchoes: {get: ()=>totalEchoes},
939     //task: {get: ()=>task},
940     newPSD: newScope,
941     usePSD: usePSD,
942     scheduler: {
943       get: function get() {
944         return asap$1;
945       },
946       set: function set(value) {
947         asap$1 = value;
948       }
949     },
950     rejectionMapper: {
951       get: function get() {
952         return rejectionMapper;
953       },
954       set: function set(value) {
955         rejectionMapper = value;
956       } // Map reject failures
957
958     },
959     follow: function follow(fn, zoneProps) {
960       return new Promise(function (resolve, reject) {
961         return newScope(function (resolve, reject) {
962           var psd = PSD;
963           psd.unhandleds = []; // For unhandled standard- or 3rd party Promises. Checked at psd.finalize()
964
965           psd.onunhandled = reject; // Triggered directly on unhandled promises of this library.
966
967           psd.finalize = callBoth(function () {
968             var _this = this; // Unhandled standard or 3rd part promises are put in PSD.unhandleds and
969             // examined upon scope completion while unhandled rejections in this Promise
970             // will trigger directly through psd.onunhandled
971
972
973             run_at_end_of_this_or_next_physical_tick(function () {
974               _this.unhandleds.length === 0 ? resolve() : reject(_this.unhandleds[0]);
975             });
976           }, psd.finalize);
977           fn();
978         }, zoneProps, resolve, reject);
979       });
980     }
981   });
982   /**
983   * Take a potentially misbehaving resolver function and make sure
984   * onFulfilled and onRejected are only called once.
985   *
986   * Makes no guarantees about asynchrony.
987   */
988
989   function executePromiseTask(promise, fn) {
990     // Promise Resolution Procedure:
991     // https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
992     try {
993       fn(function (value) {
994         if (promise._state !== null) return; // Already settled
995
996         if (value === promise) throw new TypeError('A promise cannot be resolved with itself.');
997         var shouldExecuteTick = promise._lib && beginMicroTickScope();
998
999         if (value && typeof value.then === 'function') {
1000           executePromiseTask(promise, function (resolve, reject) {
1001             value instanceof Promise ? value._then(resolve, reject) : value.then(resolve, reject);
1002           });
1003         } else {
1004           promise._state = true;
1005           promise._value = value;
1006           propagateAllListeners(promise);
1007         }
1008
1009         if (shouldExecuteTick) endMicroTickScope();
1010       }, handleRejection.bind(null, promise)); // If Function.bind is not supported. Exception is handled in catch below
1011     } catch (ex) {
1012       handleRejection(promise, ex);
1013     }
1014   }
1015
1016   function handleRejection(promise, reason) {
1017     rejectingErrors.push(reason);
1018     if (!promise || promise._state !== null) // tag 28122018
1019       return;
1020     var shouldExecuteTick = promise._lib && beginMicroTickScope();
1021     reason = rejectionMapper(reason);
1022     promise._state = false;
1023     promise._value = reason;
1024     debug && reason !== null && babelHelpers.typeof(reason) === 'object' && !reason._promise && tryCatch(function () {
1025       var origProp = getPropertyDescriptor(reason, "stack");
1026       reason._promise = promise;
1027       setProp(reason, "stack", {
1028         get: function get() {
1029           return stack_being_generated ? origProp && (origProp.get ? origProp.get.apply(reason) : origProp.value) : promise.stack;
1030         }
1031       });
1032     }); // Add the failure to a list of possibly uncaught errors
1033
1034     addPossiblyUnhandledError(promise);
1035     propagateAllListeners(promise);
1036     if (shouldExecuteTick) endMicroTickScope();
1037   }
1038
1039   function propagateAllListeners(promise) {
1040     //debug && linkToPreviousPromise(promise);
1041     var listeners = promise._listeners;
1042     promise._listeners = [];
1043
1044     for (var i = 0, len = listeners.length; i < len; ++i) {
1045       propagateToListener(promise, listeners[i]);
1046     }
1047
1048     var psd = promise._PSD;
1049     --psd.ref || psd.finalize(); // if psd.ref reaches zero, call psd.finalize();
1050
1051     if (numScheduledCalls === 0) {
1052       // If numScheduledCalls is 0, it means that our stack is not in a callback of a scheduled call,
1053       // and that no deferreds where listening to this rejection or success.
1054       // Since there is a risk that our stack can contain application code that may
1055       // do stuff after this code is finished that may generate new calls, we cannot
1056       // call finalizers here.
1057       ++numScheduledCalls;
1058       asap$1(function () {
1059         if (--numScheduledCalls === 0) finalizePhysicalTick(); // Will detect unhandled errors
1060       }, []);
1061     }
1062   }
1063
1064   function propagateToListener(promise, listener) {
1065     if (promise._state === null) {
1066       promise._listeners.push(listener);
1067
1068       return;
1069     }
1070
1071     var cb = promise._state ? listener.onFulfilled : listener.onRejected;
1072
1073     if (cb === null) {
1074       // This Listener doesnt have a listener for the event being triggered (onFulfilled or onReject) so lets forward the event to any eventual listeners on the Promise instance returned by then() or catch()
1075       return (promise._state ? listener.resolve : listener.reject)(promise._value);
1076     }
1077
1078     ++listener.psd.ref;
1079     ++numScheduledCalls;
1080     asap$1(callListener, [cb, promise, listener]);
1081   }
1082
1083   function callListener(cb, promise, listener) {
1084     try {
1085       // Set static variable currentFulfiller to the promise that is being fullfilled,
1086       // so that we connect the chain of promises (for long stacks support)
1087       currentFulfiller = promise; // Call callback and resolve our listener with it's return value.
1088
1089       var ret,
1090           value = promise._value;
1091
1092       if (promise._state) {
1093         // cb is onResolved
1094         ret = cb(value);
1095       } else {
1096         // cb is onRejected
1097         if (rejectingErrors.length) rejectingErrors = [];
1098         ret = cb(value);
1099         if (rejectingErrors.indexOf(value) === -1) markErrorAsHandled(promise); // Callback didnt do Promise.reject(err) nor reject(err) onto another promise.
1100       }
1101
1102       listener.resolve(ret);
1103     } catch (e) {
1104       // Exception thrown in callback. Reject our listener.
1105       listener.reject(e);
1106     } finally {
1107       // Restore env and currentFulfiller.
1108       currentFulfiller = null;
1109       if (--numScheduledCalls === 0) finalizePhysicalTick();
1110       --listener.psd.ref || listener.psd.finalize();
1111     }
1112   }
1113
1114   function getStack(promise, stacks, limit) {
1115     if (stacks.length === limit) return stacks;
1116     var stack = "";
1117
1118     if (promise._state === false) {
1119       var failure = promise._value,
1120           errorName,
1121           message;
1122
1123       if (failure != null) {
1124         errorName = failure.name || "Error";
1125         message = failure.message || failure;
1126         stack = prettyStack(failure, 0);
1127       } else {
1128         errorName = failure; // If error is undefined or null, show that.
1129
1130         message = "";
1131       }
1132
1133       stacks.push(errorName + (message ? ": " + message : "") + stack);
1134     }
1135
1136     if (debug) {
1137       stack = prettyStack(promise._stackHolder, 2);
1138       if (stack && stacks.indexOf(stack) === -1) stacks.push(stack);
1139       if (promise._prev) getStack(promise._prev, stacks, limit);
1140     }
1141
1142     return stacks;
1143   }
1144
1145   function linkToPreviousPromise(promise, prev) {
1146     // Support long stacks by linking to previous completed promise.
1147     var numPrev = prev ? prev._numPrev + 1 : 0;
1148
1149     if (numPrev < LONG_STACKS_CLIP_LIMIT) {
1150       promise._prev = prev;
1151       promise._numPrev = numPrev;
1152     }
1153   }
1154   /* The callback to schedule with setImmediate() or setTimeout().
1155      It runs a virtual microtick and executes any callback registered in microtickQueue.
1156    */
1157
1158
1159   function physicalTick() {
1160     beginMicroTickScope() && endMicroTickScope();
1161   }
1162
1163   function beginMicroTickScope() {
1164     var wasRootExec = isOutsideMicroTick;
1165     isOutsideMicroTick = false;
1166     needsNewPhysicalTick = false;
1167     return wasRootExec;
1168   }
1169   /* Executes micro-ticks without doing try..catch.
1170      This can be possible because we only use this internally and
1171      the registered functions are exception-safe (they do try..catch
1172      internally before calling any external method). If registering
1173      functions in the microtickQueue that are not exception-safe, this
1174      would destroy the framework and make it instable. So we don't export
1175      our asap method.
1176   */
1177
1178
1179   function endMicroTickScope() {
1180     var callbacks, i, l;
1181
1182     do {
1183       while (microtickQueue.length > 0) {
1184         callbacks = microtickQueue;
1185         microtickQueue = [];
1186         l = callbacks.length;
1187
1188         for (i = 0; i < l; ++i) {
1189           var item = callbacks[i];
1190           item[0].apply(null, item[1]);
1191         }
1192       }
1193     } while (microtickQueue.length > 0);
1194
1195     isOutsideMicroTick = true;
1196     needsNewPhysicalTick = true;
1197   }
1198
1199   function finalizePhysicalTick() {
1200     var unhandledErrs = unhandledErrors;
1201     unhandledErrors = [];
1202     unhandledErrs.forEach(function (p) {
1203       p._PSD.onunhandled.call(null, p._value, p);
1204     });
1205     var finalizers = tickFinalizers.slice(0); // Clone first because finalizer may remove itself from list.
1206
1207     var i = finalizers.length;
1208
1209     while (i) {
1210       finalizers[--i]();
1211     }
1212   }
1213
1214   function run_at_end_of_this_or_next_physical_tick(fn) {
1215     function finalizer() {
1216       fn();
1217       tickFinalizers.splice(tickFinalizers.indexOf(finalizer), 1);
1218     }
1219
1220     tickFinalizers.push(finalizer);
1221     ++numScheduledCalls;
1222     asap$1(function () {
1223       if (--numScheduledCalls === 0) finalizePhysicalTick();
1224     }, []);
1225   }
1226
1227   function addPossiblyUnhandledError(promise) {
1228     // Only add to unhandledErrors if not already there. The first one to add to this list
1229     // will be upon the first rejection so that the root cause (first promise in the
1230     // rejection chain) is the one listed.
1231     if (!unhandledErrors.some(function (p) {
1232       return p._value === promise._value;
1233     })) unhandledErrors.push(promise);
1234   }
1235
1236   function markErrorAsHandled(promise) {
1237     // Called when a reject handled is actually being called.
1238     // Search in unhandledErrors for any promise whos _value is this promise_value (list
1239     // contains only rejected promises, and only one item per error)
1240     var i = unhandledErrors.length;
1241
1242     while (i) {
1243       if (unhandledErrors[--i]._value === promise._value) {
1244         // Found a promise that failed with this same error object pointer,
1245         // Remove that since there is a listener that actually takes care of it.
1246         unhandledErrors.splice(i, 1);
1247         return;
1248       }
1249     }
1250   }
1251
1252   function PromiseReject(reason) {
1253     return new Promise(INTERNAL, false, reason);
1254   }
1255
1256   function wrap(fn, errorCatcher) {
1257     var psd = PSD;
1258     return function () {
1259       var wasRootExec = beginMicroTickScope(),
1260           outerScope = PSD;
1261
1262       try {
1263         switchToZone(psd, true);
1264         return fn.apply(this, arguments);
1265       } catch (e) {
1266         errorCatcher && errorCatcher(e);
1267       } finally {
1268         switchToZone(outerScope, false);
1269         if (wasRootExec) endMicroTickScope();
1270       }
1271     };
1272   } //
1273   // variables used for native await support
1274   //
1275
1276
1277   var task = {
1278     awaits: 0,
1279     echoes: 0,
1280     id: 0
1281   }; // The ongoing macro-task when using zone-echoing.
1282
1283   var taskCounter = 0; // ID counter for macro tasks.
1284
1285   var zoneStack = []; // Stack of left zones to restore asynchronically.
1286
1287   var zoneEchoes = 0; // zoneEchoes is a must in order to persist zones between native await expressions.
1288
1289   var totalEchoes = 0; // ID counter for micro-tasks. Used to detect possible native await in our Promise.prototype.then.
1290
1291   var zone_id_counter = 0;
1292
1293   function newScope(fn, props$$1, a1, a2) {
1294     var parent = PSD,
1295         psd = Object.create(parent);
1296     psd.parent = parent;
1297     psd.ref = 0;
1298     psd.global = false;
vendor: 1,438 bytes, lines 1299-1340
1299     psd.id = ++zone_id_counter; // Prepare for promise patching (done in usePSD):
1300
1301     var globalEnv = globalPSD.env;
1302     psd.env = patchGlobalPromise ? {
1303       Promise: Promise,
1304       PromiseProp: {
1305         value: Promise,
1306         configurable: true,
1307         writable: true
1308       },
1309       all: Promise.all,
1310       race: Promise.race,
1311       resolve: Promise.resolve,
1312       reject: Promise.reject,
1313       nthen: getPatchedPromiseThen(globalEnv.nthen, psd),
1314       gthen: getPatchedPromiseThen(globalEnv.gthen, psd) // global then
1315
1316     } : {};
1317     if (props$$1) extend(psd, props$$1); // unhandleds and onunhandled should not be specifically set here.
1318     // Leave them on parent prototype.
1319     // unhandleds.push(err) will push to parent's prototype
1320     // onunhandled() will call parents onunhandled (with this scope's this-pointer though!)
1321
1322     ++parent.ref;
1323
1324     psd.finalize = function () {
1325       --this.parent.ref || this.parent.finalize();
1326     };
1327
1328     var rv = usePSD(psd, fn, a1, a2);
1329     if (psd.ref === 0) psd.finalize();
1330     return rv;
1331   } // Function to call if scopeFunc returns NativePromise
1332   // Also for each NativePromise in the arguments to Promise.all()
1333
1334
1335   function incrementExpectedAwaits() {
1336     if (!task.id) task.id = ++taskCounter;
1337     ++task.awaits;
1338     task.echoes += ZONE_ECHO_LIMIT;
1339     return task.id;
1340   } // Function to call when 'then' calls back on a native promise where onA
1340waitExpected() had been called.
1341   // Also call this when a native await calls then method on a promise. In that case, don't supply
1342   // sourceTaskId because we already know it refers to current task.
1343
1344
1345   function decrementExpectedAwaits(sourceTaskId) {
1346     if (!task.awaits || sourceTaskId && sourceTaskId !== task.id) return;
1347     if (--task.awaits === 0) task.id = 0;
1348     task.echoes = task.awaits * ZONE_ECHO_LIMIT; // Will reset echoes to 0 if awaits is 0.
1349   } // Call from Promise.all() and Promise.race()
1350
1351
1352   function onPossibleParallellAsync(possiblePromise) {
1353     if (task.echoes && possiblePromise && possiblePromise.constructor === NativePromise) {
1354       incrementExpectedAwaits();
1355       return possiblePromise.then(function (x) {
1356         decrementExpectedAwaits();
1357         return x;
1358       }, function (e) {
1359         decrementExpectedAwaits();
1360         return rejection(e);
1361       });
1362     }
1363
1364     return possiblePromise;
1365   }
1366
1367   function zoneEnterEcho(targetZone) {
1368     ++totalEchoes;
1369
1370     if (!task.echoes || --task.echoes === 0) {
1371       task.echoes = task.id = 0; // Cancel zone echoing.
1372     }
1373
1374     zoneStack.push(PSD);
1375     switchToZone(targetZone, true);
1376   }
1377
1378   function zoneLeaveEcho() {
1379     var zone = zoneStack[zoneStack.length - 1];
1380     zoneStack.pop();
1381     switchToZone(zone, false);
1382   }
1383
1384   function switchToZone(targetZone, bEnteringZone) {
1385     var currentZone = PSD;
1386
1387     if (bEnteringZone ? task.echoes && (!zoneEchoes++ || targetZone !== PSD) : zoneEchoes && (! --zoneEchoes || targetZone !== PSD)) {
1388       // Enter or leave zone asynchronically as well, so that tasks initiated during current tick
1389       // will be surrounded by the zone when they are invoked.
1390       enqueueNativeMicroTask(bEnteringZone ? zoneEnterEcho.bind(null, targetZone) : zoneLeaveEcho);
1391     }
1392
1393     if (targetZone === PSD) return;
1394     PSD = targetZone; // The actual zone switch occurs at this line.
1395     // Snapshot on every leave from global zone.
1396
1397     if (currentZone === globalPSD) globalPSD.env = snapShot();
1398
1399     if (patchGlobalPromise) {
1400       // Let's patch the global and native Promises (may be same or may be different)
1401       var GlobalPromise = globalPSD.env.Promise; // Swich environments (may be PSD-zone or the global zone. Both apply.)
1402
1403       var targetEnv = targetZone.env; // Change Promise.prototype.then for native and global Promise (they MAY differ on polyfilled environments, but both can be accessed)
1404       // Must be done on each zone change because the patched method contains targetZone in its closure.
1405
1406       nativePromiseProto.then = targetEnv.nthen;
1407       GlobalPromise.prototype.then = targetEnv.gthen;
1408
1409       if (currentZone.global || targetZone.global) {
1410         // Leaving or entering global zone. It's time to patch / restore global Promise.
1411         // Set this Promise to window.Promise so that transiled async functions will work on Firefox, Safari and IE, as well as with Zonejs and angular.
1412         Object.defineProperty(_global, 'Promise', targetEnv.PromiseProp); // Support Promise.all() etc to work indexedDB-safe also when people are including es6-promise as a module (they might
1413         // not be accessing global.Promise but a local reference to it)
1414
1415         GlobalPromise.all = targetEnv.all;
1416         GlobalPromise.race = targetEnv.race;
1417         GlobalPromise.resolve = targetEnv.resolve;
1418         GlobalPromise.reject = targetEnv.reject;
1419       }
1420     }
1421   }
1422
1423   function snapShot() {
1424     var GlobalPromise = _global.Promise || Promise; // tag 02032020
1425
1426     return patchGlobalPromise ? {
1427       Promise: GlobalPromise,
1428       PromiseProp: Object.getOwnPropertyDescriptor(_global, "Promise"),
1429       all: GlobalPromise.all,
1430       race: GlobalPromise.race,
1431       resolve: GlobalPromise.resolve,
1432       reject: GlobalPromise.reject,
1433       nthen: nativePromiseProto.then,
1434       gthen: GlobalPromise.prototype.then
1435     } : {};
1436   }
1437
1438   function usePSD(psd, fn, a1, a2, a3) {
1439     var outerScope = PSD;
1440
1441     try {
1442       switchToZone(psd, true);
1443       return fn(a1, a2, a3);
1444     } finally {
1445       switchToZone(outerScope, false);
1446     }
1447   }
1448
1449   function enqueueNativeMicroTask(job) {
1450     //
1451     // Precondition: nativePromiseThen !== undefined
1452     //
1453     nativePromiseThen.call(resolvedNativePromise, job);
1454   }
1455
1456   function nativeAwaitCompatibleWrap(fn, zone, possibleAwait) {
1457     return typeof fn !== 'function' ? fn : function () {
1458       var outerZone = PSD;
1459       if (possibleAwait) incrementExpectedAwaits();
1460       switchToZone(zone, true);
1461
1462       try {
1463         return fn.apply(this, arguments);
1464       } finally {
1465         switchToZone(outerZone, false);
1466       }
1467     };
1468   }
1469
1470   function getPatchedPromiseThen(origThen, zone) {
1471     return function (onResolved, onRejected) {
1472       return origThen.call(this, nativeAwaitCompatibleWrap(onResolved, zone, false), nativeAwaitCompatibleWrap(onRejected, zone, false));
1473     };
1474   }
1475
1476   var UNHANDLEDREJECTION = "unhandledrejection";
1477
1478   function globalError(err, promise) {
1479     var rv;
1480
1481     try {
1482       rv = promise.onuncatched(err);
1483     } catch (e) {}
1484
1485     if (rv !== false) try {
1486       var event,
1487           eventData = {
1488         promise: promise,
1489         reason: err
1490       };
1491
1492       if (_global.document && document.createEvent) {
1493         event = document.createEvent('Event');
1494         event.initEvent(UNHANDLEDREJECTION, true, true);
1495         extend(event, eventData);
1496       } else if (_global.CustomEvent) {
1497         event = new CustomEvent(UNHANDLEDREJECTION, {
1498           detail: eventData
1499         });
1500         extend(event, eventData);
1501       }
1502
1503       if (event && _global.dispatchEvent) {
1504         dispatchEvent(event);
1505         if (!_global.PromiseRejectionEvent && _global.onunhandledrejection) // No native support for PromiseRejectionEvent but user has set window.onunhandledrejection. Manually call it.
1506           try {
1507             _global.onunhandledrejection(event);
1508           } catch (_) {}
1509       }
1510
1511       if (!event.defaultPrevented) {
1512         console.warn("Unhandled rejection: " + (err.stack || err));
1513       }
1514     } catch (e) {}
1515   }
1516
1517   var rejection = Promise.reject;
1518
1519   function Events(ctx) {
1520     var evs = {};
1521
1522     var rv = function rv(eventName, subscriber) {
1523       if (subscriber) {
1524         // Subscribe. If additional arguments than just the subscriber was provided, forward them as well.
1525         var i = arguments.length,
1526             args = new Array(i - 1);
1527
1528         while (--i) {
1529           args[i - 1] = arguments[i];
1530         }
1531
1532         evs[eventName].subscribe.apply(null, args);
1533         return ctx;
1534       } else if (typeof eventName === 'string') {
1535         // Return interface allowing to fire or unsubscribe from event
1536         return evs[eventName];
1537       }
1538     };
1539
1540     rv.addEventType = add;
1541
1542     for (var i = 1, l = arguments.length; i < l; ++i) {
1543       add(arguments[i]);
1544     }
1545
1546     return rv;
1547
1548     function add(eventName, chainFunction, defaultFunction) {
1549       if (babelHelpers.typeof(eventName) === 'object') return addConfiguredEvents(eventName);
1550       if (!chainFunction) chainFunction = reverseStoppableEventChain;
1551       if (!defaultFunction) defaultFunction = nop;
1552       var context = {
1553         subscribers: [],
1554         fire: defaultFunction,
1555         subscribe: function subscribe(cb) {
1556           if (context.subscribers.indexOf(cb) === -1) {
1557             context.subscribers.push(cb);
1558             context.fire = chainFunction(context.fire, cb);
1559           }
1560         },
1561         unsubscribe: function unsubscribe(cb) {
1562           context.subscribers = context.subscribers.filter(function (fn) {
1563             return fn !== cb;
1564           });
1565           context.fire = context.subscribers.reduce(chainFunction, defaultFunction);
1566         }
1567       };
1568       evs[eventName] = rv[eventName] = context;
1569       return context;
1570     }
1571
1572     function addConfiguredEvents(cfg) {
1573       // events(this, {reading: [functionChain, nop]});
1574       keys(cfg).forEach(function (eventName) {
1575         var args = cfg[eventName];
1576
1577         if (isArray(args)) {
1578           add(eventName, cfg[eventName][0], cfg[eventName][1]);
1579         } else if (args === 'asap') {
1580           // Rather than approaching event subscription using a functional approach, we here do it in a for-loop where subscriber is executed in its own stack
1581           // enabling that any exception that occur wont disturb the initiator and also not nescessary be catched and forgotten.
1582           var context = add(eventName, mirror, function fire() {
1583             // Optimazation-safe cloning of arguments into args.
1584             var i = arguments.length,
1585                 args = new Array(i);
1586
1587             while (i--) {
1588               args[i] = arguments[i];
1589             } // All each subscriber:
1590
1591
1592             context.subscribers.forEach(function (fn) {
1593               asap(function fireEvent() {
1594                 fn.apply(null, args);
1595               });
1596             });
1597           });
1598         } else throw new exceptions.InvalidArgument("Invalid event config");
1599       });
1600     }
1601   }
1602   /*
1603    * Dexie.js - a minimalistic wrapper for IndexedDB
1604    * ===============================================
1605    *
1606    * Copyright (c) 2014-2017 David Fahlander
1607    *
1608    * Version 2.0.4, Fri May 25 2018
1609    *
1610    * http://dexie.org
1611    *
1612    * Apache License Version 2.0, January 2004, http://www.apache.org/licenses/LICENSE-2.0
1613    *
1614    */
1615
1616
1617   var DEXIE_VERSION = '2.0.4';
1618   var maxString = String.fromCharCode(65535);
1619
1620   var maxKey = function () {
1621     try {
1622       IDBKeyRange.only([[]]);
1623       return [[]];
1624     } catch (e) {
1625       return maxString;
1626     }
1627   }();
1628
1629   var minKey = -Infinity;
1630   var INVALID_KEY_ARGUMENT = "Invalid key provided. Keys must be of type string, number, Date or Array<string | number | Date>.";
1631   var STRING_EXPECTED = "String expected.";
1632   var connections = [];
1633   var isIEOrEdge = typeof navigator !== 'undefined' && /(MSIE|Trident|Edge)/.test(navigator.userAgent);
1634   var hasIEDeleteObjectStoreBug = isIEOrEdge;
1635   var hangsOnDeleteLargeKeyRange = isIEOrEdge;
1636
1637   var dexieStackFrameFilter = function dexieStackFrameFilter(frame) {
1638     return !/(dexie\.js|dexie\.min\.js)/.test(frame);
1639   };
1640
1641   var dbNamesDB; // Global database for backing Dexie.getDatabaseNames() on browser without indexedDB.webkitGetDatabaseNames()
1642   // Init debug
1643
1644   setDebug(debug, dexieStackFrameFilter);
1645
1646   function Dexie(dbName, options) {
1647     /// <param name="options" type="Object" optional="true">Specify only if you wich to control which addons that should run on this instance</param>
1648     var deps = Dexie.dependencies;
1649     var opts = extend({
1650       // Default Options
1651       addons: Dexie.addons,
1652       autoOpen: true,
1653       indexedDB: deps.indexedDB,
1654       IDBKeyRange: deps.IDBKeyRange // Backend IDBKeyRange api. Default to browser env.
1655
1656     }, options);
1657     var addons = opts.addons,
1658         autoOpen = opts.autoOpen,
1659         indexedDB = opts.indexedDB,
1660         IDBKeyRange = opts.IDBKeyRange;
1661     var globalSchema = this._dbSchema = {};
1662     var versions = [];
1663     var dbStoreNames = [];
1664     var allTables = {}; ///<var type="IDBDatabase" />
1665
1666     var idbdb = null; // Instance of IDBDatabase
1667
1668     var dbOpenError = null;
1669     var isBeingOpened = false;
1670     var onReadyBeingFired = null;
1671     var openComplete = false;
1672     var READONLY = "readonly",
1673         READWRITE = "readwrite";
1674     var db = this;
1675     var dbReadyResolve,
1676         dbReadyPromise = new Promise(function (resolve) {
1677       dbReadyResolve = resolve;
1678     }),
1679         cancelOpen,
1680         openCanceller = new Promise(function (_, reject) {
1681       cancelOpen = reject;
1682     });
1683     var autoSchema = true;
1684     var hasNativeGetDatabaseNames = !!getNativeGetDatabaseNamesFn(indexedDB),
1685         hasGetAll;
1686
1687     function init() {
1688       // Default subscribers to "versionchange" and "blocked".
1689       // Can be overridden by custom handlers. If custom handlers return false, these default
1690       // behaviours will be prevented.
1691       db.on("versionchange", function (ev) {
1692         // Default behavior for versionchange event is to close database connection.
1693         // Caller can override this behavior by doing db.on("versionchange", function(){ return false; });
1694         // Let's not block the other window from making it's delete() or open() call.
1695         // NOTE! This event is never fired in IE,Edge or Safari.
1696         if (ev.newVersion > 0) console.warn("Another connection wants to upgrade database '" + db.name + "'. Closing db now to resume the upgrade.");else console.warn("Another connection wants to delete database '" + db.name + "'. Closing db now to resume the delete request.");
1697         db.close(); // In many web applications, it would be recommended to force window.reload()
1698         // when this event occurs. To do that, subscribe to the versionchange event
1699         // and call window.location.reload(true) if ev.newVersion > 0 (not a deletion)
1700         // The reason for this is that your current web app obviously has old schema code that needs
1701         // to be updated. Another window got a newer version of the app and needs to upgrade DB but
1702         // your window is blocking it unless we close it here.
1703       });
1704       db.on("blocked", function (ev) {
1705         if (!ev.newVersion || ev.newVersion < ev.oldVersion) console.warn("Dexie.delete('" + db.name + "') was blocked");else console.warn("Upgrade '" + db.name + "' blocked by other connection holding version " + ev.oldVersion / 10);
1706       });
1707     } //
1708     //
1709     //
1710     // ------------------------- Versioning Framework---------------------------
1711     //
1712     //
1713     //
1714
1715
1716     this.version = function (versionNumber) {
1717       /// <param name="versionNumber" type="Number"></param>
1718       /// <returns type="Version"></returns>
1719       if (idbdb || isBeingOpened) throw new exceptions.Schema("Cannot add version when database is open");
1720       this.verno = Math.max(this.verno, versionNumber);
1721       var versionInstance = versions.filter(function (v) {
1722         return v._cfg.version === versionNumber;
1723       })[0];
1724       if (versionInstance) return versionInstance;
1725       versionInstance = new Version(versionNumber);
1726       versions.push(versionInstance);
1727       versions.sort(lowerVersionFirst); // Disable autoschema mode, as at least one version is specified.
1728
1729       autoSchema = false;
1730       return versionInstance;
1731     };
1732
1733     function Version(versionNumber) {
1734       this._cfg = {
1735         version: versionNumber,
1736         storesSource: null,
1737         dbschema: {},
1738         tables: {},
1739         contentUpgrade: null
1740       };
1741       this.stores({}); // Derive earlier schemas by default.
1742     }
1743
1744     extend(Version.prototype, {
1745       stores: function stores(_stores) {
1746         /// <summary>
1747         ///   Defines the schema for a particular version
1748         /// </summary>
1749         /// <param name="stores" type="Object">
1750         /// Example: <br/>
1751         ///   {users: "id++,first,last,&amp;username,*email", <br/>
1752         ///   passwords: "id++,&amp;username"}<br/>
1753         /// <br/>
1754         /// Syntax: {Table: "[primaryKey][++],[&amp;][*]index1,[&amp;][*]index2,..."}<br/><br/>
1755         /// Special characters:<br/>
1756         ///  "&amp;"  means unique key, <br/>
1757         ///  "*"  means value is multiEntry, <br/>
1758         ///  "++" means auto-increment and only applicable for primary key <br/>
1759         /// </param>
1760         this._cfg.storesSource = this._cfg.storesSource ? extend(this._cfg.storesSource, _stores) : _stores; // Derive stores from earlier versions if they are not explicitely specified as null or a new syntax.
1761
1762         var storesSpec = {};
1763         versions.forEach(function (version) {
1764           extend(storesSpec, version._cfg.storesSource);
1765         });
1766         var dbschema = this._cfg.dbschema = {};
1767
1768         this._parseStoresSpec(storesSpec, dbschema); // Update the latest schema to this version
1769         // Update API
1770
1771
1772         globalSchema = db._dbSchema = dbschema;
1773         removeTablesApi([allTables, db, Transaction.prototype]); // Keep Transaction.prototype even though it should be depr.
1774
1775         setApiOnPlace([allTables, db, Transaction.prototype, this._cfg.tables], keys(dbschema), dbschema);
1776         dbStoreNames = keys(dbschema);
1777         return this;
1778       },
1779       upgrade: function upgrade(upgradeFunction) {
1780         this._cfg.contentUpgrade = upgradeFunction;
1781         return this;
1782       },
1783       _parseStoresSpec: function _parseStoresSpec(stores, outSchema) {
1784         keys(stores).forEach(function (tableName) {
1785           if (stores[tableName] !== null) {
1786             var instanceTemplate = {};
1787             var indexes = parseIndexSyntax(stores[tableName]);
1788             var primKey = indexes.shift();
1789             if (primKey.multi) throw new exceptions.Schema("Primary key cannot be multi-valued");
1790             if (primKey.keyPath) setByKeyPath(instanceTemplate, primKey.keyPath, primKey.auto ? 0 : primKey.keyPath);
1791             indexes.forEach(function (idx) {
1792               if (idx.auto) throw new exceptions.Schema("Only primary key can be marked as autoIncrement (++)");
1793               if (!idx.keyPath) throw new exceptions.Schema("Index must have a name and cannot be an empty string");
1794               setByKeyPath(instanceTemplate, idx.keyPath, idx.compound ? idx.keyPath.map(function () {
1795                 return "";
1796               }) : "");
1797             });
1798             outSchema[tableName] = new TableSchema(tableName, primKey, indexes, instanceTemplate);
1799           }
1800         });
1801       }
1802     });
1803
1804     function runUpgraders(oldVersion, idbtrans, reject) {
1805       var trans = db._createTransaction(READWRITE, dbStoreNames, globalSchema);
1806
1807       trans.create(idbtrans);
1808
1809       trans._completion.catch(reject);
1810
1811       var rejectTransaction = trans._reject.bind(trans);
1812
1813       newScope(function () {
1814         PSD.trans = trans;
1815
1816         if (oldVersion === 0) {
1817           // Create tables:
1818           keys(globalSchema).forEach(function (tableName) {
1819             createTable(idbtrans, tableName, globalSchema[tableName].primKey, globalSchema[tableName].indexes);
1820           });
1821           Promise.follow(function () {
1822             return db.on.populate.fire(trans);
1823           }).catch(rejectTransaction);
1824         } else updateTablesAndIndexes(oldVersion, trans, idbtrans).catch(rejectTransaction);
1825       });
1826     }
1827
1828     function updateTablesAndIndexes(oldVersion, trans, idbtrans) {
1829       // Upgrade version to version, step-by-step from oldest to newest version.
1830       // Each transaction object will contain the table set that was current in that version (but also not-yet-deleted tables from its previous version)
1831       var queue = [];
1832       var oldVersionStruct = versions.filter(function (version) {
1833         return version._cfg.version === oldVersion;
1834       })[0];
1835       if (!oldVersionStruct) throw new exceptions.Upgrade("Dexie specification of currently installed DB version is missing");
1836       globalSchema = db._dbSchema = oldVersionStruct._cfg.dbschema;
1837       var anyContentUpgraderHasRun = false;
1838       var versToRun = versions.filter(function (v) {
1839         return v._cfg.version > oldVersion;
1840       });
1841       versToRun.forEach(function (version) {
1842         /// <param name="version" type="Version"></param>
1843         queue.push(function () {
1844           var oldSchema = globalSchema;
1845           var newSchema = version._cfg.dbschema;
1846           adjustToExistingIndexNames(oldSchema, idbtrans);
1847           adjustToExistingIndexNames(newSchema, idbtrans);
1848           globalSchema = db._dbSchema = newSchema;
1849           var diff = getSchemaDiff(oldSchema, newSchema); // Add tables
1850
1851           diff.add.forEach(function (tuple) {
1852             createTable(idbtrans, tuple[0], tuple[1].primKey, tuple[1].indexes);
1853           }); // Change tables
1854
1855           diff.change.forEach(function (change) {
1856             if (change.recreate) {
1857               throw new exceptions.Upgrade("Not yet support for changing primary key");
1858             } else {
1859               var store = idbtrans.objectStore(change.name); // Add indexes
1860
1861               change.add.forEach(function (idx) {
1862                 addIndex(store, idx);
1863               }); // Update indexes
1864
1865               change.change.forEach(function (idx) {
1866                 store.deleteIndex(idx.name);
1867                 addIndex(store, idx);
1868               }); // Delete indexes
1869
1870               change.del.forEach(function (idxName) {
1871                 store.deleteIndex(idxName);
1872               });
1873             }
1874           });
1875
1876           if (version._cfg.contentUpgrade) {
1877             anyContentUpgraderHasRun = true;
1878             return Promise.follow(function () {
1879               version._cfg.contentUpgrade(trans);
1880             });
1881           }
1882         });
1883         queue.push(function (idbtrans) {
1884           if (!anyContentUpgraderHasRun || !hasIEDeleteObjectStoreBug) {
1885             var newSchema = version._cfg.dbschema; // Delete old tables
1886
1887             deleteRemovedTables(newSchema, idbtrans);
1888           }
1889         });
1890       }); // Now, create a queue execution engine
1891
1892       function runQueue() {
1893         return queue.length ? Promise.resolve(queue.shift()(trans.idbtrans)).then(runQueue) : Promise.resolve();
1894       }
1895
1896       return runQueue().then(function () {
1897         createMissingTables(globalSchema, idbtrans); // At last, make sure to create any missing tables. (Needed by addons that add stores to DB without specifying version)
1898       });
1899     }
1900
1901     function getSchemaDiff(oldSchema, newSchema) {
1902       var diff = {
1903         del: [],
1904         add: [],
1905         change: [] // Array of {name: tableName, recreate: newDefinition, del: delIndexNames, add: newIndexDefs, change: changedIndexDefs}
1906
1907       };
1908
1909       for (var table in oldSchema) {
1910         if (!newSchema[table]) diff.del.push(table);
1911       }
1912
1913       for (table in newSchema) {
1914         var oldDef = oldSchema[table],
1915             newDef = newSchema[table];
1916
1917         if (!oldDef) {
1918           diff.add.push([table, newDef]);
1919         } else {
1920           var change = {
1921             name: table,
1922             def: newDef,
1923             recreate: false,
1924             del: [],
1925             add: [],
1926             change: []
1927           };
1928
1929           if (oldDef.primKey.src !== newDef.primKey.src) {
1930             // Primary key has changed. Remove and re-add table.
1931             change.recreate = true;
1932             diff.change.push(change);
1933           } else {
1934             // Same primary key. Just find out what differs:
1935             var oldIndexes = oldDef.idxByName;
1936             var newIndexes = newDef.idxByName;
1937
1938             for (var idxName in oldIndexes) {
1939               if (!newIndexes[idxName]) change.del.push(idxName);
1940             }
1941
1942             for (idxName in newIndexes) {
1943               var oldIdx = oldIndexes[idxName],
1944                   newIdx = newIndexes[idxName];
1945               if (!oldIdx) change.add.push(newIdx);else if (oldIdx.src !== newIdx.src) change.change.push(newIdx);
1946             }
1947
1948             if (change.del.length > 0 || change.add.length > 0 || change.change.length > 0) {
1949               diff.change.push(change);
1950             }
1951           }
1952         }
1953       }
1954
1955       return diff;
1956     }
1957
1958     function createTable(idbtrans, tableName, primKey, indexes) {
1959       /// <param name="idbtrans" type="IDBTransaction"></param>
1960       var store = idbtrans.db.createObjectStore(tableName, primKey.keyPath ? {
1961         keyPath: primKey.keyPath,
1962         autoIncrement: primKey.auto
1963       } : {
1964         autoIncrement: primKey.auto
1965       });
1966       indexes.forEach(function (idx) {
1967         addIndex(store, idx);
1968       });
1969       return store;
1970     }
1971
1972     function createMissingTables(newSchema, idbtrans) {
1973       keys(newSchema).forEach(function (tableName) {
1974         if (!idbtrans.db.objectStoreNames.contains(tableName)) {
1975           createTable(idbtrans, tableName, newSchema[tableName].primKey, newSchema[tableName].indexes);
1976         }
1977       });
1978     }
1979
1980     function deleteRemovedTables(newSchema, idbtrans) {
1981       for (var i = 0; i < idbtrans.db.objectStoreNames.length; ++i) {
1982         var storeName = idbtrans.db.objectStoreNames[i];
1983
1984         if (newSchema[storeName] == null) {
1985           idbtrans.db.deleteObjectStore(storeName);
1986         }
1987       }
1988     }
1989
1990     function addIndex(store, idx) {
1991       store.createIndex(idx.name, idx.keyPath, {
1992         unique: idx.unique,
1993         multiEntry: idx.multi
1994       });
1995     } //
1996     //
1997     //      Dexie Protected API
1998     //
1999     //
2000
2001
2002     this._allTables = allTables;
2003
2004     this._createTransaction = function (mode, storeNames, dbschema, parentTransaction) {
2005       return new Transaction(mode, storeNames, dbschema, parentTransaction);
2006     };
2007     /* Generate a temporary transaction when db operations are done outside a transaction scope.
2008     */
2009
2010
2011     function tempTransaction(mode, storeNames, fn) {
2012       if (!openComplete && !PSD.letThrough) {
2013         if (!isBeingOpened) {
2014           if (!autoOpen) return rejection(new exceptions.DatabaseClosed());
2015           db.open().catch(nop); // Open in background. If if fails, it will be catched by the final promise anyway.
2016         }
2017
2018         return dbReadyPromise.then(function () {
2019           return tempTransaction(mode, storeNames, fn);
2020         });
2021       } else {
2022         var trans = db._createTransaction(mode, storeNames, globalSchema);
2023
2024         try {
2025           trans.create();
2026         } catch (ex) {
2027           return rejection(ex);
2028         }
2029
2030         return trans._promise(mode, function (resolve, reject) {
2031           return newScope(function () {
2032             PSD.trans = trans;
2033             return fn(resolve, reject, trans);
2034           });
2035         }).then(function (result) {
2036           // Instead of resolving value directly, wait with resolving it until transaction has completed.
2037           // Otherwise the data would not be in the DB if requesting it in the then() operation.
2038           // Specifically, to ensure that the following expression will work:
2039           //
2040           //   db.friends.put({name: "Arne"}).then(function () {
2041           //       db.friends.where("name").equals("Arne").count(function(count) {
2042           //           assert (count === 1);
2043           //       });
2044           //   });
2045           //
2046           return trans._completion.then(function () {
2047             return result;
2048           });
2049         });
2050         /*.catch(err => { // Don't do this as of now. If would affect bulk- and modify methods in a way that could be more intuitive. But wait! Maybe change in next major.
2051         trans._reject(err);
2052         return rejection(err);
2053         });*/
2054       }
2055     }
2056
2057     this._whenReady = function (fn) {
2058       return openComplete || PSD.letThrough ? fn() : new Promise(function (resolve, reject) {
2059         if (!isBeingOpened) {
2060           if (!autoOpen) {
2061             reject(new exceptions.DatabaseClosed());
2062             return;
2063           }
2064
2065           db.open().catch(nop); // Open in background. If if fails, it will be catched by the final promise anyway.
2066         }
2067
2068         dbReadyPromise.then(resolve, reject);
2069       }).then(fn);
2070     }; //
2071     //
2072     //
2073     //
2074     //      Dexie API
2075     //
2076     //
2077     //
2078
2079
2080     this.verno = 0;
2081
2082     this.open = function () {
2083       if (isBeingOpened || idbdb) return dbReadyPromise.then(function () {
2084         return dbOpenError ? rejection(dbOpenError) : db;
2085       });
2086       debug && (openCanceller._stackHolder = getErrorWithStack()); // Let stacks point to when open() was called rather than where new Dexie() was called.
2087
2088       isBeingOpened = true;
2089       dbOpenError = null;
2090       openComplete = false; // Function pointers to call when the core opening process completes.
2091
2092       var resolveDbReady = dbReadyResolve,
2093           // upgradeTransaction to abort on failure.
2094       upgradeTransaction = null;
2095       return Promise.race([openCanceller, new Promise(function (resolve, reject) {
2096         // Multiply db.verno with 10 will be needed to workaround upgrading bug in IE:
2097         // IE fails when deleting objectStore after reading from it.
2098         // A future version of Dexie.js will stopover an intermediate version to workaround this.
2099         // At that point, we want to be backward compatible. Could have been multiplied with 2, but by using 10, it is easier to map the number to the real version number.
2100         // If no API, throw!
2101         if (!indexedDB) throw new exceptions.MissingAPI("indexedDB API 
2101not found. If using IE10+, make sure to run your code on a server URL " + "(not locally). If using old Safari versions, make sure to include indexedDB polyfill.");
2102         var req = autoSchema ? indexedDB.open(dbName) : indexedDB.open(dbName, Math.round(db.verno * 10));
2103         if (!req) throw new exceptions.MissingAPI("IndexedDB API not available"); // May happen in Safari private mode, see https://github.com/dfahlander/Dexie.js/issues/134
2104
2105         req.onerror = eventRejectHandler(reject);
2106         req.onblocked = wrap(fireOnBlocked);
2107         req.onupgradeneeded = wrap(function (e) {
2108           upgradeTransaction = req.transaction;
2109
2110           if (autoSchema && !db._allowEmptyDB) {
2111             // Caller did not specify a version or schema. Doing that is only acceptable for opening alread existing databases.
2112             // If onupgradeneeded is called it means database did not exist. Reject the open() promise and make sure that we
2113             // do not create a new database by accident here.
2114             req.onerror = preventDefault; // Prohibit onabort error from firing before we're done!
2115
2116             upgradeTransaction.abort(); // Abort transaction (would hope that this would make DB disappear but it doesnt.)
2117             // Close database and delete it.
2118
2119             req.result.close();
2120             var delreq = indexedDB.deleteDatabase(dbName); // The upgrade transaction is atomic, and javascript is single threaded - meaning that there is no risk that we delete someone elses database here!
2121
2122             delreq.onsuccess = delreq.onerror = wrap(function () {
2123               reject(new exceptions.NoSuchDatabase("Database " + dbName + " doesnt exist"));
2124             });
2125           } else {
2126             upgradeTransaction.onerror = eventRejectHandler(reject);
2127             var oldVer = e.oldVersion > Math.pow(2, 62) ? 0 : e.oldVersion; // Safari 8 fix.
2128
2129             runUpgraders(oldVer / 10, upgradeTransaction, reject, req);
2130           }
2131         }, reject);
2132         req.onsuccess = wrap(function () {
2133           // Core opening procedure complete. Now let's just record some stuff.
2134           upgradeTransaction = null;
2135           idbdb = req.result;
2136           connections.push(db); // Used for emulating versionchange event on IE/Edge/Safari.
2137
2138           if (autoSchema) readGlobalSchema();else if (idbdb.objectStoreNames.length > 0) {
2139             try {
2140               adjustToExistingIndexNames(globalSchema, idbdb.transaction(safariMultiStoreFix(idbdb.objectStoreNames), READONLY));
2141             } catch (e) {// Safari may bail out if > 1 store names. However, this shouldnt be a showstopper. Issue #120.
2142             }
2143           }
2144           idbdb.onversionchange = wrap(function (ev) {
2145             db._vcFired = true; // detect implementations that not support versionchange (IE/Edge/Safari)
2146
2147             db.on("versionchange").fire(ev);
2148           });
2149
2150           if (!hasNativeGetDatabaseNames && dbName !== '__dbnames') {
2151             dbNamesDB.dbnames.put({
2152               name: dbName
2153             }).catch(nop);
2154           }
2155
2156           resolve();
2157         }, reject);
2158       })]).then(function () {
2159         // Before finally resolving the dbReadyPromise and this promise,
2160         // call and await all on('ready') subscribers:
2161         // Dexie.vip() makes subscribers able to use the database while being opened.
2162         // This is a must since these subscribers take part of the opening procedure.
2163         onReadyBeingFired = [];
2164         return Promise.resolve(Dexie.vip(db.on.ready.fire)).then(function fireRemainders() {
2165           if (onReadyBeingFired.length > 0) {
2166             // In case additional subscribers to db.on('ready') were added during the time db.on.ready.fire was executed.
2167             var remainders = onReadyBeingFired.reduce(promisableChain, nop);
2168             onReadyBeingFired = [];
2169             return Promise.resolve(Dexie.vip(remainders)).then(fireRemainders);
2170           }
2171         });
2172       }).finally(function () {
2173         onReadyBeingFired = null;
2174       }).then(function () {
2175         // Resolve the db.open() with the db instance.
2176         isBeingOpened = false;
2177         return db;
2178       }).catch(function (err) {
2179         try {
2180           // Did we fail within onupgradeneeded? Make sure to abort the upgrade transaction so it doesnt commit.
2181           upgradeTransaction && upgradeTransaction.abort();
2182         } catch (e) {}
2183
2184         isBeingOpened = false; // Set before calling db.close() so that it doesnt reject openCanceller again (leads to unhandled rejection event).
2185
2186         db.close(); // Closes and resets idbdb, removes connections, resets dbReadyPromise and openCanceller so that a later db.open() is fresh.
2187         // A call to db.close() may have made on-ready subscribers fail. Use dbOpenError if set, since err could be a follow-up error on that.
2188
2189         dbOpenError = err; // Record the error. It will be used to reject further promises of db operations.
2190
2191         return rejection(dbOpenError);
2192       }).finally(function () {
2193         openComplete = true;
2194         resolveDbReady(); // dbReadyPromise is resolved no matter if open() rejects or resolved. It's just to wake up waiters.
2195       });
2196     };
2197
2198     this.close = function () {
2199       var idx = connections.indexOf(db);
2200       if (idx >= 0) connections.splice(idx, 1);
2201
2202       if (idbdb) {
2203         try {
2204           idbdb.close();
2205         } catch (e) {}
2206
2207         idbdb = null;
2208       }
2209
2210       autoOpen = false;
2211       dbOpenError = new exceptions.DatabaseClosed();
2212       if (isBeingOpened) cancelOpen(dbOpenError); // Reset dbReadyPromise promise:
2213
2214       dbReadyPromise = new Promise(function (resolve) {
2215         dbReadyResolve = resolve;
2216       });
2217       openCanceller = new Promise(function (_, reject) {
2218         cancelOpen = reject;
2219       });
2220     };
2221
2222     this.delete = function () {
2223       var hasArguments = arguments.length > 0;
2224       return new Promise(function (resolve, reject) {
2225         if (hasArguments) throw new exceptions.InvalidArgument("Arguments not allowed in db.delete()");
2226
2227         if (isBeingOpened) {
2228           dbReadyPromise.then(doDelete);
2229         } else {
2230           doDelete();
2231         }
2232
2233         function doDelete() {
2234           db.close();
2235           var req = indexedDB.deleteDatabase(dbName);
2236           req.onsuccess = wrap(function () {
2237             if (!hasNativeGetDatabaseNames) {
2238               dbNamesDB.dbnames.delete(dbName).catch(nop);
2239             }
2240
2241             resolve();
2242           });
2243           req.onerror = eventRejectHandler(reject);
2244           req.onblocked = fireOnBlocked;
2245         }
2246       });
2247     };
2248
2249     this.backendDB = function () {
2250       return idbdb;
2251     };
2252
2253     this.isOpen = function () {
2254       return idbdb !== null;
2255     };
2256
2257     this.hasBeenClosed = function () {
2258       return dbOpenError && dbOpenError instanceof exceptions.DatabaseClosed;
2259     };
2260
2261     this.hasFailed = function () {
2262       return dbOpenError !== null;
2263     };
2264
2265     this.dynamicallyOpened = function () {
2266       return autoSchema;
2267     }; //
2268     // Properties
2269     //
2270
2271
2272     this.name = dbName; // db.tables - an array of all Table instances.
2273
2274     props(this, {
2275       tables: {
2276         get: function get() {
2277           /// <returns type="Array" elementType="Table" />
2278           return keys(allTables).map(function (name) {
2279             return allTables[name];
2280           });
2281         }
2282       }
2283     }); //
2284     // Events
2285     //
2286
2287     this.on = Events(this, "populate", "blocked", "versionchange", {
2288       ready: [promisableChain, nop]
2289     });
2290     this.on.ready.subscribe = override(this.on.ready.subscribe, function (subscribe) {
2291       return function (subscriber, bSticky) {
2292         Dexie.vip(function () {
2293           if (openComplete) {
2294             // Database already open. Call subscriber asap.
2295             if (!dbOpenError) Promise.resolve().then(subscriber); // bSticky: Also subscribe to future open sucesses (after close / reopen)
2296
2297             if (bSticky) subscribe(subscriber);
2298           } else if (onReadyBeingFired) {
2299             // db.on('ready') subscribers are currently being executed and have not yet resolved or rejected
2300             onReadyBeingFired.push(subscriber);
2301             if (bSticky) subscribe(subscriber);
2302           } else {
2303             // Database not yet open. Subscribe to it.
2304             subscribe(subscriber);
2304 // If bSticky is falsy, make sure to unsubscribe subscriber when fired once.
2305
2306             if (!bSticky) subscribe(function unsubscribe() {
2307               db.on.ready.unsubscribe(subscriber);
2308               db.on.ready.unsubscribe(unsubscribe);
2309             });
2310           }
2311         });
2312       };
2313     });
2314
2315     this.transaction = function () {
2316       /// <summary>
2317       ///
2318       /// </summary>
2319       /// <param name="mode" type="String">"r" for readonly, or "rw" for readwrite</param>
2320       /// <param name="tableInstances">Table instance, Array of Table instances, String or String Array of object stores to include in the transaction</param>
2321       /// <param name="scopeFunc" type="Function">Function to execute with transaction</param>
2322       var args = extractTransactionArgs.apply(this, arguments);
2323       return this._transaction.apply(this, args);
2324     };
2325
2326     function extractTransactionArgs(mode, _tableArgs_, scopeFunc) {
2327       // Let table arguments be all arguments between mode and last argument.
2328       var i = arguments.length;
2329       if (i < 2) throw new exceptions.InvalidArgument("Too few arguments"); // Prevent optimzation killer (https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments)
2330       // and clone arguments except the first one into local var 'args'.
2331
2332       var args = new Array(i - 1);
2333
2334       while (--i) {
2335         args[i - 1] = arguments[i];
2336       } // Let scopeFunc be the last argument and pop it so that args now only contain the table arguments.
2337
2338
2339       scopeFunc = args.pop();
2340       var tables = flatten(args); // Support using array as middle argument, or a mix of arrays and non-arrays.
2341
2342       return [mode, tables, scopeFunc];
2343     }
2344
2345     this._transaction = function (mode, tables, scopeFunc) {
2346       var parentTransaction = PSD.trans; // Check if parent transactions is bound to this db instance, and if caller wants to reuse it
2347
2348       if (!parentTransaction || parentTransaction.db !== db || mode.indexOf('!') !== -1) parentTransaction = null;
2349       var onlyIfCompatible = mode.indexOf('?') !== -1;
2350       mode = mode.replace('!', '').replace('?', ''); // Ok. Will change arguments[0] as well but we wont touch arguments henceforth.
2351
2352       try {
2353         //
2354         // Get storeNames from arguments. Either through given table instances, or through given table names.
2355         //
2356         var storeNames = tables.map(function (table) {
2357           var storeName = table instanceof Table ? table.name : table;
2358           if (typeof storeName !== 'string') throw new TypeError("Invalid table argument to Dexie.transaction(). Only Table or String are allowed");
2359           return storeName;
2360         }); //
2361         // Resolve mode. Allow shortcuts "r" and "rw".
2362         //
2363
2364         if (mode == "r" || mode == READONLY) mode = READONLY;else if (mode == "rw" || mode == READWRITE) mode = READWRITE;else throw new exceptions.InvalidArgument("Invalid transaction mode: " + mode);
2365
2366         if (parentTransaction) {
2367           // Basic checks
2368           if (parentTransaction.mode === READONLY && mode === READWRITE) {
2369             if (onlyIfCompatible) {
2370               // Spawn new transaction instead.
2371               parentTransaction = null;
2372             } else throw new exceptions.SubTransaction("Cannot enter a sub-transaction with READWRITE mode when parent transaction is READONLY");
2373           }
2374
2375           if (parentTransaction) {
2376             storeNames.forEach(function (storeName) {
2377               if (parentTransaction && parentTransaction.storeNames.indexOf(storeName) === -1) {
2378                 if (onlyIfCompatible) {
2379                   // Spawn new transaction instead.
2380                   parentTransaction = null;
2381                 } else throw new exceptions.SubTransaction("Table " + storeName + " not included in parent transaction.");
2382               }
2383             });
2384           }
2385
2386           if (onlyIfCompatible && parentTransaction && !parentTransaction.active) {
2387             // '?' mode should not keep using an inactive transaction.
2388             parentTransaction = null;
2389           }
2390         }
2391       } catch (e) {
2392         return parentTransaction ? parentTransaction._promise(null, function (_, reject) {
2393           reject(e);
2394         }) : rejection(e);
2395       } // If this is a sub-transaction, lock the parent and then launch the sub-transaction.
2396
2397
2398       return parentTransaction ? parentTransaction._promise(mode, enterTransactionScope, "lock") : PSD.trans ? // no parent transaction despite PSD.trans exists. Make sure also
2399       // that the zone we create is not a sub-zone of current, because
2400       // Promise.follow() should not wait for it if so.
2401       usePSD(PSD.transless, function () {
2402         return db._whenReady(enterTransactionScope);
2403       }) : db._whenReady(enterTransactionScope);
2404
2405       function enterTransactionScope() {
2406         return Promise.resolve().then(function () {
2407           // Keep a pointer to last non-transactional PSD to use if someone calls Dexie.ignoreTransaction().
2408           var transless = PSD.transless || PSD; // Our transaction.
2409           //return new Promise((resolve, reject) => {
2410
2411           var trans = db._createTransaction(mode, storeNames, globalSchema, parentTransaction); // Let the transaction instance be part of a Promise-specific data (PSD) value.
2412
2413
2414           var zoneProps = {
2415             trans: trans,
2416             transless: transless
2417           };
2418
2419           if (parentTransaction) {
2420             // Emulate transaction commit awareness for inner transaction (must 'commit' when the inner transaction has no more operations ongoing)
2421             trans.idbtrans = parentTransaction.idbtrans;
2422           } else {
2423             trans.create(); // Create the backend transaction so that complete() or error() will trigger even if no operation is made upon it.
2424           } // Support for native async await.
2425
2426
2427           if (scopeFunc.constructor === AsyncFunction) {
2428             incrementExpectedAwaits();
2429           }
2430
2431           var returnValue;
2432           var promiseFollowed = Promise.follow(function () {
2433             // Finally, call the scope function with our table and transaction arguments.
2434             returnValue = scopeFunc.call(trans, trans);
2435
2436             if (returnValue) {
2437               if (returnValue.constructor === NativePromise) {
2438                 var decrementor = decrementExpectedAwaits.bind(null, null);
2439                 returnValue.then(decrementor, decrementor);
2440               } else if (typeof returnValue.next === 'function' && typeof returnValue.throw === 'function') {
2441                 // scopeFunc returned an iterator with throw-support. Handle yield as await.
2442                 returnValue = awaitIterator(returnValue);
2443               }
2444             }
2445           }, zoneProps);
2446           return (returnValue && typeof returnValue.then === 'function' ? // Promise returned. User uses promise-style transactions.
2447           Promise.resolve(returnValue).then(function (x) {
2448             return trans.active ? x // Transaction still active. Continue.
2449             : rejection(new exceptions.PrematureCommit("Transaction committed too early. See http://bit.ly/2kdckMn"));
2450           }) // No promise returned. Wait for all outstanding promises before continuing.
2451           : promiseFollowed.then(function () {
2452             return returnValue;
2453           })).then(function (x) {
2454             // sub transactions don't react to idbtrans.oncomplete. We must trigger a completion:
2455             if (parentTransaction) trans._resolve(); // wait for trans._completion
2456             // (if root transaction, this means 'complete' event. If sub-transaction, we've just fired it ourselves)
2457
2458             return trans._completion.then(function () {
2459               return x;
2460             });
2461           }).catch(function (e) {
2462             trans._reject(e); // Yes, above then-handler were maybe not called because of an unhandled rejection in scopeFunc!
2463
2464
2465             return rejection(e);
2466           });
2467         });
2468       }
2469     };
2470
2471     this.table = function (tableName) {
2472       /// <returns type="Table"></returns>
2473       if (!hasOwn(allTables, tableName)) {
2474         throw new exceptions.InvalidTable("Table " + tableName + " does not exist");
2475       }
2476
2477       return allTables[tableName];
2478     }; //
2479     //
2480     //
2481     // Table Class
2482     //
2483     //
2484     //
2485
2486
2487     function Table(name, tableSchema, optionalTrans) {
2488       /// <param name="name" type="String"></param>
2489       this.name = name;
2490       this.schema = tableSchema;
2491       this._tx = optionalTrans;
2492       this.hook = allTables[name] ? allTables[name].hook : Events(null, {
2493         "creating": [hookCreatingChain, nop],
2494         "reading": [pureFunctionChain, mirror],
2495         "updating": [hookUpdatingChain, nop],
2496         "deleting": [hookDeletingChain, nop]
2497       });
2498     }
2499
2500     function BulkErrorHandlerCatchAll(errorList, done, supportHooks) {
2501       return (supportHooks ? hookedEventRejectHandler : eventRejectHandler)(function (e) {
2502         errorList.push(e);
2503         done && done();
2504       });
2505     }
2506
2507     function _bulkDelete(idbstore, trans, keysOrTuples, hasDeleteHook, deletingHook) {
2508       // If hasDeleteHook, keysOrTuples must be an array of tuples: [[key1, value2],[key2,value2],...],
2509       // else keysOrTuples must be just an array of keys: [key1, key2, ...].
2510       return new Promise(function (resolve, reject) {
2511         var len = keysOrTuples.length,
2512             lastItem = len - 1;
2513         if (len === 0) return resolve();
2514
2515         if (!hasDeleteHook) {
2516           for (var i = 0; i < len; ++i) {
2517             var req = idbstore.delete(keysOrTuples[i]);
2518             req.onerror = eventRejectHandler(reject);
2519             if (i === lastItem) req.onsuccess = wrap(function () {
2520               return resolve();
2521             });
2522           }
2523         } else {
2524           var hookCtx,
2525               errorHandler = hookedEventRejectHandler(reject),
2526               successHandler = hookedEventSuccessHandler(null);
2527           tryCatch(function () {
2528             for (var i = 0; i < len; ++i) {
2529               hookCtx = {
2530                 onsuccess: null,
2531                 onerror: null
2532               };
2533               var tuple = keysOrTuples[i];
2534               deletingHook.call(hookCtx, tuple[0], tuple[1], trans);
2535               var req = idbstore.delete(tuple[0]);
2536               req._hookCtx = hookCtx;
2537               req.onerror = errorHandler;
2538               if (i === lastItem) req.onsuccess = hookedEventSuccessHandler(resolve);else req.onsuccess = successHandler;
2539             }
2540           }, function (err) {
2541             hookCtx.onerror && hookCtx.onerror(err);
2542             throw err;
2543           });
2544         }
2545       });
2546     }
2547
2548     props(Table.prototype, {
2549       //
2550       // Table Protected Methods
2551       //
2552       _trans: function getTransaction(mode, fn, writeLocked) {
2553         var trans = this._tx || PSD.trans;
2554         return trans && trans.db === db ? trans === PSD.trans ? trans._promise(mode, fn, writeLocked) : newScope(function () {
2555           return trans._promise(mode, fn, writeLocked);
2556         }, {
2557           trans: trans,
2558           transless: PSD.transless || PSD
2559         }) : tempTransaction(mode, [this.name], fn);
2560       },
2561       _idbstore: function getIDBObjectStore(mode, fn, writeLocked) {
2562         var tableName = this.name;
2563
2564         function supplyIdbStore(resolve, reject, trans) {
2565           if (trans.storeNames.indexOf(tableName) === -1) throw new exceptions.NotFound("Table" + tableName + " not part of transaction");
2566           return fn(resolve, reject, trans.idbtrans.objectStore(tableName), trans);
2567         }
2568
2569         return this._trans(mode, supplyIdbStore, writeLocked);
2570       },
2571       //
2572       // Table Public Methods
2573       //
2574       get: function get(keyOrCrit, cb) {
2575         if (keyOrCrit && keyOrCrit.constructor === Object) return this.where(keyOrCrit).first(cb);
2576         var self = this;
2577         return this._idbstore(READONLY, function (resolve, reject, idbstore) {
2578           var req = idbstore.get(keyOrCrit);
2579           req.onerror = eventRejectHandler(reject);
2580           req.onsuccess = wrap(function () {
2581             resolve(self.hook.reading.fire(req.result));
2582           }, reject);
2583         }).then(cb);
2584       },
2585       where: function where(indexOrCrit) {
2586         if (typeof indexOrCrit === 'string') return new WhereClause(this, indexOrCrit);
2587         if (isArray(indexOrCrit)) return new WhereClause(this, "[" + indexOrCrit.join('+') + "]"); // indexOrCrit is an object map of {[keyPath]:value}
2588
2589         var keyPaths = keys(indexOrCrit);
2590         if (keyPaths.length === 1) // Only one critera. This was the easy case:
2591           return this.where(keyPaths[0]).equals(indexOrCrit[keyPaths[0]]); // Multiple criterias.
2592         // Let's try finding a compound index that matches all keyPaths in
2593         // arbritary order:
2594
2595         var compoundIndex = this.schema.indexes.concat(this.schema.primKey).filter(function (ix) {
2596           return ix.compound && keyPaths.every(function (keyPath) {
2597             return ix.keyPath.indexOf(keyPath) >= 0;
2598           }) && ix.keyPath.every(function (keyPath) {
2599             return keyPaths.indexOf(keyPath) >= 0;
2600           });
2601         })[0];
2602         if (compoundIndex && maxKey !== maxString) // Cool! We found such compound index
2603           // and this browser supports compound indexes (maxKey !== maxString)!
2604           return this.where(compoundIndex.name).equals(compoundIndex.keyPath.map(function (kp) {
2605             return indexOrCrit[kp];
2606           }));
2607         if (!compoundIndex) console.warn("The query " + JSON.stringify(indexOrCrit) + " on " + this.name + " would benefit of a " + ("compound index [" + keyPaths.join('+') + "]")); // Ok, now let's fallback to finding at least one matching index
2608         // and filter the rest.
2609
2610         var idxByName = this.schema.idxByName;
2611         var simpleIndex = keyPaths.reduce(function (r, keyPath) {
2612           return [r[0] || idxByName[keyPath], r[0] || !idxByName[keyPath] ? combine(r[1], function (x) {
2613             return '' + getByKeyPath(x, keyPath) == '' + indexOrCrit[keyPath];
2614           }) : r[1]];
2615         }, [null, null]);
2616         var idx = simpleIndex[0];
2617         return idx ? this.where(idx.name).equals(indexOrCrit[idx.keyPath]).filter(simpleIndex[1]) : compoundIndex ? this.filter(simpleIndex[1]) : // Has compound but browser bad. Allow filter.
2618         this.where(keyPaths).equals(''); // No index at all. Fail lazily.
2619       },
2620       count: function count(cb) {
2621         return this.toCollection().count(cb);
2622       },
2623       offset: function offset(_offset) {
2624         return this.toCollection().offset(_offset);
2625       },
2626       limit: function limit(numRows) {
2627         return this.toCollection().limit(numRows);
2628       },
2629       reverse: function reverse() {
2630         return this.toCollection().reverse();
2631       },
2632       filter: function filter(filterFunction) {
2633         return this.toCollection().and(filterFunction);
2634       },
2635       each: function each(fn) {
2636         return this.toCollection().each(fn);
2637       },
2638       toArray: function toArray(cb) {
2639         return this.toCollection().toArray(cb);
2640       },
2641       orderBy: function orderBy(index) {
2642         return new Collection(new WhereClause(this, isArray(index) ? "[" + index.join('+') + "]" : index));
2643       },
2644       toCollection: function toCollection() {
2645         return new Collection(new WhereClause(this));
2646       },
2647       mapToClass: function mapToClass(constructor, structure) {
2648         /// <summary>
2649         ///     Map table to a javascript constructor function. Objects returned from the database will be instances of this class, making
2650         ///     it possible to the instanceOf operator as well as extending the class using constructor.prototype.method = function(){...}.
2651         /// </summary>
2652         /// <param name="constructor">Constructor function representing the class.</param>
2653         /// <param name="structure" optional="true">Helps IDE code completion by knowing the members that objects contain and not just the indexes. Also
2654         /// know what type each member has. Example: {name: String, emailAddresses: [String], password}</param>
2655         this.schema.mappedClass = constructor;
2656         var instanceTemplate = Object.create(constructor.prototype);
2657
2658         if (structure) {
2659           // structure and instanceTemplate is for IDE code competion only while constructor.prototype is for actual inheritance.
2660           applyStructure(instanceTemplate, structure);
2661         }
2662
2663         this.schema.instanceTemplate = instanceTemplate; // Now, subscribe to the when("reading") event to make all objects that come out from this table inherit from given class
2664         // no matter which method to use for reading (Table.get() or Table.where(...)... )
2665
2666         var readHook = function readHook(obj) {
2667           if (!obj) return obj; // No valid object. (Value is null). Return as is.
2668           // Create a new object that derives from constructor:
2669
2670           var res = Object.create(constructor.prototype); // Clone members:
2671
2672           for (var m in obj) {
2673             if (hasOwn(obj, m)) try {
2674               res[m] = obj[m];
2675             } catch (_) {}
2676           }
2677
2678           return res;
2679         };
2680
2681         if (this.schema.readHook) {
2682           this.hook.reading.unsubscribe(this.schema.readHook);
2683         }
2684
2685         this.schema.readHook = readHook;
2686         this.hook("reading", readHook);
2687         return constructor;
2688       },
2689       defineClass: function defineClass(structure) {
2690         /// <summary>
2691         ///     Define all members of the class that represents the table. This will help code completion of when objects are read from the database
2692         ///     as well as making it possible to extend the prototype of the returned constructor function.
2693         /// </summary>
2694         /// <param name="structure">Helps IDE code completion by knowing the members that objects contain and not just the indexes. Also
2695         /// know what type each member has. Example: {name: String, emailAddresses: [String], properties: {shoeSize: Number}}</param>
2696         return this.mapToClass(Dexie.defineClass(structure), structure);
2697       },
2698       bulkDelete: function bulkDelete(keys$$1) {
2699         if (this.hook.deleting.fire === nop) {
2700           return this._idbstore(READWRITE, function (resolve, reject, idbstore, trans) {
2701             resolve(_bulkDelete(idbstore, trans, keys$$1, false, nop));
2702           });
2703         } else {
2704           return this.where(':id').anyOf(keys$$1).delete().then(function () {}); // Resolve with undefined.
2705         }
2706       },
2707       bulkPut: function bulkPut(objects, keys$$1) {
2708         var _this = this;
2709
2710         return this._idbstore(READWRITE, function (resolve, reject, idbstore) {
2711           if (!idbstore.keyPath && !_this.schema.primKey.auto && !keys$$1) throw new exceptions.InvalidArgument("bulkPut() with non-inbound keys requires ke
2711ys array in second argument");
2712           if (idbstore.keyPath && keys$$1) throw new exceptions.InvalidArgument("bulkPut(): keys argument invalid on tables with inbound keys");
2713           if (keys$$1 && keys$$1.length !== objects.length) throw new exceptions.InvalidArgument("Arguments objects and keys must have the same length");
2714           if (objects.length === 0) return resolve(); // Caller provided empty list.
2715
2716           var done = function done(result) {
2717             if (errorList.length === 0) resolve(result);else reject(new BulkError(_this.name + ".bulkPut(): " + errorList.length + " of " + numObjs + " operations failed", errorList));
2718           };
2719
2720           var req,
2721               errorList = [],
2722               errorHandler,
2723               numObjs = objects.length,
2724               table = _this;
2725
2726           if (_this.hook.creating.fire === nop && _this.hook.updating.fire === nop) {
2727             //
2728             // Standard Bulk (no 'creating' or 'updating' hooks to care about)
2729             //
2730             errorHandler = BulkErrorHandlerCatchAll(errorList);
2731
2732             for (var i = 0, l = objects.length; i < l; ++i) {
2733               req = keys$$1 ? idbstore.put(objects[i], keys$$1[i]) : idbstore.put(objects[i]);
2734               req.onerror = errorHandler;
2735             } // Only need to catch success or error on the last operation
2736             // according to the IDB spec.
2737
2738
2739             req.onerror = BulkErrorHandlerCatchAll(errorList, done);
2740             req.onsuccess = eventSuccessHandler(done);
2741           } else {
2742             var effectiveKeys = keys$$1 || idbstore.keyPath && objects.map(function (o) {
2743               return getByKeyPath(o, idbstore.keyPath);
2744             }); // Generate map of {[key]: object}
2745
2746             var objectLookup = effectiveKeys && arrayToObject(effectiveKeys, function (key, i) {
2747               return key != null && [key, objects[i]];
2748             });
2749             var promise = !effectiveKeys ? // Auto-incremented key-less objects only without any keys argument.
2750             table.bulkAdd(objects) : // Keys provided. Either as inbound in provided objects, or as a keys argument.
2751             // Begin with updating those that exists in DB:
2752             table.where(':id').anyOf(effectiveKeys.filter(function (key) {
2753               return key != null;
2754             })).modify(function () {
2755               this.value = objectLookup[this.primKey];
2756               objectLookup[this.primKey] = null; // Mark as "don't add this"
2757             }).catch(ModifyError, function (e) {
2758               errorList = e.failures; // No need to concat here. These are the first errors added.
2759             }).then(function () {
2760               // Now, let's examine which items didnt exist so we can add them:
2761               var objsToAdd = [],
2762                   keysToAdd = keys$$1 && []; // Iterate backwards. Why? Because if same key was used twice, just add the last one.
2763
2764               for (var i = effectiveKeys.length - 1; i >= 0; --i) {
2765                 var key = effectiveKeys[i];
2766
2767                 if (key == null || objectLookup[key]) {
2768                   objsToAdd.push(objects[i]);
2769                   keys$$1 && keysToAdd.push(key);
2770                   if (key != null) objectLookup[key] = null; // Mark as "dont add again"
2771                 }
2772               } // The items are in reverse order so reverse them before adding.
2773               // Could be important in order to get auto-incremented keys the way the caller
2774               // would expect. Could have used unshift instead of push()/reverse(),
2775               // but: http://jsperf.com/unshift-vs-reverse
2776
2777
2778               objsToAdd.reverse();
2779               keys$$1 && keysToAdd.reverse();
2780               return table.bulkAdd(objsToAdd, keysToAdd);
2781             }).then(function (lastAddedKey) {
2782               // Resolve with key of the last object in given arguments to bulkPut():
2783               var lastEffectiveKey = effectiveKeys[effectiveKeys.length - 1]; // Key was provided.
2784
2785               return lastEffectiveKey != null ? lastEffectiveKey : lastAddedKey;
2786             });
2787             promise.then(done).catch(BulkError, function (e) {
2788               // Concat failure from ModifyError and reject using our 'done' method.
2789               errorList = errorList.concat(e.failures);
2790               done();
2791             }).catch(reject);
2792           }
2793         }, "locked"); // If called from transaction scope, lock transaction til all steps are done.
2794       },
2795       bulkAdd: function bulkAdd(objects, keys$$1) {
2796         var self = this,
2797             creatingHook = this.hook.creating.fire;
2798         return this._idbstore(READWRITE, function (resolve, reject, idbstore, trans) {
2799           if (!idbstore.keyPath && !self.schema.primKey.auto && !keys$$1) throw new exceptions.InvalidArgument("bulkAdd() with non-inbound keys requires keys array in second argument");
2800           if (idbstore.keyPath && keys$$1) throw new exceptions.InvalidArgument("bulkAdd(): keys argument invalid on tables with inbound keys");
2801           if (keys$$1 && keys$$1.length !== objects.length) throw new exceptions.InvalidArgument("Arguments objects and keys must have the same length");
2802           if (objects.length === 0) return resolve(); // Caller provided empty list.
2803
2804           function done(result) {
2805             if (errorList.length === 0) resolve(result);else reject(new BulkError(self.name + ".bulkAdd(): " + errorList.length + " of " + numObjs + " operations failed", errorList));
2806           }
2807
2808           var req,
2809               errorList = [],
2810               errorHandler,
2811               successHandler,
2812               numObjs = objects.length;
2813
2814           if (creatingHook !== nop) {
2815             //
2816             // There are subscribers to hook('creating')
2817             // Must behave as documented.
2818             //
2819             var keyPath = idbstore.keyPath,
2820                 hookCtx;
2821             errorHandler = BulkErrorHandlerCatchAll(errorList, null, true);
2822             successHandler = hookedEventSuccessHandler(null);
2823             tryCatch(function () {
2824               for (var i = 0, l = objects.length; i < l; ++i) {
2825                 hookCtx = {
2826                   onerror: null,
2827                   onsuccess: null
2828                 };
2829                 var key = keys$$1 && keys$$1[i];
2830                 var obj = objects[i],
2831                     effectiveKey = keys$$1 ? key : keyPath ? getByKeyPath(obj, keyPath) : undefined,
2832                     keyToUse = creatingHook.call(hookCtx, effectiveKey, obj, trans);
2833
2834                 if (effectiveKey == null && keyToUse != null) {
2835                   if (keyPath) {
2836                     obj = deepClone(obj);
2837                     setByKeyPath(obj, keyPath, keyToUse);
2838                   } else {
2839                     key = keyToUse;
2840                   }
2841                 }
2842
2843                 req = key != null ? idbstore.add(obj, key) : idbstore.add(obj);
2844                 req._hookCtx = hookCtx;
2845
2846                 if (i < l - 1) {
2847                   req.onerror = errorHandler;
2848                   if (hookCtx.onsuccess) req.onsuccess = successHandler;
2849                 }
2850               }
2851             }, function (err) {
2852               hookCtx.onerror && hookCtx.onerror(err);
2853               throw err;
2854             });
2855             req.onerror = BulkErrorHandlerCatchAll(errorList, done, true);
2856             req.onsuccess = hookedEventSuccessHandler(done);
2857           } else {
2858             //
2859             // Standard Bulk (no 'creating' hook to care about)
2860             //
2861             errorHandler = BulkErrorHandlerCatchAll(errorList);
2862
2863             for (var i = 0, l = objects.length; i < l; ++i) {
2864               req = keys$$1 ? idbstore.add(objects[i], keys$$1[i]) : idbstore.add(objects[i]);
2865               req.onerror = errorHandler;
2866             } // Only need to catch success or error on the last operation
2867             // according to the IDB spec.
2868
2869
2870             req.onerror = BulkErrorHandlerCatchAll(errorList, done);
2871             req.onsuccess = eventSuccessHandler(done);
2872           }
2873         });
2874       },
2875       add: function add(obj, key) {
2876         /// <summary>
2877         ///   Add an object to the database. In case an object with same primary key already exists, the object will not be added.
2878         /// </summary>
2879         /// <param name="obj" type="Object">A javascript object to insert</param>
2880         /// <param name="key" optional="true">Primary key</param>
2881         var creatingHook = this.hook.creating.fire;
2882         return this._idbstore(READWRITE, function (resolve, reject, idbstore, trans) {
2883           var hookCtx = {
2884             onsuccess: null,
2885             onerror: null
2886           };
2887
2888           if (creatingHook !== nop) {
2889             var effectiveKey = key != null ? key : idbstore.keyPath ? getByKeyPath(obj, idbstore.keyPath) : undefined;
2890             var keyToUse = creatingHook.call(hookCtx, effectiveKey, obj, trans); // Allow subscribers to when("creating") to generate the key.
2891
2892             if (effectiveKey == null && keyToUse != null) {
2893               if (idbstore.keyPath) setByKeyPath(obj, idbstore.keyPath, keyToUse);else key = keyToUse;
2894             }
2895           }
2896
2897           try {
2898             var req = key != null ? idbstore.add(obj, key) : idbstore.add(obj);
2899             req._hookCtx = hookCtx;
2900             req.onerror = hookedEventRejectHandler(reject);
2901             req.onsuccess = hookedEventSuccessHandler(function (result) {
2902               // TODO: Remove these two lines in next major release (2.0?)
2903               // It's no good practice to have side effects on provided parameters
2904               var keyPath = idbstore.keyPath;
2905               if (keyPath) setByKeyPath(obj, keyPath, result);
2906               resolve(result);
2907             });
2908           } catch (e) {
2909             if (hookCtx.onerror) hookCtx.onerror(e);
2910             throw e;
2911           }
2912         });
2913       },
2914       put: function put(obj, key) {
2915         var _this = this; /// <summary>
2916         ///   Add an object to the database but in case an object with same primary key alread exists, the existing one will get updated.
2917         /// </summary>
2918         /// <param name="obj" type="Object">A javascript object to insert or update</param>
2919         /// <param name="key" optional="true">Primary key</param>
2920
2921
2922         var creatingHook = this.hook.creating.fire,
2923             updatingHook = this.hook.updating.fire;
2924
2925         if (creatingHook !== nop || updatingHook !== nop) {
2926           //
2927           // People listens to when("creating") or when("updating") events!
2928           // We must know whether the put operation results in an CREATE or UPDATE.
2929           //
2930           var keyPath = this.schema.primKey.keyPath;
2931           var effectiveKey = key !== undefined ? key : keyPath && getByKeyPath(obj, keyPath);
2932           if (effectiveKey == null) return this.add(obj); // Since key is optional, make sure we get it from obj if not provided
2933           // Primary key exist. Lock transaction and try modifying existing. If nothing modified, call add().
2934           // clone obj before this async call. If caller modifies obj the line after put(), the IDB spec requires that it should not affect operation.
2935
2936           obj = deepClone(obj);
2937           return this._trans(READWRITE, function () {
2938             return _this.where(":id").equals(effectiveKey).modify(function () {
2939               // Replace extisting value with our object
2940               // CRUD event firing handled in Collection.modify()
2941               this.value = obj;
2942             }).then(function (count) {
2943               return count === 0 ? _this.add(obj, key) : effectiveKey;
2944             });
2945           }, "locked"); // Lock needed because operation is splitted into modify() and add().
2946         } else {
2947           // Use the standard IDB put() method.
2948           return this._idbstore(READWRITE, function (resolve, reject, idbstore) {
2949             var req = key !== undefined ? idbstore.put(obj, key) : idbstore.put(obj);
2950             req.onerror = eventRejectHandler(reject);
2951             req.onsuccess = wrap(function (ev) {
2952               var keyPath = idbstore.keyPath;
2953               if (keyPath) setByKeyPath(obj, keyPath, ev.target.result);
2954               resolve(req.result);
2955             });
2956           });
2957         }
2958       },
2959       'delete': function _delete(key) {
2960         /// <param name="key">Primary key of the object to delete</param>
2961         if (this.hook.deleting.subscribers.length) {
2962           // People listens to when("deleting") event. Must implement delete using Collection.delete() that will
2963           // call the CRUD event. Only Collection.delete() will know whether an object was actually deleted.
2964           return this.where(":id").equals(key).delete();
2965         } else {
2966           // No one listens. Use standard IDB delete() method.
2967           return this._idbstore(READWRITE, function (resolve, reject, idbstore) {
2968             var req = idbstore.delete(key);
2969             req.onerror = eventRejectHandler(reject);
2970             req.onsuccess = wrap(function () {
2971               resolve(req.result);
2972             });
2973           });
2974         }
2975       },
2976       clear: function clear() {
2977         if (this.hook.deleting.subscribers.length) {
2978           // People listens to when("deleting") event. Must implement delete using Collection.delete() that will
2979           // call the CRUD event. Only Collection.delete() will knows which objects that are actually deleted.
2980           return this.toCollection().delete();
2981         } else {
2982           return this._idbstore(READWRITE, function (resolve, reject, idbstore) {
2983             var req = idbstore.clear();
2984             req.onerror = eventRejectHandler(reject);
2985             req.onsuccess = wrap(function () {
2986               resolve(req.result);
2987             });
2988           });
2989         }
2990       },
2991       update: function update(keyOrObject, modifications) {
2992         if (babelHelpers.typeof(modifications) !== 'object' || isArray(modifications)) throw new exceptions.InvalidArgument("Modifications must be an object.");
2993
2994         if (babelHelpers.typeof(keyOrObject) === 'object' && !isArray(keyOrObject)) {
2995           // object to modify. Also modify given object with the modifications:
2996           keys(modifications).forEach(function (keyPath) {
2997             setByKeyPath(keyOrObject, keyPath, modifications[keyPath]);
2998           });
2999           var key = getByKeyPath(keyOrObject, this.schema.primKey.keyPath);
3000           if (key === undefined) return rejection(new exceptions.InvalidArgument("Given object does not contain its primary key"));
3001           return this.where(":id").equals(key).modify(modifications);
3002         } else {
3003           // key to modify
3004           return this.where(":id").equals(keyOrObject).modify(modifications);
3005         }
3006       }
3007     }); //
3008     //
3009     //
3010     // Transaction Class
3011     //
3012     //
3013     //
3014
3015     function Transaction(mode, storeNames, dbschema, parent) {
3016       var _this = this; /// <summary>
3017       ///    Transaction class. Represents a database transaction. All operations on db goes through a Transaction.
3018       /// </summary>
3019       /// <param name="mode" type="String">Any of "readwrite" or "readonly"</param>
3020       /// <param name="storeNames" type="Array">Array of table names to operate on</param>
3021
3022
3023       this.db = db;
3024       this.mode = mode;
3025       this.storeNames = storeNames;
3026       this.idbtrans = null;
3027       this.on = Events(this, "complete", "error", "abort");
3028       this.parent = parent || null;
3029       this.active = true;
3030       this._reculock = 0;
3031       this._blockedFuncs = [];
3032       this._resolve = null;
3033       this._reject = null;
3034       this._waitingFor = null;
3035       this._waitingQueue = null;
3036       this._spinCount = 0; // Just for debugging waitFor()
3037
3038       this._completion = new Promise(function (resolve, reject) {
3039         _this._resolve = resolve;
3040         _this._reject = reject;
3041       });
3042
3043       this._completion.then(function () {
3044         _this.active = false;
3045
3046         _this.on.complete.fire();
3047       }, function (e) {
3048         var wasActive = _this.active;
3049         _this.active = false;
3050
3051         _this.on.error.fire(e);
3052
3053         _this.parent ? _this.parent._reject(e) : wasActive && _this.idbtrans && _this.idbtrans.abort();
3054         return rejection(e); // Indicate we actually DO NOT catch this error.
3055       });
3056     }
3057
3058     props(Transaction.prototype, {
3059       //
3060       // Transaction Protected Methods (not required by API users, but needed internally and eventually by dexie extensions)
3061       //
3062       _lock: function _lock() {
3063         assert(!PSD.global); // Locking and unlocking reuires to be within a PSD scope.
3064         // Temporary set all requests into a pending queue if they are called before database is ready.
3065
3066         ++this._reculock; // Recursive read/write lock pattern using PSD (Promise Specific Data) instead of TLS (Thread Local Storage)
3067
3068         if (this._reculock === 1 && !PSD.global) PSD.lockOwnerFor = this;
3069         return this;
3070       },
3071       _unlock: function _unlock() {
3072         assert(!PSD.global); // Locking and unlocking reuires to be within a PSD scope.
3073
3074         if (--this._reculock === 0) {
3075           if (!PSD.global) PSD.lockOwnerFor = null;
3076
3077           while (this._blockedFuncs.length > 0 && !this._locked()) {
3078             var fnAndPSD = this._blockedFuncs.shift();
3079
3080             try {
3081               usePSD(fnAndPSD[1], fnAndPSD[0]);
3082             } catch (e) {}
3083           }
3084         }
3085
3086         return this;
3087       },
3088       _locked: function _locked() {
3089         // Checks if any write-lock is applied on this transaction.
3090         // To simplify the Dexie API for extension implementations, we support recursive locks.
3091         // This is accomplished by using "Promise Specific Data" (PSD).
3092         // PSD data is bound to a Promise and any child Promise emitted through then() or resolve( new Promise() ).
3093         // PSD is local to code executing on top of the call stacks of any of any code executed by Promise():
3094         //         * callback given to the Promise() constructor  (function (resolve, reject){...})
3095         //         * callbacks given to then()/catch()/finally() methods (function (value){...})
3096         // If creating a new independant Promise instance from within a Promise call stack, the new Promise will derive the PSD from the call stack of the parent Promise.
3097         // Derivation is done so that the inner PSD __proto__ points to the outer PSD.
3098         // PSD.lockOwnerFor will point to current transaction object if the currently executing PSD scope owns the lock.
3099         return this._reculock && PSD.lockOwnerFor !== this;
3100       },
3101       create: function create(idbtrans) {
3102         var _this = this;
3103
3104         if (!this.mode) return this;
3105         assert(!this.idbtrans);
3106
3107         if (!idbtrans && !idbdb) {
3108           switch (dbOpenError && dbOpenError.name) {
3109             case "DatabaseClosedError":
3110               // Errors where it is no difference whether it was caused by the user operation or an earlier call to db.open()
3111               throw new exceptions.DatabaseClosed(dbOpenError);
3112
3113             case "MissingAPIError":
3114               // Errors where it is no difference whether it was caused by the user operation or an earlier call to db.open()
3115               throw new exceptions.MissingAPI(dbOpenError.message, dbOpenError);
3116
3117             default:
3118               // Make it clear that the user operation was not what caused the error - the error had occurred earlier on db.open()!
3119               throw new exceptions.OpenFailed(dbOpenError);
3120           }
3121         }
3122
3123         if (!this.active) throw new exceptions.TransactionInactive();
3124         assert(this._completion._state === null);
3125         idbtrans = this.idbtrans = idbtrans || idbdb.transaction(safariMultiStoreFix(this.storeNames), this.mode);
3126         idbtrans.onerror = wrap(function (ev) {
3127           preventDefault(ev); // Prohibit default bubbling to window.error
3128
3129           _this._reject(idbtrans.error);
3130         });
3131         idbtrans.onabort = wrap(function (ev) {
3132           preventDefault(ev);
3133           _this.active && _this._reject(new exceptions.Abort(idbtrans.error));
3134           _this.active = false;
3135
3136           _this.on("abort").fire(ev);
3137         });
3138         idbtrans.oncomplete = wrap(function () {
3139           _this.active = false;
3140
3141           _this._resolve();
3142         });
3143         return this;
3144       },
3145       _promise: function _promise(mode, fn, bWriteLock) {
3146         var _this = this;
3147
3148         if (mode === READWRITE && this.mode !== READWRITE) return rejection(new exceptions.ReadOnly("Transaction is readonly"));
3149         if (!this.active) return rejection(new exceptions.TransactionInactive());
3150
3151         if (this._locked()) {
3152           return new Promise(function (resolve, reject) {
3153             _this._blockedFuncs.push([function () {
3154               _this._promise(mode, fn, bWriteLock).then(resolve, reject);
3155             }, PSD]);
3156           });
3157         } else if (bWriteLock) {
3158           return newScope(function () {
3159             var p = new Promise(function (resolve, reject) {
3160               _this._lock();
3161
3162               var rv = fn(resolve, reject, _this);
3163               if (rv && rv.then) rv.then(resolve, reject);
3164             });
3165             p.finally(function () {
3166               return _this._unlock();
3167             });
3168             p._lib = true;
3169             return p;
3170           });
3171         } else {
3172           var p = new Promise(function (resolve, reject) {
3173             var rv = fn(resolve, reject, _this);
3174             if (rv && rv.then) rv.then(resolve, reject);
3175           });
3176           p._lib = true;
3177           return p;
3178         }
3179       },
3180       _root: function _root() {
3181         return this.parent ? this.parent._root() : this;
3182       },
3183       waitFor: function waitFor(promise) {
3184         // Always operate on the root transaction (in case this is a sub stransaction)
3185         var root = this._root(); // For stability reasons, convert parameter to promise no matter what type is passed to waitFor().
3186         // (We must be able to call .then() on it.)
3187
3188
3189         promise = Promise.resolve(promise);
3190
3191         if (root._waitingFor) {
3192           // Already called waitFor(). Wait for both to complete.
3193           root._waitingFor = root._waitingFor.then(function () {
3194             return promise;
3195           });
3196         } else {
3197           // We're not in waiting state. Start waiting state.
3198           root._waitingFor = promise;
3199           root._waitingQueue = []; // Start interacting with indexedDB until promise completes:
3200
3201           var store = root.idbtrans.objectStore(root.storeNames[0]);
3202
3203           (function spin() {
3204             ++root._spinCount; // For debugging only
3205
3206             while (root._waitingQueue.length) {
3207               root._waitingQueue.shift()();
3208             }
3209
3210             if (root._waitingFor) store.get(-Infinity).onsuccess = spin;
3211           })();
3212         }
3213
3214         var currentWaitPromise = root._waitingFor;
3215         return new Promise(function (resolve, reject) {
3216           promise.then(function (res) {
3217             return root._waitingQueue.push(wrap(resolve.bind(null, res)));
3218           }, function (err) {
3219             return root._waitingQueue.push(wrap(reject.bind(null, err)));
3220           }).finally(function () {
3221             if (root._waitingFor === currentWaitPromise) {
3222               // No one added a wait after us. Safe to stop the spinning.
3223               root._waitingFor = null;
3224             }
3225           });
3226         });
3227       },
3228       //
3229       // Transaction Public Properties and Methods
3230       //
3231       abort: function abort() {
3232         this.active && this._reject(new exceptions.Abort());
3233         this.active = false;
3234       },
3235       tables: {
3236         get: deprecated("Transaction.tables", function () {
3237           return allTables;
3238         })
3239       },
3240       table: function table(name) {
3241         var table = db.table(name); // Don't check that table is part of transaction. It must fail lazily!
3242
3243         return new Table(name, table.schema, this);
3244       }
3245     }); //
3246     //
3247     //
3248     // WhereClause
3249     //
3250     //
3251     //
3252
3253     function WhereClause(table, index, orCollection) {
3254       /// <param name="table" type="Table"></param>
3255       /// <param name="index" type="String" optional="true"></param>
3256       /// <param name="orCollection" type="Collection" optional="true"></param>
3257       this._ctx = {
3258         table: table,
3259         index: index === ":id" ? null : index,
3260         or: orCollection
3261       };
3262     }
3263
3264     props(WhereClause.prototype, function () {
3265       // WhereClause private methods
3266       function fail(collectionOrWhereClause, err, T) {
3267         var collection = collectionOrWhereClause instanceof WhereClause ? new Collection(collectionOrWhereClause) : collectionOrWhereClause;
3268         collection._ctx.error = T ? new T(err) : new TypeError(err);
3269         return collection;
3270       }
3271
3272       function emptyCollection(whereClause) {
3273         return new Collection(whereClause, function () {
3274           return IDBKeyRange.only("");
3275         }).limit(0);
3276       }
3277
3278       function upperFactory(dir) {
3279         return dir === "next" ? function (s) {
3280           return s.toUpperCase();
3281         } : function (s) {
3282           return s.toLowerCase();
3283         };
3284       }
3285
3286       function lowerFactory(dir) {
3287         return dir === "next" ? function (s) {
3288           return s.toLowerCase();
3289         } : function (s) {
3290           return s.toUpperCase();
3291         };
3292       }
3293
3294       function nextCasing(key, lowerKey, upperNeedle, lowerNeedle, cmp, dir) {
3295         var length = Math.min(key.length, lowerNeedle.length);
3296         var llp = -1;
3297
3298         for (var i = 0; i < length; ++i) {
3299           var lwrKeyChar = lowerKey[i];
3300
3301           if (lwrKeyChar !== lowerNeedle[i]) {
3302             if (cmp(key[i], upperNeedle[i]) < 0) return key.substr(0, i) + upperNeedle[i] + upperNeedle.substr(i + 1);
3303             if (cmp(key[i], lowerNeedle[i]) < 0) return key.substr(0, i) + lowerNeedle[i] + upperNeedle.substr(i + 1);
3304             if (llp >= 0) return key.substr(0, llp) + lowerKey[llp] + upperNeedle.substr(llp + 1);
3305             return null;
3306           }
3307
3308           if (cmp(key[i], lwrKeyChar) < 0) llp = i;
3309         }
3310
3311         if (length < lowerNeedle.length && dir === "next") return key + upperNeedle.substr(key.length);
3312         if (length < key.length && dir === "prev") return key.substr(0, upperNeedle.length);
3313         return llp < 0 ? null : key.substr(0, llp) + lowerNeedle[llp] + upperNeedle.substr(llp + 1);
3314       }
3315
3316       function addIgnoreCaseAlgorithm(whereClause, match, needles, suffix) {
3317         /// <param name="needles" type="Array" elementType="String"></param>
3318         var upper,
3319             lower,
3320             compare,
3321             upperNeedles,
3322             lowerNeedles,
3323             direction,
3324             nextKeySuffix,
3325             needlesLen = needles.length;
3326
3327         if (!needles.every(function (s) {
3328           return typeof s === 'string';
3329         })) {
3330           return fail(whereClause, STRING_EXPECTED);
3331         }
3332
3333         function initDirection(dir) {
3334           upper = upperFactory(dir);
3335           lower = lowerFactory(dir);
3336           compare = dir === "next" ? simpleCompare : simpleCompareReverse;
3337           var needleBounds = needles.map(function (needle) {
3338             return {
3339               lower: lower(needle),
3340               upper: upper(needle)
3341             };
3342           }).sort(function (a, b) {
3343             return compare(a.lower, b.lower);
3344           });
3345           upperNeedles = needleBounds.map(function (nb) {
3346             return nb.upper;
3347           });
3348           lowerNeedles = needleBounds.map(function (nb) {
3349             return nb.lower;
3350           });
3351           direction = dir;
3352           nextKeySuffix = dir === "next" ? "" : suffix;
3353         }
3354
3355         initDirection("next");
3356         var c = new Collection(whereClause, function () {
3357           return IDBKeyRange.bound(upperNeedles[0], lowerNeedles[needlesLen - 1] + suffix);
3358         });
3359
3360         c._ondirectionchange = function (direction) {
3361           // This event onlys occur before filter is called the first time.
3362           initDirection(direction);
3363         };
3364
3365         var firstPossibleNeedle = 0;
3366
3367         c._addAlgorithm(function (cursor, advance, resolve) {
3368           /// <param name="cursor" type="IDBCursor"></param>
3369           /// <param name="advance" type="Function"></param>
3370           /// <param name="resolve" type="Function"></param>
3371           var key = cursor.key;
3372           if (typeof key !== 'string') return false;
3373           var lowerKey = lower(key);
3374
3375           if (match(lowerKey, lowerNeedles, firstPossibleNeedle)) {
3376             return true;
3377           } else {
3378             var lowestPossibleCasing = null;
3379
3380             for (var i = firstPossibleNeedle; i < needlesLen; ++i) {
3381               var casing = nextCasing(key, lowerKey, upperNeedles[i], lowerNeedles[i], compare, direction);
3382               if (casing === null && lowestPossibleCasing === null) firstPossibleNeedle = i + 1;else if (lowestPossibleCasing === null || compare(lowestPossibleCasing, casing) > 0) {
3383                 lowestPossibleCasing = casing;
3384               }
3385             }
3386
3387             if (lowestPossibleCasing !== null) {
3388               advance(function () {
3389                 cursor.continue(lowestPossibleCasing + nextKeySuffix);
3390               });
3391             } else {
3392               advance(resolve);
3393             }
3394
3395             return false;
3396           }
3397         });
3398
3399         return c;
3400       } //
3401       // WhereClause public methods
3402       //
3403
3404
3405       return {
3406         between: function between(lower, upper, includeLower, includeUpper) {
3407           /// <summary>
3408           ///     Filter out records whose where-field lays between given lower and upper values. Applies to Strings, Numbers and Dates.
3409           /// </summary>
3410           /// <param name="lower"></param>
3411           /// <param name="upper"></param>
3412           /// <param name="includeLower" optional="true">Whether items that equals lower should be included. Default true.</param>
3413           /// <param name="includeUpper" optional="true">Whether items that equals upper should be included. Default false.</param>
3414           /// <returns type="Collection"></returns>
3415           includeLower = includeLower !== false; // Default to true
3416
3417           includeUpper = includeUpper === true; // Default to false
3418
3419           try {
3420             if (cmp(lower, upper) > 0 || cmp(lower, upper) === 0 && (includeLower || includeUpper) && !(includeLower && includeUpper)) return emptyCollection(this); // Workaround for idiotic W3C Specification that DataError must be thrown if lower > upper. The natural result would be to return an empty collection.
3421
3422             return new Collection(this, function () {
3423               return IDBKeyRange.bound(lower, upper, !includeLower, !includeUpper);
3424             });
3425           } catch (e) {
3426             return fail(this, INVALID_KEY_ARGUMENT);
3427           }
3428         },
3429         equals: function equals(value) {
3430           return new Collection(this, function () {
3431             return IDBKeyRange.only(value);
3432           });
3433         },
3434         above: function above(value) {
3435           return new Collection(this, function () {
3436             return IDBKeyRange.lowerBound(value, true);
3437           });
3438         },
3439         aboveOrEqual: function aboveOrEqual(value) {
3440           return new Collection(this, function () {
3441             return IDBKeyRange.lowerBound(value);
3442           });
3443         },
3444         below: function below(value) {
3445           return new Collection(this, function () {
3446             return IDBKeyRange.upperBound(value, true);
3447           });
3448         },
3449         belowOrEqual: function belowOrEqual(value) {
3450           return new Collection(this, function () {
3451             return IDBKeyRange.upperBound(value);
3452           });
3453         },
3454         startsWith: function startsWith(str) {
3455           /// <param name="str" type="String"></param>
3456           if (typeof str !== 'string') return fail(this, STRING_EXPECTED);
3457           return this.between(str, str + maxString, true, true);
3458         },
3459         startsWithIgnoreCase: function startsWithIgnoreCase(str) {
3460           /// <param name="str" type="String"></param>
3461           if (str === "") return this.startsWith(str);
3462           return addIgnoreCaseAlgorithm(this, function (x, a) {
3463             return x.indexOf(a[0]) === 0;
3464           }, [str], maxString);
3465         },
3466         equalsIgnoreCase: function equalsIgnoreCase(str) {
3467           /// <param name="str" type="String"></param>
3468           return addIgnoreCaseAlgorithm(this, function (x, a) {
3469             return x === a[0];
3470           }, [str], "");
3471         },
3472         anyOfIgnoreCase: function anyOfIgnoreCase() {
3473           var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
3474           if (set.length === 0) return emptyCollection(this);
3475           return addIgnoreCaseAlgorithm(this, function (x, a) {
3476             return a.indexOf(x) !== -1;
3477           }, set, "");
3478         },
3479         startsWithAnyOfIgnoreCase: function startsWithAnyOfIgnoreCase() {
3480           var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
3481           if (set.length === 0) return emptyCollection(this);
3482           return addIgnoreCaseAlgorithm(this, function (x, a) {
3483             return a.some(function (n) {
3484               return x.indexOf(n) === 0;
3485             });
3486           }, set, maxString);
3487         },
3488         anyOf: function anyOf() {
3489           var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
3490           var compare = ascending;
3491
3492           try {
3493             set.sort(compare);
3494           } catch (e) {
3495             return fail(this, INVALID_KEY_ARGUMENT);
3496           }
3497
3498           if (set.length === 0) return emptyCollection(this);
3499           var c = new Collection(this, function () {
3500             return IDBKeyRange.bound(set[0], set[set.length - 1]);
3501           });
3502
3503           c._ondirectionchange = function (direction) {
3504             compare = direction === "next" ? ascending : descending;
3505             set.sort(compare);
3506           };
3507
3508           var i = 0;
3509
3510           c._addAlgorithm(function (cursor, advance, resolve) {
3511             var key = cursor.key;
3512
3513             while (compare(key, set[i]) > 0) {
3514               // The cursor has passed beyond this key. Check next.
3515               ++i;
3516
3517               if (i === set.length) {
3518                 // There is no next. Stop searching.
3519                 advance(resolve);
3520                 return false;
3521               }
3522             }
3523
3524             if (compare(key, set[i]) === 0) {
3525               // The current cursor value should be included and we should continue a single step in case next item has the same key or possibly our next key in set.
3526               return true;
3527             } else {
3528               // cursor.key not yet at set[i]. Forward cursor to the next key to hunt for.
3529               advance(function () {
3530                 cursor.continue(set[i]);
3531               });
3532               return false;
3533             }
3534           });
3535
3536           return c;
3537         },
3538         notEqual: function notEqual(value) {
3539           return this.inAnyRange([[minKey, value], [value, maxKey]], {
3540             includeLowers: false,
3541             includeUppers: false
3542           });
3543         },
3544         noneOf: function noneOf() {
3545           var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
3546           if (set.length === 0) return new Collection(this); // Return entire collection.
3547
3548           try {
3549             set.sort(ascending);
3550           } catch (e) {
3551             return fail(this, INVALID_KEY_ARGUMENT);
3552           } // Transform ["a","b","c"] to a set of ranges for between/above/below: [[minKey,"a"], ["a","b"], ["b","c"], ["c",maxKey]]
3553
3554
3555           var ranges = set.reduce(function (res, val) {
3556             return res ? res.concat([[res[res.length - 1][1], val]]) : [[minKey, val]];
3557           }, null);
3558           ranges.push([set[set.length - 1], maxKey]);
3559           return this.inAnyRange(ranges, {
3560             includeLowers: false,
3561             includeUppers: false
3562           });
3563         },
3564
3565         /** Filter out values withing given set of ranges.
3566         * Example, give children and elders a rebate of 50%:
3567         *
3568         *   db.friends.where('age').inAnyRange([[0,18],[65,Infinity]]).modify({Rebate: 1/2});
3569         *
3570         * @param {(string|number|Date|Array)[][]} ranges
3571         * @param {{includeLowers: boolean, includeUppers: boolean}} options
3572         */
3573         inAnyRange: function inAnyRange(ranges, options) {
3574           if (ranges.length === 0) return emptyCollection(this);
3575
3576           if (!ranges.every(function (range) {
3577             return range[0] !== undefined && range[1] !== undefined && ascending(range[0], range[1]) <= 0;
3578           })) {
3579             return fail(this, "First argument to inAnyRange() must be an Array of two-value Arrays [lower,upper] where upper must not be lower than lower", exceptions.InvalidArgument);
3580           }
3581
3582           var includeLowers = !options || options.includeLowers !== false; // Default to true
3583
3584           var includeUppers = options && options.includeUppers === true; // Default to false
3585
3586           function addRange(ranges, newRange) {
3587             for (var i = 0, l = ranges.length; i < l; ++i) {
3588               var range = ranges[i];
3589
3590               if (cmp(newRange[0], range[1]) < 0 && cmp(newRange[1], range[0]) > 0) {
3591                 range[0] = min(range[0], newRange[0]);
3592                 range[1] = max(range[1], newRange[1]);
3593                 break;
3594               }
3595             }
3596
3597             if (i === l) ranges.push(newRange);
3598             return ranges;
3599           }
3600
3601           var sortDirection = ascending;
3602
3603           function rangeSorter(a, b) {
3604             return sortDirection(a[0], b[0]);
3605           } // Join overlapping ranges
3606
3607
3608           var set;
3609
3610           try {
3611             set = ranges.reduce(addRange, []);
3612             set.sort(rangeSorter);
3613           } catch (ex) {
3614             return fail(this, INVALID_KEY_ARGUMENT);
3615           }
3616
3617           var i = 0;
3618           var keyIsBeyondCurrentEntry = includeUppers ? function (key) {
3619             return ascending(key, set[i][1]) > 0;
3620           } : function (key) {
3621             return ascending(key, set[i][1]) >= 0;
3622           };
3623           var keyIsBeforeCurrentEntry = includeLowers ? function (key) {
3624             return descending(key, set[i][0]) > 0;
3625           } : function (key) {
3626             return descending(key, set[i][0]) >= 0;
3627           };
3628
3629           function keyWithinCurrentRange(key) {
3630             return !keyIsBeyondCurrentEntry(key) && !keyIsBeforeCurrentEntry(key);
3631           }
3632
3633           var checkKey = keyIsBeyondCurrentEntry;
3634           var c = new Collection(this, function () {
3635             return IDBKeyRange.bound(set[0][0], set[set.length - 1][1], !includeLowers, !includeUppers);
3636           });
3637
3638           c._ondirectionchange = function (direction) {
3639             if (direction === "next") {
3640               checkKey = keyIsBeyondCurrentEntry;
3641               sortDirection = ascending;
3642             } else {
3643               checkKey = keyIsBeforeCurrentEntry;
3644               sortDirection = descending;
3645             }
3646
3647             set.sort(rangeSorter);
3648           };
3649
3650           c._addAlgorithm(function (cursor, advance, resolve) {
3651             var key = cursor.key;
3652
3653             while (checkKey(key)) {
3654               // The cursor has passed beyond this key. Check next.
3655               ++i;
3656
3657               if (i === set.length) {
3658                 // There is no next. Stop searching.
3659                 advance(resolve);
3660                 return false;
3661               }
3662             }
3663
3664             if (keyWithinCurrentRange(key)) {
3665               // The current cursor value should be included and we should continue a single step in case next item has the same key or possibly our next key in set.
3666               return true;
3667             } else if (cmp(key, set[i][1]) === 0 || cmp(key, set[i][0]) === 0) {
3668               // includeUpper or includeLower is false so keyWithinCurrentRange() returns false even though we are at range border.
3669               // Continue to next key but don't include this one.
3670               return false;
3671             } else {
3672               // cursor.key not yet at set[i]. Forward cursor to the next key to hunt for.
3673               advance(function () {
3674                 if (sortDirection === ascending) cursor.continue(set[i][0]);else cursor.continue(set[i][1]);
3675               });
3676               return false;
3677             }
3678           });
3679
3680           return c;
3681         },
3682         startsWithAnyOf: function startsWithAnyOf() {
3683           var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
3684
3685           if (!set.every(function (s) {
3686             return typeof s === 'string';
3687           })) {
3688             return fail(this, "startsWithAnyOf() only works with strings");
3689           }
3690
3691           if (set.length === 0) return emptyCollection(this);
3692           return this.inAnyRange(set.map(function (str) {
3693             return [str, str + maxString];
3694           }));
3695         }
3696       };
3697     }); //
3698     //
3699     //
3700     // Collection Class
3701     //
3702     //
3703     //
3704
3705     function Collection(whereClause, keyRangeGenerator) {
3706       /// <summary>
3707       ///
3708       /// </summary>
3709       /// <param name="whereClause" type="WhereClause">Where clause instance</param>
3710       /// <param name="keyRangeGenerator" value="function(){ return IDBKeyRange.bound(0,1);}" optional="true"></param>
3711       var keyRange = null,
3712           error = null;
3713       if (keyRangeGenerator) try {
3714         keyRange = keyRangeGenerator();
3715       } catch (ex) {
3716         error = ex;
3717       }
3718       var whereCtx = whereClause._ctx,
3719           table = whereCtx.table;
3720       this._ctx = {
3721         table: table,
3722         index: whereCtx.index,
3723         isPrimKey: !whereCtx.index || table.schema.primKey.keyPath && whereCtx.index === table.schema.primKey.name,
3724         range: keyRange,
3725         keysOnly: false,
3726         dir: "next",
3727         unique: "",
3728         algorithm: null,
3729         filter: null,
3730         replayFilter: null,
3731         justLimit: true,
3732         isMatch: null,
3733         offset: 0,
3734         limit: Infinity,
3735         error: error,
3736         or: whereCtx.or,
3737         valueMapper: table.hook.reading.fire
3738       };
3739     }
3740
3741     function isPlainKeyRange(ctx, ignoreLimitFilter) {
3742       return !(ctx.filter || ctx.algorithm || ctx.or) && (ignoreLimitFilter ? ctx.justLimit : !ctx.replayFilter);
3743     }
3744
3745     props(Collection.prototype, function () {
3746       //
3747       // Collection Private Functions
3748       //
3749       function addFilter(ctx, fn) {
3750         ctx.filter = combine(ctx.filter, fn);
3751       }
3752
3753       function addReplayFilter(ctx, factory, isLimitFilter) {
3754         var curr = ctx.replayFilter;
3755         ctx.replayFilter = curr ? function () {
3756           return combine(curr(), factory());
3757         } : factory;
3758         ctx.justLimit = isLimitFilter && !curr;
3759       }
3760
3761       function addMatchFilter(ctx, fn) {
3762         ctx.isMatch = combine(ctx.isMatch, fn);
3763       }
3764       /** @param ctx {
3765        *      isPrimKey: boolean,
3766        *      table: Table,
3767        *      index: string
3768        * }
3769        * @param store IDBObjectStore
3770        **/
3771
3772
3773       function getIndexOrStore(ctx, store) {
3774         if (ctx.isPrimKey) return store;
3775         var indexSpec = ctx.table.schema.idxByName[ctx.index];
3776         if (!indexSpec) throw new exceptions.Schema("KeyPath " + ctx.index + " on object store " + store.name + " is not indexed");
3777         return store.index(indexSpec.name);
3778       }
3779       /** @param ctx {
3780        *      isPrimKey: boolean,
3781        *      table: Table,
3782        *      index: string,
3783        *      keysOnly: boolean,
3784        *      range?: IDBKeyRange,
3785        *      dir: "next" | "prev"
3786        * }
3787        */
3788
3789
3790       function openCursor(ctx, store) {
3791         var idxOrStore = getIndexOrStore(ctx, store);
3792         return ctx.keysOnly && 'openKeyCursor' in idxOrStore ? idxOrStore.openKeyCursor(ctx.range || null, ctx.dir + ctx.unique) : idxOrStore.openCursor(ctx.range || null, ctx.dir + ctx.unique);
3793       }
3794
3795       function iter(ctx, fn, resolve, reject, idbstore) {
3796         var filter = ctx.replayFilter ? combine(ctx.filter, ctx.replayFilter()) : ctx.filter;
3797
3798         if (!ctx.or) {
3799           iterate(openCursor(ctx, idbstore), combine(ctx.algorithm, filter), fn, resolve, reject, !ctx.keysOnly && ctx.valueMapper);
3800         } else (function () {
3801           var set = {};
3802           var resolved = 0;
3803
3804           function resolveboth() {
3805             if (++resolved === 2) resolve(); // Seems like we just support or btwn max 2 expressions, but there are no limit because we do recursion.
3806           }
3807
3808           function union(item, cursor, advance) {
3809             if (!filter || filter(cursor, advance, resolveboth, reject)) {
3810               var primaryKey = cursor.primaryKey;
3811               var key = '' + primaryKey;
3812               if (key === '[object ArrayBuffer]') key = '' + new Uint8Array(primaryKey);
3813
3814               if (!hasOwn(set, key)) {
3815                 set[key] = true;
3816                 fn(item, cursor, advance);
3817               }
3818             }
3819           }
3820
3821           ctx.or._iterate(union, resolveboth, reject, idbstore);
3822
3823           iterate(openCursor(ctx, idbstore), ctx.algorithm, union, resolveboth, reject, !ctx.keysOnly && ctx.valueMapper);
3824         })();
3825       }
3826
3827       return {
3828         //
3829         // Collection Protected Functions
3830         //
3831         _read: function _read(fn, cb) {
3832           var ctx = this._ctx;
3833           return ctx.error ? ctx.table._trans(null, rejection.bind(null, ctx.error)) : ctx.table._idbstore(READONLY, fn).then(cb);
3834         },
3835         _write: function _write(fn) {
3836           var ctx = this._ctx;
3837           return ctx.error ? ctx.table._trans(null, rejection.bind(null, ctx.error)) : ctx.table._idbstore(READWRITE, fn, "locked"); // When doing write operations on collections, always lock the operation so that upcoming operations gets queued.
3838         },
3839         _addAlgorithm: function _addAlgorithm(fn) {
3840           var ctx = this._ctx;
3841           ctx.algorithm = combine(ctx.algorithm, fn);
3842         },
3843         _iterate: function _iterate(fn, resolve, reject, idbstore) {
3844           return iter(this._ctx, fn, resolve, reject, idbstore);
3845         },
3846         clone: function clone(props$$1) {
3847           var rv = Object.create(this.constructor.prototype),
3848               ctx = Object.create(this._ctx);
3849           if (props$$1) extend(ctx, props$$1);
3850           rv._ctx = ctx;
3851           return rv;
3852         },
3853         raw: function raw() {
3854           this._ctx.valueMapper = null;
3855           return this;
3856         },
3857         //
3858         // Collection Public methods
3859         //
3860         each: function each(fn) {
3861           var ctx = this._ctx;
3862           return this._read(function (resolve, reject, idbstore) {
3863             iter(ctx, fn, resolve, reject, idbstore);
3864           });
3865         },
3866         count: function count(cb) {
3867           var ctx = this._ctx;
3868
3869           if (isPlainKeyRange(ctx, true)) {
3870             // This is a plain key range. We can use the count() method if the index.
3871             return this._read(function (resolve, reject, idbstore) {
3872               var idx = getIndexOrStore(ctx, idbstore);
3873               var req = ctx.range ? idx.count(ctx.range) : idx.count();
3874               req.onerror = eventRejectHandler(reject);
3875
3876               req.onsuccess = function (e) {
3877                 resolve(Math.min(e.target.result, ctx.limit));
3878               };
3879             }, cb);
3880           } else {
3881             // Algorithms, filters or expressions are applied. Need to count manually.
3882             var count = 0;
3883             return this._read(function (resolve, reject, idbstore) {
3884               iter(ctx, function () {
3885                 ++count;
3886                 return false;
3887               }, function () {
3888                 resolve(count);
3889               }, reject, idbstore);
3890             }, cb);
3891           }
3892         },
3893         sortBy: function sortBy(keyPath, cb) {
3894           /// <param name="keyPath" type="String"></param>
3895           var parts = keyPath.split('.').reverse(),
3896               lastPart = parts[0],
3897               lastIndex = parts.length - 1;
3898
3899           function getval(obj, i) {
3900             if (i) return getval(obj[parts[i]], i - 1);
3901             return obj[lastPart];
3902           }
3903
3904           var order = this._ctx.dir === "next" ? 1 : -1;
3905
3906           function sorter(a, b) {
3907             var aVal = getval(a, lastIndex),
3908                 bVal = getval(b, lastIndex);
3909             return aVal < bVal ? -order : aVal > bVal ? order : 0;
3910           }
3911
3912           return this.toArray(function (a) {
3913             return a.sort(sorter);
3914           }).then(cb);
3915         },
3916         toArray: function toArray(cb) {
3917           var ctx = this._ctx;
3918           return this._read(function (resolve, reject, idbstore) {
3919             if (hasGetAll && ctx.dir === 'next' && isPlainKeyRange(ctx, true) && ctx.limit > 0) {
3920               // Special optimation if we could use IDBObjectStore.getAll() or
3921               // IDBKeyRange.getAll():
3922               var readingHook = ctx.table.hook.reading.fire;
3923               var idxOrStore = getIndexOrStore(ctx, idbstore);
3924               var req = ctx.limit < Infinity ? idxOrStore.getAll(ctx.range, ctx.limit) : idxOrStore.getAll(ctx.range);
3925               req.onerror = eventRejectHandler(reject);
3926               req.onsuccess = readingHook === mirror ? eventSuccessHandler(resolve) : eventSuccessHandler(function (res) {
3927                 try {
3928                   resolve(res.map(readingHook));
3929                 } catch (e) {
3930                   reject(e);
3931                 }
3932               });
3933             } else {
3934               // Getting array through a cursor.
3935               var a = [];
3936               iter(ctx, function (item) {
3937                 a.push(item);
3938               }, function arrayComplete() {
3939                 resolve(a);
3940               }, reject, idbstore);
3941             }
3942           }, cb);
3943         },
3944         offset: function offset(_offset2) {
3945           var ctx = this._ctx;
3946           if (_offset2 <= 0) return this;
3947           ctx.offset += _offset2; // For count()
3948
3949           if (isPlainKeyRange(ctx)) {
3950             addReplayFilter(ctx, function () {
3951               var offsetLeft = _offset2;
3952               return function (cursor, advance) {
3953                 if (offsetLeft === 0) return true;
3954
3955                 if (offsetLeft === 1) {
3956                   --offsetLeft;
3957                   return false;
3958                 }
3959
3960                 advance(function () {
3961                   cursor.advance(offsetLeft);
3962                   offsetLeft = 0;
3963                 });
3964                 return false;
3965               };
3966             });
3967           } else {
3968             addReplayFilter(ctx, function () {
3969               var offsetLeft = _offset2;
3970               return function () {
3971                 return --offsetLeft < 0;
3972               };
3973             });
3974           }
3975
3976           return this;
3977         },
3978         limit: function limit(numRows) {
3979           this._ctx.limit = Math.min(this._ctx.limit, numRows); // For count()
3980
3981           addReplayFilter(this._ctx, function () {
3982             var rowsLeft = numRows;
3983             return function (cursor, advance, resolve) {
3984               if (--rowsLeft <= 0) advance(resolve); // Stop after this item has been included
3985
3986               return rowsLeft >= 0; // If numRows is already below 0, return false because then 0 was passed to numRows initially. Otherwise we wouldnt come here.
3987             };
3988           }, true);
3989           return this;
3990         },
3991         until: function until(filterFunction, bIncludeStopEntry) {
3992           addFilter(this._ctx, function (cursor, advance, resolve) {
3993             if (filterFunction(cursor.value)) {
3994               advance(resolve);
3995               return bIncludeStopEntry;
3996             } else {
3997               return true;
3998             }
3999           });
4000           return this;
4001         },
4002         first: function first(cb) {
4003           return this.limit(1).toArray(function (a) {
4004             return a[0];
4005           }).then(cb);
4006         },
4007         last: function last(cb) {
4008           return this.reverse().first(cb);
4009         },
4010         filter: function filter(filterFunction) {
4011           /// <param name="jsFunctionFilter" type="Function">function(val){return true/false}</param>
4012           addFilter(this._ctx, function (cursor) {
4013             return filterFunction(cursor.value);
4014           }); // match filters not used in Dexie.js but can be used by 3rd part libraries to test a
4015           // collection for a match without querying DB. Used by Dexie.Observable.
4016
4017           addMatchFilter(this._ctx, filterFunction);
4018           return this;
4019         },
4020         and: function and(filterFunction) {
4021           return this.filter(filterFunction);
4022         },
4023         or: function or(indexName) {
4024           return new WhereClause(this._ctx.table, indexName, this);
4025         },
4026         reverse: function reverse() {
4027           this._ctx.dir = this._ctx.dir === "prev" ? "next" : "prev";
4028           if (this._ondirectionchange) this._ondirectionchange(this._ctx.dir);
4029           return this;
4030         },
4031         desc: function desc() {
4032           return this.reverse();
4033         },
4034         eachKey: function eachKey(cb) {
4035           var ctx = this._ctx;
4036           ctx.keysOnly = !ctx.isMatch;
4037           return this.each(function (val, cursor) {
4038             cb(cursor.key, cursor);
4039           });
4040         },
4041         eachUniqueKey: function eachUniqueKey(cb) {
4042           this._ctx.unique = "unique";
4043           return this.eachKey(cb);
4044         },
4045         eachPrimaryKey: function eachPrimaryKey(cb) {
4046           var ctx = this._ctx;
4047           ctx.keysOnly = !ctx.isMatch;
4048           return this.each(function (val, cursor) {
4049             cb(cursor.primaryKey, cursor);
4050           });
4051         },
4052         keys: function keys(cb) {
4053           var ctx = this._ctx;
4054           ctx.keysOnly = !ctx.isMatch;
4055           var a = [];
4056           return this.each(function (item, cursor) {
4057             a.push(cursor.key);
4058           }).then(function () {
4059             return a;
4060           }).then(cb);
4061         },
4062         primaryKeys: function primaryKeys(cb) {
4063           var ctx = this._ctx;
4064
4065           if (hasGetAll && ctx.dir === 'next' && isPlainKeyRange(ctx, true) && ctx.limit > 0) {
4066             // Special optimation if we could use IDBObjectStore.getAllKeys() or
4067             // IDBKeyRange.getAllKeys():
4068             return this._read(function (resolve, reject, idbstore) {
4069               var idxOrStore = getIndexOrStore(ctx, idbstore);
4070               var req = ctx.limit < Infinity ? idxOrStore.getAllKeys(ctx.range, ctx.limit) : idxOrStore.getAllKeys(ctx.range);
4071               req.onerror = eventRejectHandler(reject);
4072               req.onsuccess = eventSuccessHandler(resolve);
4073             }).then(cb);
4074           }
4075
4076           ctx.keysOnly = !ctx.isMatch;
4077           var a = [];
4078           return this.each(function (item, cursor) {
4079             a.push(cursor.primaryKey);
4080           }).then(function () {
4081             return a;
4082           }).then(cb);
4083         },
4084         uniqueKeys: function uniqueKeys(cb) {
4085           this._ctx.unique = "unique";
4086           return this.keys(cb);
4087         },
4088         firstKey: function firstKey(cb) {
4089           return this.limit(1).keys(function (a) {
4090             return a[0];
4091           }).then(cb);
4092         },
4093         lastKey: function lastKey(cb) {
4094           return this.reverse().firstKey(cb);
4095         },
4096         distinct: function distinct() {
4097           var ctx = this._ctx,
4098               idx = ctx.index && ctx.table.schema.idxByName[ctx.index];
4099           if (!idx || !idx.multi) return this; // distinct() only makes differencies on multiEntry indexes.
4100
4101           var set = {};
4102           addFilter(this._ctx, function (cursor) {
4103             var strKey = cursor.primaryKey.toString(); // Converts any Date to String, String to String, Number to String and Array to comma-separated string
4104
4105             var found = hasOwn(set, strKey);
4106             set[strKey] = true;
4107             return !found;
4108           });
4109           return this;
4110         },
4111         //
4112         // Methods that mutate storage
4113         //
4114         modify: function modify(changes) {
4115           var self = this,
4116               ctx = this._ctx,
4117               hook = ctx.table.hook,
4118               updatingHook = hook.updating.fire,
4119               deletingHook = hook.deleting.fire;
4120           return this._write(function (resolve, reject, idbstore, trans) {
4121             var modifyer;
4122
4123             if (typeof changes === 'function') {
4124               // Changes is a function that may update, add or delete propterties or even require a deletion the object itself (delete this.item)
4125               if (updatingHook === nop && deletingHook === nop) {
4126                 // Noone cares about what is being changed. Just let the modifier function be the given argument as is.
4127                 modifyer = changes;
4128               } else {
4129                 // People want to know exactly what is being modified or deleted.
4130                 // Let modifyer be a proxy function that finds out what changes the caller is actually doing
4131                 // and call the hooks accordingly!
4132                 modifyer = function modifyer(item) {
4133                   var origItem = deepClone(item); // Clone the item first so we can compare laters.
4134
4135                   if (changes.call(this, item, this) === false) return false; // Call the real modifyer function (If it returns false explicitely, it means it dont want to modify anyting on this object)
4136
4137                   if (!hasOwn(this, "value")) {
4138                     // The real modifyer function requests a deletion of the object. Inform the deletingHook that a deletion is taking place.
4139                     deletingHook.call(this, this.primKey, item, trans);
4140                   } else {
4141                     // No deletion. Check what was changed
4142                     var objectDiff = getObjectDiff(origItem, this.value);
4143                     var additionalChanges = updatingHook.call(this, objectDiff, this.primKey, origItem, trans);
4144
4145                     if (additionalChanges) {
4146                       // Hook want to apply additional modifications. Make sure to fullfill the will of the hook.
4147                       item = this.value;
4148                       keys(additionalChanges).forEach(function (keyPath) {
4149                         setByKeyPath(item, keyPath, additionalChanges[keyPath]); // Adding {keyPath: undefined} means that the keyPath should be deleted. Handled by setByKeyPath
4150                       });
4151                     }
4152                   }
4153                 };
4154               }
4155             } else if (updatingHook === nop) {
4156               // changes is a set of {keyPath: value} and no one is listening to the updating hook.
4157               var keyPaths = keys(changes);
4158               var numKeys = keyPaths.length;
4159
4160               modifyer = function modifyer(item) {
4161                 var anythingModified = false;
4162
4163                 for (var i = 0; i < numKeys; ++i) {
4164                   var keyPath = keyPaths[i],
4165                       val = changes[keyPath];
4166
4167                   if (getByKeyPath(item, keyPath) !== val) {
4168                     setByKeyPath(item, keyPath, val); // Adding {keyPath: undefined} means that the keyPath should be deleted. Handled by setByKeyPath
4169
4170                     anythingModified = true;
4171                   }
4172                 }
4173
4174                 return anythingModified;
4175               };
4176             } else {
4177               // changes is a set of {keyPath: value} and people are listening to the updating hook so we need to call it and
4178               // allow it to add additional modifications to make.
4179               var origChanges = changes;
4180               changes = shallowClone(origChanges); // Let's work with a clone of the changes keyPath/value set so that we can restore it in case a hook extends it.
4181
4182               modifyer = function modifyer(item) {
4183                 var anythingModified = false;
4184                 var additionalChanges = updatingHook.call(this, changes, this.primKey, deepClone(item), trans);
4185                 if (additionalChanges) extend(changes, additionalChanges);
4186                 keys(changes).forEach(function (keyPath) {
4187                   var val = changes[keyPath];
4188
4189                   if (getByKeyPath(item, keyPath) !== val) {
4190                     setByKeyPath(item, keyPath, val);
4191                     anythingModified = true;
4192                   }
4193                 });
4194                 if (additionalChanges) changes = shallowClone(origChanges); // Restore original changes for next iteration
4195
4196                 return anythingModified;
4197               };
4198             }
4199
4200             var count = 0;
4201             var successCount = 0;
4202             var iterationComplete = false;
4203             var failures = [];
4204             var failKeys = [];
4205             var currentKey = null;
4206
4207             function modifyItem(item, cursor) {
4208               currentKey = cursor.primaryKey;
4209               var thisContext = {
4210                 primKey: cursor.primaryKey,
4211                 value: item,
4212                 onsuccess: null,
4213                 onerror: null
4214               };
4215
4216               function onerror(e) {
4217                 failures.push(e);
4218                 failKeys.push(thisContext.primKey);
4219                 checkFinished();
4220                 return true; // Catch these errors and let a final rejection decide whether or not to abort entire transaction
4221               }
4222
4223               if (modifyer.call(thisContext, item, thisContext) !== false) {
4224                 var bDelete = !hasOwn(thisContext, "value");
4225                 ++count;
4226                 tryCatch(function () {
4227                   var req = bDelete ? cursor.delete() : cursor.update(thisContext.value);
4228                   req._hookCtx = thisContext;
4229                   req.onerror = hookedEventRejectHandler(onerror);
4230                   req.onsuccess = hookedEventSuccessHandler(function () {
4231                     ++successCount;
4232                     checkFinished();
4233                   });
4234                 }, onerror);
4235               } else if (thisContext.onsuccess) {
4236                 // Hook will expect either onerror or onsuccess to always be called!
4237                 thisContext.onsuccess(thisContext.value);
4238               }
4239             }
4240
4241             function doReject(e) {
4242               if (e) {
4243                 failures.push(e);
4244                 failKeys.push(currentKey);
4245               }
4246
4247               return reject(new ModifyError("Error modifying one or more objects", failures, successCount, failKeys));
4248             }
4249
4250             function checkFinished() {
4251               if (iterationComplete && successCount + failures.length === count) {
4252                 if (failures.length > 0) doReject();else resolve(successCount);
4253               }
4254             }
4255
4256             self.clone().raw()._iterate(modifyItem, function () {
4257               iterationComplete = true;
4258               checkFinished();
4259             }, doReject, idbstore);
4260           });
4261         },
4262         'delete': function _delete() {
4263           var _this = this;
4264
4265           var ctx = this._ctx,
4266               range = ctx.range,
4267               deletingHook = ctx.table.hook.deleting.fire,
4268               hasDeleteHook = deletingHook !== nop;
4269
4270           if (!hasDeleteHook && isPlainKeyRange(ctx) && (ctx.isPrimKey && !hangsOnDeleteLargeKeyRange || !range)) {
4271             // May use IDBObjectStore.delete(IDBKeyRange) in this case (Issue #208)
4272             // For chromium, this is the way most optimized version.
4273             // For IE/Edge, this could hang the indexedDB engine and make operating system instable
4274             // (https://gist.github.com/dfahlander/5a39328f029de18222cf2125d56c38f7)
4275             return this._write(function (resolve, reject, idbstore) {
4276               // Our API contract is to return a count of deleted items, so we have to count() before delete().
4277               var onerror = eventRejectHandler(reject),
4278                   countReq = range ? idbstore.count(range) : idbstore.count();
4279               countReq.onerror = onerror;
4280
4281               countReq.onsuccess = function () {
4282                 var count = countReq.result;
4283                 tryCatch(function () {
4284                   var delReq = range ? idbstore.delete(range) : idbstore.clear();
4285                   delReq.onerror = onerror;
4286
4287                   delReq.onsuccess = function () {
4288                     return resolve(count);
4289                   };
4290                 }, function (err) {
4291                   return reject(err);
4292                 });
4293               };
4294             });
4295           } // Default version to use when collection is not a vanilla IDBKeyRange on the primary key.
4296           // Divide into chunks to not starve RAM.
4297           // If has delete hook, we will have to collect not just keys but also objects, so it will use
4298           // more memory and need lower chunk size.
4299
4300
4301           var CHUNKSIZE = hasDeleteHook ? 2000 : 10000;
4302           return this._write(function (resolve, reject, idbstore, trans) {
4303             var totalCount = 0; // Clone collection and change its table and set a limit of CHUNKSIZE on the cloned Collection instance.
4304
4305             var collection = _this.clone({
4306               keysOnly: !ctx.isMatch && !hasDeleteHook
4307             }) // load just keys (unless filter() or and() or deleteHook has subscribers)
4308             .distinct() // In case multiEntry is used, never delete same key twice because resulting count
4309             .limit(CHUNKSIZE).raw(); // Don't filter through reading-hooks (like mapped classes etc)
4310
4311
4312             var keysOrTuples = []; // We're gonna do things on as many chunks that are needed.
4313             // Use recursion of nextChunk function:
4314
4315             var nextChunk = function nextChunk() {
4316               return collection.each(hasDeleteHook ? function (val, cursor) {
4317                 // Somebody subscribes to hook('deleting'). Collect all primary keys and their values,
4318                 // so that the hook can be called with its values in bulkDelete().
4319                 keysOrTuples.push([cursor.primaryKey, cursor.value]);
4320               } : function (val, cursor) {
4321                 // No one subscribes to hook('deleting'). Collect only primary keys:
4322                 keysOrTuples.push(cursor.primaryKey);
4323               }).then(function () {
4324                 // Chromium deletes faster when doing it in sort order.
4325                 hasDeleteHook ? keysOrTuples.sort(function (a, b) {
4326                   return ascending(a[0], b[0]);
4327                 }) : keysOrTuples.sort(ascending);
4328                 return _bulkDelete(idbstore, trans, keysOrTuples, hasDeleteHook, deletingHook);
4329               }).then(function () {
4330                 var count = keysOrTuples.length;
4331                 totalCount += count;
4332                 keysOrTuples = [];
4333                 return count < CHUNKSIZE ? totalCount : nextChunk();
4334               });
4335             };
4336
4337             resolve(nextChunk());
4338           });
4339         }
4340       };
4341     }); //
4342     //
4343     //
4344     // ------------------------- Help functions ---------------------------
4345     //
4346     //
4347     //
4348
4349     function lowerVersionFirst(a, b) {
4350       return a._cfg.version - b._cfg.version;
4351     }
4352
4353     function setApiOnPlace(objs, tableNames, dbschema) {
4354       tableNames.forEach(function (tableName) {
4355         var schema = dbschema[tableName];
4356         objs.forEach(function (obj) {
4357           if (!(tableName in obj)) {
4358             if (obj === Transaction.prototype || obj instanceof Transaction) {
4359               // obj is a Transaction prototype (or prototype of a subclass to Transaction)
4360               // Make the API a getter that returns this.table(tableName)
4361               setProp(obj, tableName, {
4362                 get: function get() {
4363                   return this.table(tableName);
4364                 }
4365               });
4366             } else {
4367               // Table will not be bound to a transaction (will use Dexie.currentTransaction)
4368               obj[tableName] = new Table(tableName, schema);
4369             }
4370           }
4371         });
4372       });
4373     }
4374
4375     function removeTablesApi(objs) {
4376       objs.forEach(function (obj) {
4377         for (var key in obj) {
4378           if (obj[key] instanceof Table) delete obj[key];
4379         }
4380       });
4381     }
4382
4383     function iterate(req, filter, fn, resolve, reject, valueMapper) {
4384       // Apply valueMapper (hook('reading') or mappped class)
4385       var mappedFn = valueMapper ? function (x, c, a) {
4386         return fn(valueMapper(x), c, a);
4387       } : fn; // Wrap fn with PSD and microtick stuff from Promise.
4388
4389       var wrappedFn = wrap(mappedFn, reject);
4390       if (!req.onerror) req.onerror = eventRejectHandler(reject);
4391
4392       if (filter) {
4393         req.onsuccess = trycatcher(function filter_record() {
4394           var cursor = req.result;
4395
4396           if (cursor) {
4397             var c = function c() {
4398               cursor.continue();
4399             };
4400
4401             if (filter(cursor, function (advancer) {
4402               c = advancer;
4403             }, resolve, reject)) wrappedFn(cursor.value, cursor, function (advancer) {
4404               c = advancer;
4405             });
4406             c();
4407           } else {
4408             resolve();
4409           }
4410         }, reject);
4411       } else {
4412         req.onsuccess = trycatcher(function filter_record() {
4413           var cursor = req.result;
4414
4415           if (cursor) {
4416             var c = function c() {
4417               cursor.continue();
4418             };
4419
4420             wrappedFn(cursor.value, cursor, function (advancer) {
4421               c = advancer;
4422             });
4423             c();
4424           } else {
4425             resolve();
4426           }
4427         }, reject);
4428       }
4429     }
4430
4431     function parseIndexSyntax(indexes) {
4432       /// <param name="indexes" type="String"></param>
4433       /// <returns type="Array" elementType="IndexSpec"></returns>
4434       var rv = [];
4435       indexes.split(',').forEach(function (index) {
4436         index = index.trim();
4437         var name = index.replace(/([&*]|\+\+)/g, ""); // Remove "&", "++" and "*"
4438         // Let keyPath of "[a+b]" be ["a","b"]:
4439
4440         var keyPath = /^\[/.test(name) ? name.match(/^\[(.*)\]$/)[1].split('+') : name;
4441         rv.push(new IndexSpec(name, keyPath || null, /\&/.test(index), /\*/.test(index), /\+\+/.test(index), isArray(keyPath), /\./.test(index)));
4442       });
4443       return rv;
4444     }
4445
4446     function cmp(key1, key2) {
4447       return indexedDB.cmp(key1, key2);
4448     }
4449
4450     function min(a, b) {
4451       return cmp(a, b) < 0 ? a : b;
4452     }
4453
4454     function max(a, b) {
4455       return cmp(a, b) > 0 ? a : b;
4456     }
4457
4458     function ascending(a, b) {
4459       return indexedDB.cmp(a, b);
4460     }
4461
4462     function descending(a, b) {
4463       return indexedDB.cmp(b, a);
4464     }
4465
4466     function simpleCompare(a, b) {
4467       return a < b ? -1 : a === b ? 0 : 1;
4468     }
4469
4470     function simpleCompareReverse(a, b) {
4471       return a > b ? -1 : a === b ? 0 : 1;
4472     }
4473
4474     function combine(filter1, filter2) {
4475       return filter1 ? filter2 ? function () {
4476         return filter1.apply(this, arguments) && filter2.apply(this, arguments);
4477       } : filter1 : filter2;
4478     }
4479
4480     function readGlobalSchema() {
4481       db.verno = idbdb.version / 10;
4482       db._dbSchema = globalSchema = {};
4483       dbStoreNames = slice(idbdb.objectStoreNames, 0);
4484       if (dbStoreNames.length === 0) return;
4484 // Database contains no stores.
4485
4486       var trans = idbdb.transaction(safariMultiStoreFix(dbStoreNames), 'readonly');
4487       dbStoreNames.forEach(function (storeName) {
4488         var store = trans.objectStore(storeName),
4489             keyPath = store.keyPath,
4490             dotted = keyPath && typeof keyPath === 'string' && keyPath.indexOf('.') !== -1;
4491         var primKey = new IndexSpec(keyPath, keyPath || "", false, false, !!store.autoIncrement, keyPath && typeof keyPath !== 'string', dotted);
4492         var indexes = [];
4493
4494         for (var j = 0; j < store.indexNames.length; ++j) {
4495           var idbindex = store.index(store.indexNames[j]);
4496           keyPath = idbindex.keyPath;
4497           dotted = keyPath && typeof keyPath === 'string' && keyPath.indexOf('.') !== -1;
4498           var index = new IndexSpec(idbindex.name, keyPath, !!idbindex.unique, !!idbindex.multiEntry, false, keyPath && typeof keyPath !== 'string', dotted);
4499           indexes.push(index);
4500         }
4501
4502         globalSchema[storeName] = new TableSchema(storeName, primKey, indexes, {});
4503       });
4504       setApiOnPlace([allTables], keys(globalSchema), globalSchema);
4505     }
4506
4507     function adjustToExistingIndexNames(schema, idbtrans) {
4508       /// <summary>
4509       /// Issue #30 Problem with existing db - adjust to existing index names when migrating from non-dexie db
4510       /// </summary>
4511       /// <param name="schema" type="Object">Map between name and TableSchema</param>
4512       /// <param name="idbtrans" type="IDBTransaction"></param>
4513       var storeNames = idbtrans.db.objectStoreNames;
4514
4515       for (var i = 0; i < storeNames.length; ++i) {
4516         var storeName = storeNames[i];
4517         var store = idbtrans.objectStore(storeName);
4518         hasGetAll = 'getAll' in store;
4519
4520         for (var j = 0; j < store.indexNames.length; ++j) {
4521           var indexName = store.indexNames[j];
4522           var keyPath = store.index(indexName).keyPath;
4523           var dexieName = typeof keyPath === 'string' ? keyPath : "[" + slice(keyPath).join('+') + "]";
4524
4525           if (schema[storeName]) {
4526             var indexSpec = schema[storeName].idxByName[dexieName];
4527             if (indexSpec) indexSpec.name = indexName;
4528           }
4529         }
4530       } // Bug with getAll() on Safari ver<604 on Workers only, see discussion following PR #579
4531
4532
4533       if (/Safari/.test(navigator.userAgent) && !/(Chrome\/|Edge\/)/.test(navigator.userAgent) && _global.WorkerGlobalScope && _global instanceof _global.WorkerGlobalScope && [].concat(navigator.userAgent.match(/Safari\/(\d*)/))[1] < 604) {
4534         hasGetAll = false;
4535       }
4536     }
4537
4538     function fireOnBlocked(ev) {
4539       db.on("blocked").fire(ev); // Workaround (not fully*) for missing "versionchange" event in IE,Edge and Safari:
4540
4541       connections.filter(function (c) {
4542         return c.name === db.name && c !== db && !c._vcFired;
4543       }).map(function (c) {
4544         return c.on("versionchange").fire(ev);
4545       });
4546     }
4547
4548     extend(this, {
4549       Collection: Collection,
4550       Table: Table,
4551       Transaction: Transaction,
4552       Version: Version,
4553       WhereClause: WhereClause
4554     });
4555     init();
4556     addons.forEach(function (fn) {
4557       fn(db);
4558     });
4559   }
4560
4561   function parseType(type) {
4562     if (typeof type === 'function') {
4563       return new type();
4564     } else if (isArray(type)) {
4565       return [parseType(type[0])];
4566     } else if (type && babelHelpers.typeof(type) === 'object') {
4567       var rv = {};
4568       applyStructure(rv, type);
4569       return rv;
4570     } else {
4571       return type;
4572     }
4573   }
4574
4575   function applyStructure(obj, structure) {
4576     keys(structure).forEach(function (member) {
4577       var value = parseType(structure[member]);
4578       obj[member] = value;
4579     });
4580     return obj;
4581   }
4582
4583   function hookedEventSuccessHandler(resolve) {
4584     // wrap() is needed when calling hooks because the rare scenario of:
4585     //  * hook does a db operation that fails immediately (IDB throws exception)
4586     //    For calling db operations on correct transaction, wrap makes sure to set PSD correctly.
4587     //    wrap() will also execute in a virtual tick.
4588     //  * If not wrapped in a virtual tick, direct exception will launch a new physical tick.
4589     //  * If this was the last event in the bulk, the promise will resolve after a physical tick
4590     //    and the transaction will have committed already.
4591     // If no hook, the virtual tick will be executed in the reject()/resolve of the final promise,
4592     // because it is always marked with _lib = true when created using Transaction._promise().
4593     return wrap(function (event) {
4594       var req = event.target,
4595           ctx = req._hookCtx,
4596           // Contains the hook error handler. Put here instead of closure to boost performance.
4597       result = ctx.value || req.result,
4598           // Pass the object value on updates. The result from ID
4598B is the primary key.
4599       hookSuccessHandler = ctx && ctx.onsuccess;
4600       hookSuccessHandler && hookSuccessHandler(result);
4601       resolve && resolve(result);
4602     }, resolve);
4603   }
4604
4605   function eventRejectHandler(reject) {
4606     return wrap(function (event) {
4607       preventDefault(event);
4608       reject(event.target.error);
4609       return false;
4610     });
4611   }
4612
4613   function eventSuccessHandler(resolve) {
4614     return wrap(function (event) {
4615       resolve(event.target.result);
4616     });
4617   }
4618
4619   function hookedEventRejectHandler(reject) {
4620     return wrap(function (event) {
4621       // See comment on hookedEventSuccessHandler() why wrap() is needed only when supporting hooks.
4622       var req = event.target,
4623           err = req.error,
4624           ctx = req._hookCtx,
4625           // Contains the hook error handler. Put here instead of closure to boost performance.
4626       hookErrorHandler = ctx && ctx.onerror;
4627       hookErrorHandler && hookErrorHandler(err);
4628       preventDefault(event);
4629       reject(err);
4630       return false;
4631     });
4632   }
4633
4634   function preventDefault(event) {
4635     if (event.stopPropagation) event.stopPropagation();
4636     if (event.preventDefault) event.preventDefault();
4637   }
4638
4639   function awaitIterator(iterator) {
4640     var callNext = function callNext(result) {
4641       return iterator.next(result);
4642     },
4643         doThrow = function doThrow(error) {
4644       return iterator.throw(error);
4645     },
4646         onSuccess = step(callNext),
4647         onError = step(doThrow);
4648
4649     function step(getNext) {
4650       return function (val) {
4651         var next = getNext(val),
4652             value = next.value;
4653         return next.done ? value : !value || typeof value.then !== 'function' ? isArray(value) ? Promise.all(value).then(onSuccess, onError) : onSuccess(value) : value.then(onSuccess, onError);
4654       };
4655     }
4656
4657     return step(callNext)();
4658   } //
4659   // IndexSpec struct
4660   //
4661
4662
4663   function IndexSpec(name, keyPath, unique, multi, auto, compound, dotted) {
4664     /// <param name="name" type="String"></param>
4665     /// <param name="keyPath" type="String"></param>
4666     /// <param name="unique" type="Boolean"></param>
4667     /// <param name="multi" type="Boolean"></param>
4668     /// <param name="auto" type="Boolean"></param>
4669     /// <param name="compound" type="Boolean"></param>
4670     /// <param name="dotted" type="Boolean"></param>
4671     this.name = name;
4672     this.keyPath = keyPath;
4673     this.unique = unique;
4674     this.multi = multi;
4675     this.auto = auto;
4676     this.compound = compound;
4677     this.dotted = dotted;
4678     var keyPathSrc = typeof keyPath === 'string' ? keyPath : keyPath && '[' + [].join.call(keyPath, '+') + ']';
4679     this.src = (unique ? '&' : '') + (multi ? '*' : '') + (auto ? "++" : "") + keyPathSrc;
4680   } //
4681   // TableSchema struct
4682   //
4683
4684
4685   function TableSchema(name, primKey, indexes, instanceTemplate) {
4686     /// <param name="name" type="String"></param>
4687     /// <param name="primKey" type="IndexSpec"></param>
4688     /// <param name="indexes" type="Array" elementType="IndexSpec"></param>
4689     /// <param name="instanceTemplate" type="Object"></param>
4690     this.name = name;
4691     this.primKey = primKey || new IndexSpec();
4692     this.indexes = indexes || [new IndexSpec()];
4693     this.instanceTemplate = instanceTemplate;
4694     this.mappedClass = null;
4695     this.idxByName = arrayToObject(indexes, function (index) {
4696       return [index.name, index];
4697     });
4698   }
4699
4700   function safariMultiStoreFix(storeNames) {
4701     return storeNames.length === 1 ? storeNames[0] : storeNames;
4702   }
4703
4704   function getNativeGetDatabaseNamesFn(indexedDB) {
4705     var fn = indexedDB && (indexedDB.getDatabaseNames || indexedDB.webkitGetDatabaseNames);
4706     return fn && fn.bind(indexedDB);
4707   } // Export Error classes
4708
4709
4710   props(Dexie, fullNameExceptions); // Dexie.XXXError = class XXXError {...};
4711   //
4712   // Static methods and properties
4713   //
4714
4715   props(Dexie, {
4716     //
4717     // Static delete() method.
4718     //
4719     delete: function _delete(databaseName) {
4720       var db = new Dexie(databaseName),
4721           promise = db.delete();
4722
4723       promise.onblocked = function (fn) {
4724         db.on("blocked", fn);
4725         return this;
4726       };
4727
4728       return promise;
4729     },
4730     //
4731     // Static exists() method.
4732     //
4733     exists: function exists(name) {
4734       return new Dexie(name).open().then(function (db) {
4735         db.close();
4736         return true;
4737       }).catch(Dexie.NoSuchDatabaseError, function () {
4738         return false;
4739       });
4740     },
4741     //
4742     // Static method for retrieving a list of all existing databases at current host.
4743     //
4744     getDatabaseNames: function getDatabaseNames(cb) {
4745       var getDatabaseNames = getNativeGetDatabaseNamesFn(Dexie.dependencies.indexedDB);
4746       return getDatabaseNames ? new Promise(function (resolve, reject) {
4747         var req = getDatabaseNames();
4748
4749         req.onsuccess = function (event) {
4750           resolve(slice(event.target.result, 0)); // Converst DOMStringList to Array<String>
4751         };
4752
4753         req.onerror = eventRejectHandler(reject);
4754       }).then(cb) : dbNamesDB.dbnames.toCollection().primaryKeys(cb);
4755     },
4756     defineClass: function defineClass() {
4757       // Default constructor able to copy given properties into this object.
4758       function Class(properties) {
4759         /// <param name="properties" type="Object" optional="true">Properties to initialize object with.
4760         /// </param>
4761         if (properties) extend(this, properties);
4762       }
4763
4764       return Class;
4765     },
4766     applyStructure: applyStructure,
4767     ignoreTransaction: function ignoreTransaction(scopeFunc) {
4768       // In case caller is within a transaction but needs to create a separate transaction.
4769       // Example of usage:
4770       //
4771       // Let's say we have a logger function in our app. Other application-logic should be unaware of the
4772       // logger function and not need to include the 'logentries' table in all transaction it performs.
4773       // The logging should always be done in a separate transaction and not be dependant on the current
4774       // running transaction context. Then you could use Dexie.ignoreTransaction() to run code that starts a new transaction.
4775       //
4776       //     Dexie.ignoreTransaction(function() {
4777       //         db.logentries.add(newLogEntry);
4778       //     });
4779       //
4780       // Unless using Dexie.ignoreTransaction(), the above example would try to reuse the current transaction
4781       // in current Promise-scope.
4782       //
4783       // An alternative to Dexie.ignoreTransaction() would be setImmediate() or setTimeout(). The reason we still provide an
4784       // API for this because
4785       //  1) The intention of writing the statement could be unclear if using setImmediate() or setTimeout().
4786       //  2) setTimeout() would wait unnescessary until firing. This is however not the case with setImmediate().
4787       //  3) setImmediate() is not supported in the ES standard.
4788       //  4) You might want to keep other PSD state that was set in a parent PSD, such as PSD.letThrough.
4789       return PSD.trans ? usePSD(PSD.transless, scopeFunc) : // Use the closest parent that was non-transactional.
4790       scopeFunc(); // No need to change scope because there is no ongoing transaction.
4791     },
4792     vip: function vip(fn) {
4793       // To be used by subscribers to the on('ready') event.
4794       // This will let caller through to access DB even when it is blocked while the db.ready() subscribers are firing.
4795       // This would have worked automatically if we were certain that the Provider was using Dexie.Promise for all asyncronic operations. The promise PSD
4796       // from the provider.connect() call would then be derived all the way to when provider would call localDatabase.applyChanges(). But since
4797       // the provider more likely is using non-promise async APIs or other thenable implementations, we cannot assume that.
4798       // Note that this method is only useful for on('ready') subscribers that is returning a Promise from the event. If not using vip()
4799       // the database could deadlock since it wont open until the returned Promise is resolved, and any non-VIPed operation started by
4800       // the caller will not resolve until database is opened.
4801       return newScope(function () {
4802         PSD.letThrough = true; // Make sure we are let through if still blocking db due to onready is firing.
4803
4804         return fn();
4805       });
4806     },
4807     async: function async(generatorFn) {
4808       return function () {
4809         try {
4810           var rv = awaitIterator(generatorFn.apply(this, arguments));
4811           if (!rv || typeof rv.then !== 'function') return Promise.resolve(rv);
4812           return rv;
4813         } catch (e) {
4814           return rejection(e);
4815         }
4816       };
4817     },
4818     spawn: function spawn(generatorFn, args, thiz) {
4819       try {
4820         var rv = awaitIterator(generatorFn.apply(thiz, args || []));
4821         if (!rv || typeof rv.then !== 'function') return Promise.resolve(rv);
4822         return rv;
4823       } catch (e) {
4824         return rejection(e);
4825       }
4826     },
4827     // Dexie.currentTransaction property
4828     currentTransaction: {
4829       get: function get() {
4830         return PSD.trans || null;
4831       }
4832     },
4833     waitFor: function waitFor(promiseOrFunction, optionalTimeout) {
4834       // If a function is provided, invoke it and pass the returning value to Transaction.waitFor()
4835       var promise = Promise.resolve(typeof promiseOrFunction === 'function' ? Dexie.ignoreTransaction(promiseOrFunction) : promiseOrFunction).timeout(optionalTimeout || 60000); // Default the timeout to one minute. Caller may specify Infinity if required.
4836       // Run given promise on current transaction. If no current transaction, just return a Dexie promise based
4837       // on given value.
4838
4839       return PSD.trans ? PSD.trans.waitFor(promise) : promise;
4840     },
4841     // Export our Promise implementation since it can be handy as a standalone Promise implementation
4842     Promise: Promise,
4843     // Dexie.debug proptery:
4844     // Dexie.debug = false
4845     // Dexie.debug = true
4846     // Dexie.debug = "dexie" - don't hide dexie's stack frames.
4847     debug: {
4848       get: function get() {
4849         return debug;
4850       },
4851       set: function set(value) {
4852         setDebug(value, value === 'dexie' ? function () {
4853           return true;
4854         } : dexieStackFrameFilter);
4855       }
4856     },
4857     // Export our derive/extend/override methodology
4858     derive: derive,
4859     extend: extend,
4860     props: props,
4861     override: override,
4862     // Export our Events() function - can be handy as a toolkit
4863     Events: Events,
4864     // Utilities
4865     getByKeyPath: getByKeyPath,
4866     setByKeyPath: setByKeyPath,
4867     delByKeyPath: delByKeyPath,
4868     shallowClone: shallowClone,
4869     deepClone: deepClone,
4870     getObjectDiff: getObjectDiff,
4871     asap: asap,
4872     maxKey: maxKey,
4873     minKey: minKey,
4874     // Addon registry
4875     addons: [],
4876     // Global DB connection list
4877     connections: connections,
4878     MultiModifyError: exceptions.Modify,
4879     errnames: errnames,
4880     // Export other static classes
4881     IndexSpec: IndexSpec,
4882     TableSchema: TableSchema,
4883     //
4884     // Dependencies
4885     //
4886     // These will automatically work in browsers with indexedDB support, or where an indexedDB polyfill has been included.
4887     //
4888     // In node.js, however, these properties must be set "manually" before instansiating a new Dexie().
4889     // For node.js, you need to require indexeddb-js or similar and then set these deps.
4890     //
4891     dependencies: function () {
4892       try {
4893         return {
4894           // Required:
4895           indexedDB: _global.indexedDB || _global.mozIndexedDB || _global.webkitIndexedDB || _global.msIndexedDB,
4896           IDBKeyRange: _global.IDBKeyRange || _global.webkitIDBKeyRange
4897         };
4898       } catch (e) {
4899         return {
4900           indexedDB: null,
4901           IDBKeyRange: null
4902         };
4903       }
4904     }(),
4905     // API Version Number: Type Number, make sure to always set a version number that can be comparable correctly. Example: 0.9, 0.91, 0.92, 1.0, 1.01, 1.1, 1.2, 1.21, etc.
4906     semVer: DEXIE_VERSION,
4907     version: DEXIE_VERSION.split('.').map(function (n) {
4908       return parseInt(n);
4909     }).reduce(function (p, c, i) {
4910       return p + c / Math.pow(10, i * 2);
4911     }),
4912     // https://github.com/dfahlander/Dexie.js/issues/186
4913     // typescript compiler tsc in mode ts-->es5 & commonJS, will expect require() to return
4914     // x.default. Workaround: Set Dexie.default = Dexie.
4915     default: Dexie,
4916     // Make it possible to import {Dexie} (non-default import)
4917     // Reason 1: May switch to that in future.
4918     // Reason 2: We declare it both default and named exported in d.ts to make it possible
4919     // to let addons extend the Dexie interface with Typescript 2.1 (works only when explicitely
4920     // exporting the symbol, not just default exporting)
4921     Dexie: Dexie
4922   }); // Map DOMErrors and DOMExceptions to corresponding Dexie errors. May change in Dexie v2.0.
4923
4924   Promise.rejectionMapper = mapError; // Initialize dbNamesDB (won't ever be opened on chromium browsers')
4925
4926   dbNamesDB = new Dexie('__dbnames');
4927   dbNamesDB.version(1).stores({
4928     dbnames: 'name'
4929   });
4930
4931   (function () {
4932     // Migrate from Dexie 1.x database names stored in localStorage:
4933     var DBNAMES = 'Dexie.DatabaseNames';
4934
4935     try {
4936       if ((typeof localStorage === "undefined" ? "undefined" : babelHelpers.typeof(localStorage)) !== undefined && _global.document !== undefined) {
4937         // Have localStorage and is not executing in a worker. Lets migrate from Dexie 1.x.
4938         JSON.parse(localStorage.getItem(DBNAMES) || "[]").forEach(function (name) {
4939           return dbNamesDB.dbnames.put({
4940             name: name
4941           }).catch(nop);
4942         });
4943         localStorage.removeItem(DBNAMES);
4944       }
4945     } catch (_e) {}
4946   })();
4947
4948   /**
4949    * Bitrix UI
4950    * IndexedDB manager (integration with Dexie.js)
4951    *
4952    * @package bitrix
4953    * @subpackage ui
4954    * @copyright 2001-2019 Bitrix
4955    *
4956    * @see	https://dexie.org/docs/Tutorial/Getting-started
4957    */
4958
4959   var Dexie$1 = function Dexie$$1(database) {
4960     babelHelpers.classCallCheck(this, Dexie$$1);
4961     return new Dexie(database);
4962   };
4963
4964   Dexie$1.delete = Dexie.delete;
4965   Dexie$1.exists = Dexie.exists;
4966   Dexie$1.getDatabaseNames = Dexie.getDatabaseNames;
4967   Dexie$1.defineClass = Dexie.defineClass;
4968   Dexie$1.applyStructure = Dexie.applyStructure;
4969   Dexie$1.ignoreTransaction = Dexie.ignoreTransaction;
4970   Dexie$1.vip = Dexie.vip;
4971   Dexie$1.async = Dexie.async;
4972   Dexie$1.spawn = Dexie.spawn;
4973   Dexie$1.currentTransaction = Dexie.currentTransaction;
4974   Dexie$1.waitFor = Dexie.waitFor;
4975   Dexie$1.Promise = Dexie.Promise;
4976   Dexie$1.debug = Dexie.debug;
4977   Dexie$1.derive = Dexie.derive;
4978   Dexie$1.extend = Dexie.extend;
4979   Dexie$1.props = Dexie.props;
4980   Dexie$1.override = Dexie.override;
4981   Dexie$1.Events = Dexie.Events;
4982   Dexie$1.getByKeyPath = Dexie.getByKeyPath;
4983   Dexie$1.setByKeyPath = Dexie.setByKeyPath;
4984   Dexie$1.delByKeyPath = Dexie.delByKeyPath;
4985   Dexie$1.shallowClone = Dexie.shallowClone;
4986   Dexie$1.deepClone = Dexie.deepClone;
4987   Dexie$1.getObjectDiff = Dexie.getObjectDiff;
4988   Dexie$1.asap = Dexie.asap;
4989   Dexie$1.maxKey = Dexie.maxKey;
4990   Dexie$1.minKey = Dexie.minKey;
4991   Dexie$1.addons = Dexie.addons;
4992   Dexie$1.connections = Dexie.connections;
4993   Dexie$1.MultiModifyError = Dexie.MultiModifyError;
4994   Dexie$1.errnames = Dexie.errnames;
4995   Dexie$1.IndexSpec = Dexie.IndexSpec;
4996   Dexie$1.TableSchema = Dexie.TableSchema;
4997   Dexie$1.dependencies = Dexie.dependencies;
4998   Dexie$1.semVer = Dexie.semVer;
4999   Dexie$1.version = Dexie.version;
5000   Dexie$1.default = Dexie.default;
5001   Dexie$1.Dexie = Dexie.Dexie;
5002
5003   exports.Dexie = Dexie$1;
5004
5005}((this.BX = this.BX || {})));
5006//# sourceMappingURL=dexie.bitrix.bundle.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.