From 572836685837c4b9eb218f3b7c093132a2ba6577 Mon Sep 17 00:00:00 2001 From: David Fahlander Date: Thu, 7 Apr 2016 12:33:54 +0200 Subject: [PATCH] Build output --- addons/Dexie.Observable/dist/README.md | 37 - .../Dexie.Observable/dist/dexie-observable.js | 817 ++++ .../dist/dexie-observable.js.map | 1 + .../dist/dexie-observable.min.js | 2 + .../dist/dexie-observable.min.js.map | 1 + addons/Dexie.Syncable/dist/README.md | 37 - addons/Dexie.Syncable/dist/dexie-syncable.js | 1005 ++++ .../Dexie.Syncable/dist/dexie-syncable.js.map | 1 + .../Dexie.Syncable/dist/dexie-syncable.min.js | 2 + .../dist/dexie-syncable.min.js.map | 1 + dist/README.md | 51 - dist/dexie.d.ts | 448 ++ dist/dexie.js | 4187 +++++++++++++++++ dist/dexie.js.map | 1 + dist/dexie.min.js | 3 + dist/dexie.min.js.map | 1 + 16 files changed, 6470 insertions(+), 125 deletions(-) delete mode 100644 addons/Dexie.Observable/dist/README.md create mode 100644 addons/Dexie.Observable/dist/dexie-observable.js create mode 100644 addons/Dexie.Observable/dist/dexie-observable.js.map create mode 100644 addons/Dexie.Observable/dist/dexie-observable.min.js create mode 100644 addons/Dexie.Observable/dist/dexie-observable.min.js.map delete mode 100644 addons/Dexie.Syncable/dist/README.md create mode 100644 addons/Dexie.Syncable/dist/dexie-syncable.js create mode 100644 addons/Dexie.Syncable/dist/dexie-syncable.js.map create mode 100644 addons/Dexie.Syncable/dist/dexie-syncable.min.js create mode 100644 addons/Dexie.Syncable/dist/dexie-syncable.min.js.map delete mode 100644 dist/README.md create mode 100644 dist/dexie.d.ts create mode 100644 dist/dexie.js create mode 100644 dist/dexie.js.map create mode 100644 dist/dexie.min.js create mode 100644 dist/dexie.min.js.map diff --git a/addons/Dexie.Observable/dist/README.md b/addons/Dexie.Observable/dist/README.md deleted file mode 100644 index 7574f1379..000000000 --- a/addons/Dexie.Observable/dist/README.md +++ /dev/null @@ -1,37 +0,0 @@ -## Can't find dexie-observable.js? -Transpiled code (dist version) IS ONLY checked in to -the [releases](https://github.com/dfahlander/Dexie.js/tree/releases/addons/Dexie.Observable/dist) -branch. - -## Download -[npmcdn.com/dexie-observable/dist/dexie-observable.js](https://npmcdn.com/dexie-observable/dist/dexie-observable.js) - -[npmcdn.com/dexie-observable/dist/dexie-observable.min.js](https://npmcdn.com/dexie-observable/dist/dexie-observable.min.js) - -[npmcdn.com/dexie-observable/dist/dexie-observable.js.map](https://npmcdn.com/dexie-observable/dist/dexie-observable.js.map) - -[npmcdn.com/dexie-observable/dist/dexie-observable.min.js.map](https://npmcdn.com/dexie-observable/dist/dexie-observable.min.js.map) - -## npm -``` -npm install dexie-observable --save -``` -## bower -Since Dexie v1.3.4, addons are included in the dexie bower package. -``` -$ bower install dexie --save -$ ls bower_components/dexie/addons/Dexie.Observable/dist -dexie-observable.js dexie-observable.js.map dexie-observable.min.js dexie-observable.min.js.map - -``` -## Or build them yourself... -Fork Dexie.js, then: -``` -git clone https://github.com/YOUR-USERNAME/Dexie.js.git -cd Dexie.js -npm install -cd addons/Dexie.Observable -npm run build # or npm run watch - -``` -If you're on windows, you need to use an elevated command prompt of some reason to get `npm install` to work. diff --git a/addons/Dexie.Observable/dist/dexie-observable.js b/addons/Dexie.Observable/dist/dexie-observable.js new file mode 100644 index 000000000..f123b5968 --- /dev/null +++ b/addons/Dexie.Observable/dist/dexie-observable.js @@ -0,0 +1,817 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('dexie')) : + typeof define === 'function' && define.amd ? define(['dexie'], factory) : + global.Dexie.Observable = factory(global.Dexie); +}(this, function (Dexie) { 'use strict'; + + Dexie = 'default' in Dexie ? Dexie['default'] : Dexie; + + var global = self; + + /** class DatabaseChange + * + * Object contained by the _changes table. + */ + var DatabaseChange = Dexie.defineClass({ + rev: Number, // Auto-incremented primary key + source: String, // Optional source creating the change. Set if transaction.source was set when doing the operation. + table: String, // Table name + key: Object, // Primary key. Any type. + type: Number, // 1 = CREATE, 2 = UPDATE, 3 = DELETE + obj: Object, // CREATE: obj contains the object created. + mods: Object, // UPDATE: mods contains the modifications made to the object. + oldObj: Object // DELETE: oldObj contains the object deleted. UPDATE: oldObj contains the old object before updates applied. + }); + + // Import some usable helper functions + var override = Dexie.override; + var Promise = Dexie.Promise; + var browserIsShuttingDown = false; + + function Observable(db) { + /// + /// Extension to Dexie providing Syncronization capabilities to Dexie. + /// + /// + + var NODE_TIMEOUT = 20000, + // 20 seconds before local db instances are timed out. This is so that old changes can be deleted when not needed and to garbage collect old _syncNodes objects. + HIBERNATE_GRACE_PERIOD = 20000, + // 20 seconds + // LOCAL_POLL: The time to wait before polling local db for changes and cleaning up old nodes. + // Polling for changes is a fallback only needed in certain circomstances (when the onstorage event doesnt reach all listeners - when different browser windows doesnt share the same process) + LOCAL_POLL = 2000, + // 1 second. In real-world there will be this value + the time it takes to poll(). + CREATE = 1, + UPDATE = 2, + DELETE = 3; + + var localStorage = Observable.localStorageImpl; + + /** class SyncNode + * + * Object contained in the _syncNodes table. + */ + var SyncNode = Dexie.defineClass({ + //id: Number, + myRevision: Number, + type: String, // "local" or "remote" + lastHeartBeat: Number, + deleteTimeStamp: Number, // In case lastHeartBeat is too old, a value of now + HIBERNATE_GRACE_PERIOD will be set here. If reached before node wakes up, node will be deleted. + url: String, // Only applicable for "remote" nodes. Only used in Dexie.Syncable. + isMaster: Number, // 1 if true. Not using Boolean because it's not possible to index Booleans in IE implementation of IDB. + + // Below properties should be extended in Dexie.Syncable. Not here. They apply to remote nodes only (type == "remote"): + syncProtocol: String, // Tells which implementation of ISyncProtocol to use for remote syncing. + syncContext: null, + syncOptions: Object, + connected: false, // FIXTHIS: Remove! Replace with status. + status: Number, + appliedRemoteRevision: null, + remoteBaseRevisions: [{ local: Number, remote: null }], + dbUploadState: { + tablesToUpload: [String], + currentTable: String, + currentKey: null, + localBaseRevision: Number + } + }); + + var mySyncNode = null; + + // Allow other addons to access the local sync node. May be needed by Dexie.Syncable. + Object.defineProperty(db, "_localSyncNode", { + get: function () { + return mySyncNode; + } + }); + + var pollHandle = null; + + if (Dexie.fake) { + // This code will never run. + // It's here just to enable auto-complete in visual studio - helps a lot when writing code. + db.version(1).stores({ + _syncNodes: "++id,myRevision,lastHeartBeat", + _changes: "++rev", + _intercomm: "++id,destinationNode", + _uncommittedChanges: "++id,node" + }); + db._syncNodes.mapToClass(SyncNode); + db._changes.mapToClass(DatabaseChange); + mySyncNode = new SyncNode({ + myRevision: 0, + type: "local", + lastHeartBeat: Date.now(), + deleteTimeStamp: null + }); + } + + // + // Override parsing the stores to add "_changes" and "_syncNodes" tables. + // + db.Version.prototype._parseStoresSpec = override(db.Version.prototype._parseStoresSpec, function (origFunc) { + return function (stores, dbSchema) { + // Create the _changes and _syncNodes tables + stores["_changes"] = "++rev"; + stores["_syncNodes"] = "++id,myRevision,lastHeartBeat,url,isMaster,type,status"; + stores["_intercomm"] = "++id,destinationNode"; + stores["_uncommittedChanges"] = "++id,node"; // For remote syncing when server returns a partial result. + // Call default implementation. Will populate the dbSchema structures. + origFunc.call(this, stores, dbSchema); + // Allow UUID primary keys using $$ prefix on primary key or indexes + Object.keys(dbSchema).forEach(function (tableName) { + var schema = dbSchema[tableName]; + if (schema.primKey.name.indexOf('$$') === 0) { + schema.primKey.uuid = true; + schema.primKey.name = schema.primKey.name.substr(2); + schema.primKey.keyPath = schema.primKey.keyPath.substr(2); + } + }); + // Now mark all observable tables + Object.keys(dbSchema).forEach(function (tableName) { + // Marked observable tables with "observable" in their TableSchema. + if (tableName.indexOf('_') !== 0 && tableName.indexOf('$') !== 0) { + dbSchema[tableName].observable = true; + } + }); + }; + }); + + // + // Make sure to subscribe to "creating", "updating" and "deleting" hooks for all observable tables that were created in the stores() method. + // + db._tableFactory = override(db._tableFactory, function (origCreateTable) { + return function createTable(mode, tableSchema, transactionPromiseFactory) { + var table = origCreateTable.apply(this, arguments); + if (table.schema.observable && transactionPromiseFactory === db._transPromiseFactory) { + // Only crudMonitor when creating + crudMonitor(table); + } + if (table.name === "_syncNodes" && transactionPromiseFactory === db._transPromiseFactory) { + table.mapToClass(SyncNode); + } + return table; + }; + }); + + // changes event on db: + db.on.addEventType({ + changes: 'asap', + cleanup: [promisableChain, nop], // fire (nodesTable, changesTable, trans). Hook called when cleaning up nodes. Subscribers may return a Promise to to more stuff. May do additional stuff if local sync node is master. + message: 'asap' + }); + + // + // Overide transaction creation to always include the "_changes" store when any observable store is involved. + // + db._createTransaction = override(db._createTransaction, function (origFunc) { + return function (mode, storenames, dbschema, parent) { + if (db.dynamicallyOpened()) return origFunc.apply(this, arguments); // Don't observe dynamically opened databases. + var addChanges = false; + if (mode === 'readwrite' && storenames.some(function (storeName) { + return dbschema[storeName] && dbschema[storeName].observable; + })) { + // At least one included store is a observable store. Make sure to also include the _changes store. + addChanges = true; + storenames = storenames.slice(0); // Clone + if (storenames.indexOf("_changes") === -1) storenames.push("_changes"); // Otherwise, firefox will hang... (I've reported the bug to Mozilla@Bugzilla) + } + // Call original db._createTransaction() + var trans = origFunc.call(this, mode, storenames, dbschema, parent); + // If this transaction is bound to any observable table, make sure to add changes when transaction completes. + if (addChanges) { + trans._lastWrittenRevision = 0; + trans.on('complete', function () { + if (trans._lastWrittenRevision) { + // Changes were written in this transaction. + if (!parent) { + // This is root-level transaction, i.e. a physical commit has happened. + // Delay-trigger a wakeup call: + if (wakeupObservers.timeoutHandle) clearTimeout(wakeupObservers.timeoutHandle); + wakeupObservers.timeoutHandle = setTimeout(function () { + delete wakeupObservers.timeoutHandle; + wakeupObservers(trans._lastWrittenRevision); + }, 25); + } else { + // This is just a virtual commit of a sub transaction. + // Wait with waking up observers until root transaction has committed. + // Make sure to mark root transaction so that it will wakeup observers upon commit. + var rootTransaction = function findRootTransaction(trans) { + return trans.parent ? findRootTransaction(trans.parent) : trans; + }(parent); + rootTransaction._lastWrittenRevision = Math.max(trans._lastWrittenRevision, rootTransaction.lastWrittenRevision || 0); + } + } + }); + // Derive "source" property from parent transaction by default + if (trans.parent && trans.parent.source) trans.source = trans.parent.source; + } + return trans; + }; + }); + + // If Observable.latestRevsion[db.name] is undefined, set it to 0 so that comparing against it always works. + // You might think that it will always be undefined before this call, but in case another Dexie instance in the same + // window with the same database name has been created already, this static property will already be set correctly. + Observable.latestRevision[db.name] = Observable.latestRevision[db.name] || 0; + + function wakeupObservers(lastWrittenRevision) { + // Make sure Observable.latestRevision[db.name] is still below our value, now when some time has elapsed and other db instances in same window possibly could have made changes too. + if (Observable.latestRevision[db.name] < lastWrittenRevision) { + // Set the static property lastRevision[db.name] to the revision of the last written change. + Observable.latestRevision[db.name] = lastWrittenRevision; + // Wakeup ourselves, and any other db instances on this window: + Dexie.ignoreTransaction(function () { + Observable.on('latestRevisionIncremented').fire(db.name, lastWrittenRevision); + }); + // Observable.on.latestRevisionIncremented will only wakeup db's in current window. + // We need a storage event to wakeup other windwos. + // Since indexedDB lacks storage events, let's use the storage event from WebStorage just for + // the purpose to wakeup db instances in other windows. + localStorage.setItem('Dexie.Observable/latestRevision/' + db.name, lastWrittenRevision); // In IE, this will also wakeup our own window. However, onLatestRevisionIncremented will work around this by only running once per revision id. + } + } + + db.close = override(db.close, function (origClose) { + return function () { + if (db.dynamicallyOpened()) return origClose.apply(this, arguments); // Don't observe dynamically opened databases. + // Teardown our framework. + if (wakeupObservers.timeoutHandle) { + clearTimeout(wakeupObservers.timeoutHandle); + delete wakeupObservers.timeoutHandle; + } + Observable.on('latestRevisionIncremented').unsubscribe(onLatestRevisionIncremented); + Observable.on('suicideNurseCall').unsubscribe(onSuicide); + Observable.on('intercomm').unsubscribe(onIntercomm); + Observable.on('beforeunload').unsubscribe(onBeforeUnload); + // Inform other db instances in same window that we are dying: + if (mySyncNode && mySyncNode.id) { + Observable.on.suicideNurseCall.fire(db.name, mySyncNode.id); + // Inform other windows as well: + localStorage.setItem('Dexie.Observable/deadnode:' + mySyncNode.id.toString() + '/' + db.name, "dead"); // In IE, this will also wakeup our own window. cleanup() may trigger twice per other db instance. But that doesnt to anything. + mySyncNode.deleteTimeStamp = 1; // One millisecond after 1970. Makes it occur in the past but still keeps it truthy. + mySyncNode.lastHeartBeat = 0; + db._syncNodes.put(mySyncNode); // This async operation may be cancelled since the browser is closing down now. + mySyncNode = null; + } + + if (pollHandle) clearTimeout(pollHandle); + pollHandle = null; + return origClose.apply(this, arguments); + }; + }); + + // Override Dexie.delete() in order to delete Observable.latestRevision[db.name]. + db.delete = override(db.delete, function (origDelete) { + return function () { + return origDelete.apply(this, arguments).then(function (result) { + // Reset Observable.latestRevision[db.name] + Observable.latestRevision[db.name] = 0; + return result; + }); + }; + }); + + // + // The Creating/Updating/Deleting hook will make sure any change is stored to the changes table + // + function crudMonitor(table) { + /// + var tableName = table.name; + + table.hook('creating').subscribe(function (primKey, obj, trans) { + /// + var rv = undefined; + if (primKey === undefined && table.schema.primKey.uuid) { + primKey = rv = Observable.createUUID(); + if (table.schema.primKey.keyPath) { + Dexie.setByKeyPath(obj, table.schema.primKey.keyPath, primKey); + } + } + + var change = { + source: trans.source || null, // If a "source" is marked on the transaction, store it. Useful for observers that want to ignore their own changes. + table: tableName, + key: primKey === undefined ? null : primKey, + type: CREATE, + obj: obj + }; + + var promise = trans.tables._changes.add(change).then(function (rev) { + trans._lastWrittenRevision = Math.max(trans._lastWrittenRevision, rev); + return rev; + }); + + // Wait for onsuccess so that we have the primKey if it is auto-incremented and update the change item if so. + this.onsuccess = function (resultKey) { + if (primKey != resultKey) promise._then(function () { + change.key = resultKey; + trans.tables._changes.put(change); + }); + }; + this.onerror = function (err) { + // If the main operation fails, make sure to regret the change + promise._then(function (rev) { + // Will only happen if app code catches the main operation error to prohibit transaction from aborting. + trans.tables._changes.delete(rev); + }); + }; + + return rv; + }); + + table.hook('updating').subscribe(function (mods, primKey, oldObj, trans) { + /// + // mods may contain property paths with undefined as value if the property + // is being deleted. Since we cannot persist undefined we need to act + // like those changes is setting the value to null instead. + var modsWithoutUndefined = {}; + // As of current Dexie version (1.0.3) hook may be called even if it wouldnt really change. + // Therefore we may do that kind of optimization here - to not add change entries if + // there's nothing to change. + var anythingChanged = false; + var newObj = Dexie.deepClone(oldObj); + for (var propPath in mods) { + var mod = mods[propPath]; + if (typeof mod === 'undefined') { + Dexie.delByKeyPath(newObj, propPath); + modsWithoutUndefined[propPath] = null; // Null is as close we could come to deleting a property when not allowing undefined. + anythingChanged = true; + } else { + var currentValue = Dexie.getByKeyPath(oldObj, propPath); + if (mod !== currentValue && JSON.stringify(mod) !== JSON.stringify(currentValue)) { + Dexie.setByKeyPath(newObj, propPath, mod); + modsWithoutUndefined[propPath] = mod; + anythingChanged = true; + } + } + } + if (anythingChanged) { + var change = { + source: trans.source || null, // If a "source" is marked on the transaction, store it. Useful for observers that want to ignore their own changes. + table: tableName, + key: primKey, + type: UPDATE, + mods: modsWithoutUndefined, + oldObj: oldObj, + obj: newObj + }; + var promise = trans.tables._changes.add(change); // Just so we get the correct revision order of the update... + this.onsuccess = function () { + promise._then(function (rev) { + trans._lastWrittenRevision = Math.max(trans._lastWrittenRevision, rev); + }); + }; + this.onerror = function (err) { + // If the main operation fails, make sure to regret the change. + promise._then(function (rev) { + // Will only happen if app code catches the main operation error to prohibit transaction from aborting. + trans.tables._changes.delete(rev); + }); + }; + } + }); + + table.hook('deleting').subscribe(function (primKey, obj, trans) { + /// + var promise = trans.tables._changes.add({ + source: trans.source || null, // If a "source" is marked on the transaction, store it. Useful for observers that want to ignore their own changes. + table: tableName, + key: primKey, + type: DELETE, + oldObj: obj + }).then(function (rev) { + trans._lastWrittenRevision = Math.max(trans._lastWrittenRevision, rev); + return rev; + }); + this.onerror = function () { + // If the main operation fails, make sure to regret the change. + // Using _then because if promise is already fullfilled, the standard then() would + // do setTimeout() and we would loose the transaction. + promise._then(function (rev) { + // Will only happen if app code catches the main operation error to prohibit transaction from aborting. + trans.tables._changes.delete(rev); + }); + }; + }); + } + + // When db opens, make sure to start monitor any changes before other db operations will start. + db.on("ready", function startObserving() { + if (db.dynamicallyOpened()) return db; // Don't observe dynamically opened databases. + return db.table("_changes").orderBy("rev").last(function (lastChange) { + // Since startObserving() is called before database open() method, this will be the first database operation enqueued to db. + // Therefore we know that the retrieved value will be This query will + var latestRevision = lastChange ? lastChange.rev : 0; + mySyncNode = new SyncNode({ + myRevision: latestRevision, + type: "local", + lastHeartBeat: Date.now(), + deleteTimeStamp: null, + isMaster: 0 + }); + if (Observable.latestRevision[db.name] < latestRevision) { + // Side track . For correctness whenever setting Observable.latestRevision[db.name] we must make sure the event is fired if increased: + // There are other db instances in same window that hasnt yet been informed about a new revision + Observable.latestRevision[db.name] = latestRevision; + Dexie.ignoreTransaction(function () { + Observable.on.latestRevisionIncremented.fire(latestRevision); + }); + } + // Add new sync node or if this is a reopening of the database after a close() call, update it. + return db.transaction('rw', '_syncNodes', function () { + db._syncNodes.where('isMaster').equals(1).count(function (anyMasterNode) { + if (!anyMasterNode) { + // There's no master node. Let's take that role then. + mySyncNode.isMaster = 1; + } + // Add our node to DB and start subscribing to events + db._syncNodes.add(mySyncNode).then(function () { + Observable.on('latestRevisionIncremented', onLatestRevisionIncremented); // Wakeup when a new revision is available. + Observable.on('beforeunload', onBeforeUnload); + Observable.on('suicideNurseCall', onSuicide); + Observable.on('intercomm', onIntercomm); + // Start polling for changes and do cleanups: + pollHandle = setTimeout(poll, LOCAL_POLL); + }); + }); + }).then(function () { + cleanup(); + }); + //cleanup(); + //}); + }); + }, true); // True means the on(ready) event will survive a db reopening (db.close() / db.open()). + + var handledRevision = 0; + + function onLatestRevisionIncremented(dbname, latestRevision) { + if (dbname === db.name) { + if (handledRevision >= latestRevision) return; // Make sure to only run once per revision. (Workaround for IE triggering storage event on same window) + handledRevision = latestRevision; + Dexie.vip(function () { + readChanges(latestRevision); + }); + } + } + + function readChanges(latestRevision, recursion, wasPartial) { + // Whenever changes are read, fire db.on("changes") with the array of changes. Eventually, limit the array to 1000 entries or so (an entire database is + // downloaded from server AFTER we are initiated. For example, if first sync call fails, then after a while we get reconnected. However, that scenario + // should be handled in case database is totally empty we should fail if sync is not available) + if (!recursion && readChanges.ongoingOperation) { + // We are already reading changes. Prohibit a parallell execution of this which would lead to duplicate trigging of 'changes' event. + // Instead, the callback in toArray() will always check Observable.latestRevision[db.name] to see if it has changed and if so, re-launch readChanges(). + // The caller should get the Promise instance from the ongoing operation so that the then() method will resolve when operation is finished. + return readChanges.ongoingOperation; + } + + var partial = false; + var ourSyncNode = mySyncNode; // Because mySyncNode can suddenly be set to null on database close, and worse, can be set to a new value if database is reopened. + if (!ourSyncNode) { + return Promise.reject("Database closed"); + } + var LIMIT = 1000; + var promise = db._changes.where("rev").above(ourSyncNode.myRevision).limit(LIMIT).toArray(function (changes) { + if (changes.length > 0) { + var lastChange = changes[changes.length - 1]; + partial = changes.length === LIMIT; + db.on('changes').fire(changes, partial); + ourSyncNode.myRevision = lastChange.rev; + } else if (wasPartial) { + // No more changes, BUT since we have triggered on('changes') with partial = true, + // we HAVE TO trigger changes again with empty list and partial = false + db.on('changes').fire([], false); + } + + return db.table("_syncNodes").update(ourSyncNode, { + lastHeartBeat: Date.now(), + deleteTimeStamp: null, // Reset "deleteTimeStamp" flag if it was there. + myRevision: ourSyncNode.myRevision + }); + }).then(function (nodeWasUpdated) { + if (!nodeWasUpdated) { + // My node has been deleted. We must have been lazy and got removed by another node. + if (browserIsShuttingDown) { + throw new Error("Browser is shutting down"); + } else { + db.close(); + console.error("Out of sync"); // TODO: What to do? Reload the page? + if (global.location) global.location.reload(true); + throw new Error("Out of sync"); // Will make current promise reject + } + } + + // Check if more changes have come since we started reading changes in the first place. If so, relaunch readChanges and let the ongoing promise not + // resolve until all changes have been read. + if (partial || Observable.latestRevision[db.name] > ourSyncNode.myRevision) { + // Either there were more than 1000 changes or additional changes where added while we were reading these changes, + // In either case, call readChanges() again until we're done. + return readChanges(Observable.latestRevision[db.name], (recursion || 0) + 1, partial); + } + }).finally(function () { + delete readChanges.ongoingOperation; + }); + + if (!recursion) { + readChanges.ongoingOperation = promise; + } + return promise; + } + + function poll() { + pollHandle = null; + var currentInstance = mySyncNode.id; + Dexie.vip(function () { + // VIP ourselves. Otherwise we might not be able to consume intercomm messages from master node before database has finished opening. This would make DB stall forever. Cannot rely on storage-event since it may not always work in some browsers of different processes. + readChanges(Observable.latestRevision[db.name]).then(cleanup).then(consumeIntercommMessages).finally(function () { + // Poll again in given interval: + if (mySyncNode && mySyncNode.id === currentInstance) { + pollHandle = setTimeout(poll, LOCAL_POLL); + } + }); + }); + } + + function cleanup() { + var ourSyncNode = mySyncNode; + if (!ourSyncNode) return Promise.reject("Database closed"); + return db.transaction('rw', '_syncNodes', '_changes', '_intercomm', function () { + // Cleanup dead local nodes that has no heartbeat for over a minute + // Dont do the following: + //nodes.where("lastHeartBeat").below(Date.now() - NODE_TIMEOUT).and(function (node) { return node.type == "local"; }).delete(); + // Because client may have been in hybernate mode and recently woken up. That would lead to deletion of all nodes. + // Instead, we should mark any old nodes for deletion in a minute or so. If they still dont wakeup after that minute we could consider them dead. + var weBecameMaster = false; + db._syncNodes.where("lastHeartBeat").below(Date.now() - NODE_TIMEOUT).and(function (node) { + return node.type === 'local'; + }).modify(function (node) { + if (node.deleteTimeStamp && node.deleteTimeStamp < Date.now()) { + // Delete the node. + delete this.value; + // Cleanup localStorage "deadnode:" entry for this node (localStorage API was used to wakeup other windows (onstorage event) - an event type missing in indexedDB.) + localStorage.removeItem('Dexie.Observable/deadnode:' + node.id + '/' + db.name); + // Check if we are deleting a master node + if (node.isMaster) { + // The node we are deleting is master. We must take over that role. + // OK to call nodes.update(). No need to call Dexie.vip() because nodes is opened in existing transaction! + db._syncNodes.update(ourSyncNode, { isMaster: 1 }); + weBecameMaster = true; + } + // Cleanup intercomm messages destinated to the node being deleted: + db._intercomm.where("destinationNode").equals(node.id).modify(function (msg) { + // OK to call intercomm. No need to call Dexie.vip() because intercomm is opened in existing transaction! + // Delete the message from DB and if someone is waiting for reply, let ourselved answer the request. + delete this.value; + if (msg.wantReply) { + // Message wants a reply, meaning someone must take over its messages when it dies. Let us be that one! + Dexie.ignoreTransaction(function () { + consumeMessage(msg); + }); + } + }); + } else if (!node.deleteTimeStamp) { + // Mark the node for deletion + node.deleteTimeStamp = Date.now() + HIBERNATE_GRACE_PERIOD; + } + }).then(function () { + // Cleanup old revisions that no node is interested of. + Observable.deleteOldChanges(db); + return db.on("cleanup").fire(weBecameMaster); + }); + }); + } + + function onBeforeUnload(event) { + // Mark our own sync node for deletion. + if (!mySyncNode) return; + browserIsShuttingDown = true; + mySyncNode.deleteTimeStamp = 1; // One millisecond after 1970. Makes it occur in the past but still keeps it truthy. + mySyncNode.lastHeartBeat = 0; + db._syncNodes.put(mySyncNode); // This async operation may be cancelled since the browser is closing down now. + Observable.wereTheOneDying = true; // If other nodes in same window wakes up by this call, make sure they dont start taking over mastership and stuff... + // Inform other windows that we're gone, so that they may take over our role if needed. Setting localStorage item below will trigger Observable.onStorage, which will trigger onSuicie() below: + localStorage.setItem('Dexie.Observable/deadnode:' + mySyncNode.id.toString() + '/' + db.name, "dead"); // In IE, this will also wakeup our own window. However, that is doublechecked in nursecall subscriber below. + } + + function onSuicide(dbname, nodeID) { + if (dbname === db.name && !Observable.wereTheOneDying) { + // Make sure it's dead indeed. Second bullet. Why? Because it has marked itself for deletion in the onbeforeunload event, which is fired just before window dies. + // It's own call to put() may have been cancelled. + // Note also that in IE, this event may be called twice, but that doesnt harm! + Dexie.vip(function () { + db._syncNodes.update(nodeID, { deleteTimeStamp: 1, lastHeartBeat: 0 }).then(cleanup); + }); + } + } + + // + // Intercommunication between nodes + // + // Enable inter-process communication between browser windows + + var requestsWaitingForReply = {}; + + db.sendMessage = function (type, message, destinationNode, options) { + /// Type of message + /// Message to send + /// ID of destination node + /// {wantReply: Boolean, isFailure: Boolean, requestId: Number}. If wantReply, the returned promise will complete with the reply from remote. Otherwise it will complete when message has been successfully sent. + if (!mySyncNode) return Promise.reject("Database closed"); + options = options || {}; + var msg = { message: message, destinationNode: destinationNode, sender: mySyncNode.id, type: type }; + Dexie.extend(msg, options); // wantReply: wantReply, success: !isFailure, requestId: ... + var tables = ["_intercomm"]; + if (options.wantReply) tables.push("_syncNodes"); // If caller wants a reply, include "_syncNodes" in transaction to check that there's a reciever there. Otherwise, new master will get it. + return db.transaction('rw?', tables, function () { + if (options.wantReply) { + // Check that there is a reciever there to take the request. + return db._syncNodes.where('id').equals(destinationNode).count(function (recieverAlive) { + if (recieverAlive) return addMessage(msg);else return db._syncNodes.where('isMaster').above(0).first(function (masterNode) { + msg.destinationNode = masterNode.id; + return addMessage(msg); + }); + }); + } else { + addMessage(msg); // No need to return Promise. Caller dont need a reply. + } + + function addMessage(msg) { + return db._intercomm.add(msg).then(function (messageId) { + localStorage.setItem("Dexie.Observable/intercomm/" + db.name, messageId.toString()); + Dexie.ignoreTransaction(function () { + Observable.on.intercomm.fire(db.name); + }); + if (options.wantReply) { + return new Promise(function (resolve, reject) { + requestsWaitingForReply[messageId.toString()] = { resolve: resolve, reject: reject }; + }); + } + }); + } + }); + }; + + db.broadcastMessage = function (type, message, bIncludeSelf) { + if (!mySyncNode) return Promise.reject("Database closed"); + var mySyncNodeId = mySyncNode.id; + db._syncNodes.each(function (node) { + if (node.type === 'local' && (bIncludeSelf || node.id !== mySyncNodeId)) { + db.sendMessage(type, message, node.id); + } + }); + }; + + db.observable = {}; + db.observable.SyncNode = SyncNode; + + function consumeIntercommMessages() { + // Check if we got messages: + if (!mySyncNode) return Promise.reject("Database closed"); + return db.table('_intercomm').where("destinationNode").equals(mySyncNode.id).modify(function (msg) { + // For each message, fire the event and remove message. + delete this.value; + Dexie.ignoreTransaction(function () { + consumeMessage(msg); + }); + }); + } + + function consumeMessage(msg) { + if (msg.type === 'response') { + // This is a response. Lookup pending request and fulfill it's promise. + var request = requestsWaitingForReply[msg.requestId.toString()]; + if (request) { + if (msg.isFailure) { + request.reject(msg.message.error); + } else { + request.resolve(msg.message.result); + } + delete requestsWaitingForReply[msg.requestId.toString()]; + } + } else { + // This is a message or request. Fire the event and add an API for the subscriber to use if reply is requested + msg.resolve = function (result) { + db.sendMessage('response', { result: result }, msg.sender, { requestId: msg.id }); + }; + msg.reject = function (error) { + db.sendMessage('response', { error: error.toString() }, msg.sender, { isFailure: true, requestId: msg.id }); + }; + var message = msg.message; + delete msg.message; + Dexie.extend(msg, message); + db.on.message.fire(msg); + } + } + + function onIntercomm(dbname) { + // When storage event trigger us to check + if (dbname === db.name) { + consumeIntercommMessages(); + } + } + } + + // + // Help functions + // + + function nop() {}; + + function promisableChain(f1, f2) { + if (f1 === nop) return f2; + return function () { + var res = f1.apply(this, arguments); + if (res && typeof res.then === 'function') { + var thiz = this, + args = arguments; + return res.then(function () { + return f2.apply(thiz, args); + }); + } + return f2.apply(this, arguments); + }; + } + + // + // Static properties and methods + // + + Observable.latestRevision = {}; // Latest revision PER DATABASE. Example: Observable.latestRevision.FriendsDB = 37; + Observable.on = Dexie.events(null, "latestRevisionIncremented", "suicideNurseCall", "intercomm", "beforeunload"); // fire(dbname, value); + Observable.createUUID = function () { + // Decent solution from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript + var d = Date.now(); + var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c === 'x' ? r : r & 0x7 | 0x8).toString(16); + }); + return uuid; + }; + + Observable.deleteOldChanges = function (db) { + db._syncNodes.orderBy("myRevision").first(function (oldestNode) { + var timeout = Date.now() + 300, + timedout = false; + db._changes.where("rev").below(oldestNode.myRevision).until(function () { + return timedout = Date.now() > timeout; + }).delete().then(function () { + // If not done garbage collecting, reschedule a continuation of it until done. + if (timedout) setTimeout(function () { + Observable.deleteOldChanges(db); + }, 10); + }); + }); + }; + + Observable._onStorage = function onStorage(event) { + // We use the onstorage event to trigger onLatestRevisionIncremented since we will wake up when other windows modify the DB as well! + if (event.key.indexOf("Dexie.Observable/") === 0) { + // For example "Dexie.Observable/latestRevision/FriendsDB" + var parts = event.key.split('/'); + var prop = parts[1]; + var dbname = parts[2]; + if (prop === 'latestRevision') { + var rev = parseInt(event.newValue, 10); + if (!isNaN(rev) && rev > Observable.latestRevision[dbname]) { + Observable.latestRevision[dbname] = rev; + Dexie.ignoreTransaction(function () { + Observable.on('latestRevisionIncremented').fire(dbname, rev); + }); + } + } else if (prop.indexOf("deadnode:") === 0) { + var nodeID = parseInt(prop.split(':')[1], 10); + if (event.newValue) { + Observable.on.suicideNurseCall.fire(dbname, nodeID); + } + } else if (prop === 'intercomm') { + if (event.newValue) { + Observable.on.intercomm.fire(dbname); + } + } + } + }; + + Observable._onBeforeUnload = function () { + Observable.on.beforeunload.fire(); + }; + + Observable.localStorageImpl = global.localStorage; + + // + // Map window events to static events in Dexie.Observable: + // + if (global.addEventListener) { + global.addEventListener("storage", Observable._onStorage); + global.addEventListener("beforeunload", Observable._onBeforeUnload); + } + // Register addon: + Dexie.Observable = Observable; + Dexie.addons.push(Observable); + + return Observable; + +})); +//# sourceMappingURL=dexie-observable.js.map \ No newline at end of file diff --git a/addons/Dexie.Observable/dist/dexie-observable.js.map b/addons/Dexie.Observable/dist/dexie-observable.js.map new file mode 100644 index 000000000..d2f7bbf62 --- /dev/null +++ b/addons/Dexie.Observable/dist/dexie-observable.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dexie-observable.js","sources":["../C:/repos/dexie-release/addons/Dexie.Observable/tools/tmp/src/Dexie.Observable.js"],"sourcesContent":["/// \n\n/**\r\n * Dexie.Observable.js\r\n * ===================\r\n * Dexie addon for observing database changes not just on local db instance but also on other instances and windows.\r\n *\r\n * version: {version} Alpha, {date}\r\n *\r\n * Disclaimber: This addon is in alpha status meaning that\r\n * its API and behavior may change.\r\n *\r\n */\nimport Dexie from 'dexie';\n\nvar global = self;\n\n/** class DatabaseChange\r\n *\r\n * Object contained by the _changes table.\r\n */\nvar DatabaseChange = Dexie.defineClass({\n rev: Number, // Auto-incremented primary key\n source: String, // Optional source creating the change. Set if transaction.source was set when doing the operation.\n table: String, // Table name\n key: Object, // Primary key. Any type.\n type: Number, // 1 = CREATE, 2 = UPDATE, 3 = DELETE\n obj: Object, // CREATE: obj contains the object created.\n mods: Object, // UPDATE: mods contains the modifications made to the object.\n oldObj: Object // DELETE: oldObj contains the object deleted. UPDATE: oldObj contains the old object before updates applied.\n});\n\n// Import some usable helper functions\nvar override = Dexie.override;\nvar Promise = Dexie.Promise;\nvar browserIsShuttingDown = false;\n\nexport default function Observable(db) {\n /// \n /// Extension to Dexie providing Syncronization capabilities to Dexie.\n /// \n /// \n\n var NODE_TIMEOUT = 20000,\n // 20 seconds before local db instances are timed out. This is so that old changes can be deleted when not needed and to garbage collect old _syncNodes objects.\n HIBERNATE_GRACE_PERIOD = 20000,\n // 20 seconds\n // LOCAL_POLL: The time to wait before polling local db for changes and cleaning up old nodes.\n // Polling for changes is a fallback only needed in certain circomstances (when the onstorage event doesnt reach all listeners - when different browser windows doesnt share the same process)\n LOCAL_POLL = 2000,\n // 1 second. In real-world there will be this value + the time it takes to poll().\n CREATE = 1,\n UPDATE = 2,\n DELETE = 3;\n\n var localStorage = Observable.localStorageImpl;\n\n /** class SyncNode\r\n *\r\n * Object contained in the _syncNodes table.\r\n */\n var SyncNode = Dexie.defineClass({\n //id: Number,\n myRevision: Number,\n type: String, // \"local\" or \"remote\"\n lastHeartBeat: Number,\n deleteTimeStamp: Number, // In case lastHeartBeat is too old, a value of now + HIBERNATE_GRACE_PERIOD will be set here. If reached before node wakes up, node will be deleted.\n url: String, // Only applicable for \"remote\" nodes. Only used in Dexie.Syncable.\n isMaster: Number, // 1 if true. Not using Boolean because it's not possible to index Booleans in IE implementation of IDB.\n\n // Below properties should be extended in Dexie.Syncable. Not here. They apply to remote nodes only (type == \"remote\"):\n syncProtocol: String, // Tells which implementation of ISyncProtocol to use for remote syncing.\n syncContext: null,\n syncOptions: Object,\n connected: false, // FIXTHIS: Remove! Replace with status.\n status: Number,\n appliedRemoteRevision: null,\n remoteBaseRevisions: [{ local: Number, remote: null }],\n dbUploadState: {\n tablesToUpload: [String],\n currentTable: String,\n currentKey: null,\n localBaseRevision: Number\n }\n });\n\n var mySyncNode = null;\n\n // Allow other addons to access the local sync node. May be needed by Dexie.Syncable.\n Object.defineProperty(db, \"_localSyncNode\", {\n get: function () {\n return mySyncNode;\n }\n });\n\n var pollHandle = null;\n\n if (Dexie.fake) {\n // This code will never run.\n // It's here just to enable auto-complete in visual studio - helps a lot when writing code.\n db.version(1).stores({\n _syncNodes: \"++id,myRevision,lastHeartBeat\",\n _changes: \"++rev\",\n _intercomm: \"++id,destinationNode\",\n _uncommittedChanges: \"++id,node\"\n });\n db._syncNodes.mapToClass(SyncNode);\n db._changes.mapToClass(DatabaseChange);\n mySyncNode = new SyncNode({\n myRevision: 0,\n type: \"local\",\n lastHeartBeat: Date.now(),\n deleteTimeStamp: null\n });\n }\n\n //\n // Override parsing the stores to add \"_changes\" and \"_syncNodes\" tables.\n //\n db.Version.prototype._parseStoresSpec = override(db.Version.prototype._parseStoresSpec, function (origFunc) {\n return function (stores, dbSchema) {\n // Create the _changes and _syncNodes tables\n stores[\"_changes\"] = \"++rev\";\n stores[\"_syncNodes\"] = \"++id,myRevision,lastHeartBeat,url,isMaster,type,status\";\n stores[\"_intercomm\"] = \"++id,destinationNode\";\n stores[\"_uncommittedChanges\"] = \"++id,node\"; // For remote syncing when server returns a partial result.\n // Call default implementation. Will populate the dbSchema structures.\n origFunc.call(this, stores, dbSchema);\n // Allow UUID primary keys using $$ prefix on primary key or indexes\n Object.keys(dbSchema).forEach(function (tableName) {\n var schema = dbSchema[tableName];\n if (schema.primKey.name.indexOf('$$') === 0) {\n schema.primKey.uuid = true;\n schema.primKey.name = schema.primKey.name.substr(2);\n schema.primKey.keyPath = schema.primKey.keyPath.substr(2);\n }\n });\n // Now mark all observable tables\n Object.keys(dbSchema).forEach(function (tableName) {\n // Marked observable tables with \"observable\" in their TableSchema.\n if (tableName.indexOf('_') !== 0 && tableName.indexOf('$') !== 0) {\n dbSchema[tableName].observable = true;\n }\n });\n };\n });\n\n //\n // Make sure to subscribe to \"creating\", \"updating\" and \"deleting\" hooks for all observable tables that were created in the stores() method.\n //\n db._tableFactory = override(db._tableFactory, function (origCreateTable) {\n return function createTable(mode, tableSchema, transactionPromiseFactory) {\n var table = origCreateTable.apply(this, arguments);\n if (table.schema.observable && transactionPromiseFactory === db._transPromiseFactory) {\n // Only crudMonitor when creating\n crudMonitor(table);\n }\n if (table.name === \"_syncNodes\" && transactionPromiseFactory === db._transPromiseFactory) {\n table.mapToClass(SyncNode);\n }\n return table;\n };\n });\n\n // changes event on db:\n db.on.addEventType({\n changes: 'asap',\n cleanup: [promisableChain, nop], // fire (nodesTable, changesTable, trans). Hook called when cleaning up nodes. Subscribers may return a Promise to to more stuff. May do additional stuff if local sync node is master.\n message: 'asap'\n });\n\n //\n // Overide transaction creation to always include the \"_changes\" store when any observable store is involved.\n //\n db._createTransaction = override(db._createTransaction, function (origFunc) {\n return function (mode, storenames, dbschema, parent) {\n if (db.dynamicallyOpened()) return origFunc.apply(this, arguments); // Don't observe dynamically opened databases.\n var addChanges = false;\n if (mode === 'readwrite' && storenames.some(function (storeName) {\n return dbschema[storeName] && dbschema[storeName].observable;\n })) {\n // At least one included store is a observable store. Make sure to also include the _changes store.\n addChanges = true;\n storenames = storenames.slice(0); // Clone\n if (storenames.indexOf(\"_changes\") === -1) storenames.push(\"_changes\"); // Otherwise, firefox will hang... (I've reported the bug to Mozilla@Bugzilla)\n }\n // Call original db._createTransaction()\n var trans = origFunc.call(this, mode, storenames, dbschema, parent);\n // If this transaction is bound to any observable table, make sure to add changes when transaction completes.\n if (addChanges) {\n trans._lastWrittenRevision = 0;\n trans.on('complete', function () {\n if (trans._lastWrittenRevision) {\n // Changes were written in this transaction.\n if (!parent) {\n // This is root-level transaction, i.e. a physical commit has happened.\n // Delay-trigger a wakeup call:\n if (wakeupObservers.timeoutHandle) clearTimeout(wakeupObservers.timeoutHandle);\n wakeupObservers.timeoutHandle = setTimeout(function () {\n delete wakeupObservers.timeoutHandle;\n wakeupObservers(trans._lastWrittenRevision);\n }, 25);\n } else {\n // This is just a virtual commit of a sub transaction.\n // Wait with waking up observers until root transaction has committed.\n // Make sure to mark root transaction so that it will wakeup observers upon commit.\n var rootTransaction = function findRootTransaction(trans) {\n return trans.parent ? findRootTransaction(trans.parent) : trans;\n }(parent);\n rootTransaction._lastWrittenRevision = Math.max(trans._lastWrittenRevision, rootTransaction.lastWrittenRevision || 0);\n }\n }\n });\n // Derive \"source\" property from parent transaction by default\n if (trans.parent && trans.parent.source) trans.source = trans.parent.source;\n }\n return trans;\n };\n });\n\n // If Observable.latestRevsion[db.name] is undefined, set it to 0 so that comparing against it always works.\n // You might think that it will always be undefined before this call, but in case another Dexie instance in the same\n // window with the same database name has been created already, this static property will already be set correctly.\n Observable.latestRevision[db.name] = Observable.latestRevision[db.name] || 0;\n\n function wakeupObservers(lastWrittenRevision) {\n // Make sure Observable.latestRevision[db.name] is still below our value, now when some time has elapsed and other db instances in same window possibly could have made changes too.\n if (Observable.latestRevision[db.name] < lastWrittenRevision) {\n // Set the static property lastRevision[db.name] to the revision of the last written change.\n Observable.latestRevision[db.name] = lastWrittenRevision;\n // Wakeup ourselves, and any other db instances on this window:\n Dexie.ignoreTransaction(function () {\n Observable.on('latestRevisionIncremented').fire(db.name, lastWrittenRevision);\n });\n // Observable.on.latestRevisionIncremented will only wakeup db's in current window.\n // We need a storage event to wakeup other windwos.\n // Since indexedDB lacks storage events, let's use the storage event from WebStorage just for\n // the purpose to wakeup db instances in other windows.\n localStorage.setItem('Dexie.Observable/latestRevision/' + db.name, lastWrittenRevision); // In IE, this will also wakeup our own window. However, onLatestRevisionIncremented will work around this by only running once per revision id.\n }\n }\n\n db.close = override(db.close, function (origClose) {\n return function () {\n if (db.dynamicallyOpened()) return origClose.apply(this, arguments); // Don't observe dynamically opened databases.\n // Teardown our framework.\n if (wakeupObservers.timeoutHandle) {\n clearTimeout(wakeupObservers.timeoutHandle);\n delete wakeupObservers.timeoutHandle;\n }\n Observable.on('latestRevisionIncremented').unsubscribe(onLatestRevisionIncremented);\n Observable.on('suicideNurseCall').unsubscribe(onSuicide);\n Observable.on('intercomm').unsubscribe(onIntercomm);\n Observable.on('beforeunload').unsubscribe(onBeforeUnload);\n // Inform other db instances in same window that we are dying:\n if (mySyncNode && mySyncNode.id) {\n Observable.on.suicideNurseCall.fire(db.name, mySyncNode.id);\n // Inform other windows as well:\n localStorage.setItem('Dexie.Observable/deadnode:' + mySyncNode.id.toString() + '/' + db.name, \"dead\"); // In IE, this will also wakeup our own window. cleanup() may trigger twice per other db instance. But that doesnt to anything.\n mySyncNode.deleteTimeStamp = 1; // One millisecond after 1970. Makes it occur in the past but still keeps it truthy.\n mySyncNode.lastHeartBeat = 0;\n db._syncNodes.put(mySyncNode); // This async operation may be cancelled since the browser is closing down now.\n mySyncNode = null;\n }\n\n if (pollHandle) clearTimeout(pollHandle);\n pollHandle = null;\n return origClose.apply(this, arguments);\n };\n });\n\n // Override Dexie.delete() in order to delete Observable.latestRevision[db.name].\n db.delete = override(db.delete, function (origDelete) {\n return function () {\n return origDelete.apply(this, arguments).then(function (result) {\n // Reset Observable.latestRevision[db.name]\n Observable.latestRevision[db.name] = 0;\n return result;\n });\n };\n });\n\n //\n // The Creating/Updating/Deleting hook will make sure any change is stored to the changes table\n //\n function crudMonitor(table) {\n /// \n var tableName = table.name;\n\n table.hook('creating').subscribe(function (primKey, obj, trans) {\n /// \n var rv = undefined;\n if (primKey === undefined && table.schema.primKey.uuid) {\n primKey = rv = Observable.createUUID();\n if (table.schema.primKey.keyPath) {\n Dexie.setByKeyPath(obj, table.schema.primKey.keyPath, primKey);\n }\n }\n\n var change = {\n source: trans.source || null, // If a \"source\" is marked on the transaction, store it. Useful for observers that want to ignore their own changes.\n table: tableName,\n key: primKey === undefined ? null : primKey,\n type: CREATE,\n obj: obj\n };\n\n var promise = trans.tables._changes.add(change).then(function (rev) {\n trans._lastWrittenRevision = Math.max(trans._lastWrittenRevision, rev);\n return rev;\n });\n\n // Wait for onsuccess so that we have the primKey if it is auto-incremented and update the change item if so.\n this.onsuccess = function (resultKey) {\n if (primKey != resultKey) promise._then(function () {\n change.key = resultKey;\n trans.tables._changes.put(change);\n });\n };\n this.onerror = function (err) {\n // If the main operation fails, make sure to regret the change\n promise._then(function (rev) {\n // Will only happen if app code catches the main operation error to prohibit transaction from aborting.\n trans.tables._changes.delete(rev);\n });\n };\n\n return rv;\n });\n\n table.hook('updating').subscribe(function (mods, primKey, oldObj, trans) {\n /// \n // mods may contain property paths with undefined as value if the property\n // is being deleted. Since we cannot persist undefined we need to act\n // like those changes is setting the value to null instead.\n var modsWithoutUndefined = {};\n // As of current Dexie version (1.0.3) hook may be called even if it wouldnt really change.\n // Therefore we may do that kind of optimization here - to not add change entries if\n // there's nothing to change.\n var anythingChanged = false;\n var newObj = Dexie.deepClone(oldObj);\n for (var propPath in mods) {\n var mod = mods[propPath];\n if (typeof mod === 'undefined') {\n Dexie.delByKeyPath(newObj, propPath);\n modsWithoutUndefined[propPath] = null; // Null is as close we could come to deleting a property when not allowing undefined.\n anythingChanged = true;\n } else {\n var currentValue = Dexie.getByKeyPath(oldObj, propPath);\n if (mod !== currentValue && JSON.stringify(mod) !== JSON.stringify(currentValue)) {\n Dexie.setByKeyPath(newObj, propPath, mod);\n modsWithoutUndefined[propPath] = mod;\n anythingChanged = true;\n }\n }\n }\n if (anythingChanged) {\n var change = {\n source: trans.source || null, // If a \"source\" is marked on the transaction, store it. Useful for observers that want to ignore their own changes.\n table: tableName,\n key: primKey,\n type: UPDATE,\n mods: modsWithoutUndefined,\n oldObj: oldObj,\n obj: newObj\n };\n var promise = trans.tables._changes.add(change); // Just so we get the correct revision order of the update...\n this.onsuccess = function () {\n promise._then(function (rev) {\n trans._lastWrittenRevision = Math.max(trans._lastWrittenRevision, rev);\n });\n };\n this.onerror = function (err) {\n // If the main operation fails, make sure to regret the change.\n promise._then(function (rev) {\n // Will only happen if app code catches the main operation error to prohibit transaction from aborting.\n trans.tables._changes.delete(rev);\n });\n };\n }\n });\n\n table.hook('deleting').subscribe(function (primKey, obj, trans) {\n /// \n var promise = trans.tables._changes.add({\n source: trans.source || null, // If a \"source\" is marked on the transaction, store it. Useful for observers that want to ignore their own changes.\n table: tableName,\n key: primKey,\n type: DELETE,\n oldObj: obj\n }).then(function (rev) {\n trans._lastWrittenRevision = Math.max(trans._lastWrittenRevision, rev);\n return rev;\n });\n this.onerror = function () {\n // If the main operation fails, make sure to regret the change.\n // Using _then because if promise is already fullfilled, the standard then() would\n // do setTimeout() and we would loose the transaction.\n promise._then(function (rev) {\n // Will only happen if app code catches the main operation error to prohibit transaction from aborting.\n trans.tables._changes.delete(rev);\n });\n };\n });\n }\n\n // When db opens, make sure to start monitor any changes before other db operations will start.\n db.on(\"ready\", function startObserving() {\n if (db.dynamicallyOpened()) return db; // Don't observe dynamically opened databases.\n return db.table(\"_changes\").orderBy(\"rev\").last(function (lastChange) {\n // Since startObserving() is called before database open() method, this will be the first database operation enqueued to db.\n // Therefore we know that the retrieved value will be This query will\n var latestRevision = lastChange ? lastChange.rev : 0;\n mySyncNode = new SyncNode({\n myRevision: latestRevision,\n type: \"local\",\n lastHeartBeat: Date.now(),\n deleteTimeStamp: null,\n isMaster: 0\n });\n if (Observable.latestRevision[db.name] < latestRevision) {\n // Side track . For correctness whenever setting Observable.latestRevision[db.name] we must make sure the event is fired if increased:\n // There are other db instances in same window that hasnt yet been informed about a new revision\n Observable.latestRevision[db.name] = latestRevision;\n Dexie.ignoreTransaction(function () {\n Observable.on.latestRevisionIncremented.fire(latestRevision);\n });\n }\n // Add new sync node or if this is a reopening of the database after a close() call, update it.\n return db.transaction('rw', '_syncNodes', function () {\n db._syncNodes.where('isMaster').equals(1).count(function (anyMasterNode) {\n if (!anyMasterNode) {\n // There's no master node. Let's take that role then.\n mySyncNode.isMaster = 1;\n }\n // Add our node to DB and start subscribing to events\n db._syncNodes.add(mySyncNode).then(function () {\n Observable.on('latestRevisionIncremented', onLatestRevisionIncremented); // Wakeup when a new revision is available.\n Observable.on('beforeunload', onBeforeUnload);\n Observable.on('suicideNurseCall', onSuicide);\n Observable.on('intercomm', onIntercomm);\n // Start polling for changes and do cleanups:\n pollHandle = setTimeout(poll, LOCAL_POLL);\n });\n });\n }).then(function () {\n cleanup();\n });\n //cleanup();\n //});\n });\n }, true); // True means the on(ready) event will survive a db reopening (db.close() / db.open()).\n\n var handledRevision = 0;\n\n function onLatestRevisionIncremented(dbname, latestRevision) {\n if (dbname === db.name) {\n if (handledRevision >= latestRevision) return; // Make sure to only run once per revision. (Workaround for IE triggering storage event on same window)\n handledRevision = latestRevision;\n Dexie.vip(function () {\n readChanges(latestRevision);\n });\n }\n }\n\n function readChanges(latestRevision, recursion, wasPartial) {\n // Whenever changes are read, fire db.on(\"changes\") with the array of changes. Eventually, limit the array to 1000 entries or so (an entire database is\n // downloaded from server AFTER we are initiated. For example, if first sync call fails, then after a while we get reconnected. However, that scenario\n // should be handled in case database is totally empty we should fail if sync is not available)\n if (!recursion && readChanges.ongoingOperation) {\n // We are already reading changes. Prohibit a parallell execution of this which would lead to duplicate trigging of 'changes' event.\n // Instead, the callback in toArray() will always check Observable.latestRevision[db.name] to see if it has changed and if so, re-launch readChanges().\n // The caller should get the Promise instance from the ongoing operation so that the then() method will resolve when operation is finished.\n return readChanges.ongoingOperation;\n }\n\n var partial = false;\n var ourSyncNode = mySyncNode; // Because mySyncNode can suddenly be set to null on database close, and worse, can be set to a new value if database is reopened.\n if (!ourSyncNode) {\n return Promise.reject(\"Database closed\");\n }\n var LIMIT = 1000;\n var promise = db._changes.where(\"rev\").above(ourSyncNode.myRevision).limit(LIMIT).toArray(function (changes) {\n if (changes.length > 0) {\n var lastChange = changes[changes.length - 1];\n partial = changes.length === LIMIT;\n db.on('changes').fire(changes, partial);\n ourSyncNode.myRevision = lastChange.rev;\n } else if (wasPartial) {\n // No more changes, BUT since we have triggered on('changes') with partial = true,\n // we HAVE TO trigger changes again with empty list and partial = false\n db.on('changes').fire([], false);\n }\n\n return db.table(\"_syncNodes\").update(ourSyncNode, {\n lastHeartBeat: Date.now(),\n deleteTimeStamp: null, // Reset \"deleteTimeStamp\" flag if it was there.\n myRevision: ourSyncNode.myRevision\n });\n }).then(function (nodeWasUpdated) {\n if (!nodeWasUpdated) {\n // My node has been deleted. We must have been lazy and got removed by another node.\n if (browserIsShuttingDown) {\n throw new Error(\"Browser is shutting down\");\n } else {\n db.close();\n console.error(\"Out of sync\"); // TODO: What to do? Reload the page?\n if (global.location) global.location.reload(true);\n throw new Error(\"Out of sync\"); // Will make current promise reject\n }\n }\n\n // Check if more changes have come since we started reading changes in the first place. If so, relaunch readChanges and let the ongoing promise not\n // resolve until all changes have been read.\n if (partial || Observable.latestRevision[db.name] > ourSyncNode.myRevision) {\n // Either there were more than 1000 changes or additional changes where added while we were reading these changes,\n // In either case, call readChanges() again until we're done.\n return readChanges(Observable.latestRevision[db.name], (recursion || 0) + 1, partial);\n }\n }).finally(function () {\n delete readChanges.ongoingOperation;\n });\n\n if (!recursion) {\n readChanges.ongoingOperation = promise;\n }\n return promise;\n }\n\n function poll() {\n pollHandle = null;\n var currentInstance = mySyncNode.id;\n Dexie.vip(function () {\n // VIP ourselves. Otherwise we might not be able to consume intercomm messages from master node before database has finished opening. This would make DB stall forever. Cannot rely on storage-event since it may not always work in some browsers of different processes.\n readChanges(Observable.latestRevision[db.name]).then(cleanup).then(consumeIntercommMessages).finally(function () {\n // Poll again in given interval:\n if (mySyncNode && mySyncNode.id === currentInstance) {\n pollHandle = setTimeout(poll, LOCAL_POLL);\n }\n });\n });\n }\n\n function cleanup() {\n var ourSyncNode = mySyncNode;\n if (!ourSyncNode) return Promise.reject(\"Database closed\");\n return db.transaction('rw', '_syncNodes', '_changes', '_intercomm', function () {\n // Cleanup dead local nodes that has no heartbeat for over a minute\n // Dont do the following:\n //nodes.where(\"lastHeartBeat\").below(Date.now() - NODE_TIMEOUT).and(function (node) { return node.type == \"local\"; }).delete();\n // Because client may have been in hybernate mode and recently woken up. That would lead to deletion of all nodes.\n // Instead, we should mark any old nodes for deletion in a minute or so. If they still dont wakeup after that minute we could consider them dead.\n var weBecameMaster = false;\n db._syncNodes.where(\"lastHeartBeat\").below(Date.now() - NODE_TIMEOUT).and(function (node) {\n return node.type === 'local';\n }).modify(function (node) {\n if (node.deleteTimeStamp && node.deleteTimeStamp < Date.now()) {\n // Delete the node.\n delete this.value;\n // Cleanup localStorage \"deadnode:\" entry for this node (localStorage API was used to wakeup other windows (onstorage event) - an event type missing in indexedDB.)\n localStorage.removeItem('Dexie.Observable/deadnode:' + node.id + '/' + db.name);\n // Check if we are deleting a master node\n if (node.isMaster) {\n // The node we are deleting is master. We must take over that role.\n // OK to call nodes.update(). No need to call Dexie.vip() because nodes is opened in existing transaction!\n db._syncNodes.update(ourSyncNode, { isMaster: 1 });\n weBecameMaster = true;\n }\n // Cleanup intercomm messages destinated to the node being deleted:\n db._intercomm.where(\"destinationNode\").equals(node.id).modify(function (msg) {\n // OK to call intercomm. No need to call Dexie.vip() because intercomm is opened in existing transaction!\n // Delete the message from DB and if someone is waiting for reply, let ourselved answer the request.\n delete this.value;\n if (msg.wantReply) {\n // Message wants a reply, meaning someone must take over its messages when it dies. Let us be that one!\n Dexie.ignoreTransaction(function () {\n consumeMessage(msg);\n });\n }\n });\n } else if (!node.deleteTimeStamp) {\n // Mark the node for deletion\n node.deleteTimeStamp = Date.now() + HIBERNATE_GRACE_PERIOD;\n }\n }).then(function () {\n // Cleanup old revisions that no node is interested of.\n Observable.deleteOldChanges(db);\n return db.on(\"cleanup\").fire(weBecameMaster);\n });\n });\n }\n\n function onBeforeUnload(event) {\n // Mark our own sync node for deletion.\n if (!mySyncNode) return;\n browserIsShuttingDown = true;\n mySyncNode.deleteTimeStamp = 1; // One millisecond after 1970. Makes it occur in the past but still keeps it truthy.\n mySyncNode.lastHeartBeat = 0;\n db._syncNodes.put(mySyncNode); // This async operation may be cancelled since the browser is closing down now.\n Observable.wereTheOneDying = true; // If other nodes in same window wakes up by this call, make sure they dont start taking over mastership and stuff...\n // Inform other windows that we're gone, so that they may take over our role if needed. Setting localStorage item below will trigger Observable.onStorage, which will trigger onSuicie() below:\n localStorage.setItem('Dexie.Observable/deadnode:' + mySyncNode.id.toString() + '/' + db.name, \"dead\"); // In IE, this will also wakeup our own window. However, that is doublechecked in nursecall subscriber below.\n }\n\n function onSuicide(dbname, nodeID) {\n if (dbname === db.name && !Observable.wereTheOneDying) {\n // Make sure it's dead indeed. Second bullet. Why? Because it has marked itself for deletion in the onbeforeunload event, which is fired just before window dies.\n // It's own call to put() may have been cancelled.\n // Note also that in IE, this event may be called twice, but that doesnt harm!\n Dexie.vip(function () {\n db._syncNodes.update(nodeID, { deleteTimeStamp: 1, lastHeartBeat: 0 }).then(cleanup);\n });\n }\n }\n\n //\n // Intercommunication between nodes\n //\n // Enable inter-process communication between browser windows\n\n var requestsWaitingForReply = {};\n\n db.sendMessage = function (type, message, destinationNode, options) {\n /// Type of message\n /// Message to send\n /// ID of destination node\n /// {wantReply: Boolean, isFailure: Boolean, requestId: Number}. If wantReply, the returned promise will complete with the reply from remote. Otherwise it will complete when message has been successfully sent.\n if (!mySyncNode) return Promise.reject(\"Database closed\");\n options = options || {};\n var msg = { message: message, destinationNode: destinationNode, sender: mySyncNode.id, type: type };\n Dexie.extend(msg, options); // wantReply: wantReply, success: !isFailure, requestId: ...\n var tables = [\"_intercomm\"];\n if (options.wantReply) tables.push(\"_syncNodes\"); // If caller wants a reply, include \"_syncNodes\" in transaction to check that there's a reciever there. Otherwise, new master will get it.\n return db.transaction('rw?', tables, function () {\n if (options.wantReply) {\n // Check that there is a reciever there to take the request.\n return db._syncNodes.where('id').equals(destinationNode).count(function (recieverAlive) {\n if (recieverAlive) return addMessage(msg);else return db._syncNodes.where('isMaster').above(0).first(function (masterNode) {\n msg.destinationNode = masterNode.id;\n return addMessage(msg);\n });\n });\n } else {\n addMessage(msg); // No need to return Promise. Caller dont need a reply.\n }\n\n function addMessage(msg) {\n return db._intercomm.add(msg).then(function (messageId) {\n localStorage.setItem(\"Dexie.Observable/intercomm/\" + db.name, messageId.toString());\n Dexie.ignoreTransaction(function () {\n Observable.on.intercomm.fire(db.name);\n });\n if (options.wantReply) {\n return new Promise(function (resolve, reject) {\n requestsWaitingForReply[messageId.toString()] = { resolve: resolve, reject: reject };\n });\n }\n });\n }\n });\n };\n\n db.broadcastMessage = function (type, message, bIncludeSelf) {\n if (!mySyncNode) return Promise.reject(\"Database closed\");\n var mySyncNodeId = mySyncNode.id;\n db._syncNodes.each(function (node) {\n if (node.type === 'local' && (bIncludeSelf || node.id !== mySyncNodeId)) {\n db.sendMessage(type, message, node.id);\n }\n });\n };\n\n db.observable = {};\n db.observable.SyncNode = SyncNode;\n\n function consumeIntercommMessages() {\n // Check if we got messages:\n if (!mySyncNode) return Promise.reject(\"Database closed\");\n return db.table('_intercomm').where(\"destinationNode\").equals(mySyncNode.id).modify(function (msg) {\n // For each message, fire the event and remove message.\n delete this.value;\n Dexie.ignoreTransaction(function () {\n consumeMessage(msg);\n });\n });\n }\n\n function consumeMessage(msg) {\n if (msg.type === 'response') {\n // This is a response. Lookup pending request and fulfill it's promise.\n var request = requestsWaitingForReply[msg.requestId.toString()];\n if (request) {\n if (msg.isFailure) {\n request.reject(msg.message.error);\n } else {\n request.resolve(msg.message.result);\n }\n delete requestsWaitingForReply[msg.requestId.toString()];\n }\n } else {\n // This is a message or request. Fire the event and add an API for the subscriber to use if reply is requested\n msg.resolve = function (result) {\n db.sendMessage('response', { result: result }, msg.sender, { requestId: msg.id });\n };\n msg.reject = function (error) {\n db.sendMessage('response', { error: error.toString() }, msg.sender, { isFailure: true, requestId: msg.id });\n };\n var message = msg.message;\n delete msg.message;\n Dexie.extend(msg, message);\n db.on.message.fire(msg);\n }\n }\n\n function onIntercomm(dbname) {\n // When storage event trigger us to check\n if (dbname === db.name) {\n consumeIntercommMessages();\n }\n }\n}\n\n//\n// Help functions\n//\n\nfunction nop() {};\n\nfunction promisableChain(f1, f2) {\n if (f1 === nop) return f2;\n return function () {\n var res = f1.apply(this, arguments);\n if (res && typeof res.then === 'function') {\n var thiz = this,\n args = arguments;\n return res.then(function () {\n return f2.apply(thiz, args);\n });\n }\n return f2.apply(this, arguments);\n };\n}\n\n//\n// Static properties and methods\n//\n\nObservable.latestRevision = {}; // Latest revision PER DATABASE. Example: Observable.latestRevision.FriendsDB = 37;\nObservable.on = Dexie.events(null, \"latestRevisionIncremented\", \"suicideNurseCall\", \"intercomm\", \"beforeunload\"); // fire(dbname, value);\nObservable.createUUID = function () {\n // Decent solution from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript\n var d = Date.now();\n var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n var r = (d + Math.random() * 16) % 16 | 0;\n d = Math.floor(d / 16);\n return (c === 'x' ? r : r & 0x7 | 0x8).toString(16);\n });\n return uuid;\n};\n\nObservable.deleteOldChanges = function (db) {\n db._syncNodes.orderBy(\"myRevision\").first(function (oldestNode) {\n var timeout = Date.now() + 300,\n timedout = false;\n db._changes.where(\"rev\").below(oldestNode.myRevision).until(function () {\n return timedout = Date.now() > timeout;\n }).delete().then(function () {\n // If not done garbage collecting, reschedule a continuation of it until done.\n if (timedout) setTimeout(function () {\n Observable.deleteOldChanges(db);\n }, 10);\n });\n });\n};\n\nObservable._onStorage = function onStorage(event) {\n // We use the onstorage event to trigger onLatestRevisionIncremented since we will wake up when other windows modify the DB as well!\n if (event.key.indexOf(\"Dexie.Observable/\") === 0) {\n // For example \"Dexie.Observable/latestRevision/FriendsDB\"\n var parts = event.key.split('/');\n var prop = parts[1];\n var dbname = parts[2];\n if (prop === 'latestRevision') {\n var rev = parseInt(event.newValue, 10);\n if (!isNaN(rev) && rev > Observable.latestRevision[dbname]) {\n Observable.latestRevision[dbname] = rev;\n Dexie.ignoreTransaction(function () {\n Observable.on('latestRevisionIncremented').fire(dbname, rev);\n });\n }\n } else if (prop.indexOf(\"deadnode:\") === 0) {\n var nodeID = parseInt(prop.split(':')[1], 10);\n if (event.newValue) {\n Observable.on.suicideNurseCall.fire(dbname, nodeID);\n }\n } else if (prop === 'intercomm') {\n if (event.newValue) {\n Observable.on.intercomm.fire(dbname);\n }\n }\n }\n};\n\nObservable._onBeforeUnload = function () {\n Observable.on.beforeunload.fire();\n};\n\nObservable.localStorageImpl = global.localStorage;\n\n//\n// Map window events to static events in Dexie.Observable:\n//\nif (global.addEventListener) {\n global.addEventListener(\"storage\", Observable._onStorage);\n global.addEventListener(\"beforeunload\", Observable._onBeforeUnload);\n}\n// Register addon:\nDexie.Observable = Observable;\nDexie.addons.push(Observable);"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/addons/Dexie.Observable/dist/dexie-observable.min.js b/addons/Dexie.Observable/dist/dexie-observable.min.js new file mode 100644 index 000000000..73d99658c --- /dev/null +++ b/addons/Dexie.Observable/dist/dexie-observable.min.js @@ -0,0 +1,2 @@ +!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n(require("dexie")):"function"==typeof define&&define.amd?define(["dexie"],n):e.Dexie.Observable=n(e.Dexie)}(this,function(e){"use strict";function n(c){function u(t){n.latestRevision[c.name]=t)return;I=t,e.vip(function(){f(t)})}}function f(e,t,i){if(!t&&f.ongoingOperation)return f.ongoingOperation;var a=!1,r=j;if(!r)return s.reject("Database closed");var u=1e3,d=c._changes.where("rev").above(r.myRevision).limit(u).toArray(function(e){if(e.length>0){var n=e[e.length-1];a=e.length===u,c.on("changes").fire(e,a),r.myRevision=n.rev}else i&&c.on("changes").fire([],!1);return c.table("_syncNodes").update(r,{lastHeartBeat:Date.now(),deleteTimeStamp:null,myRevision:r.myRevision})}).then(function(e){if(!e)throw l?new Error("Browser is shutting down"):(c.close(),console.error("Out of sync"),o.location&&o.location.reload(!0),new Error("Out of sync"));return a||n.latestRevision[c.name]>r.myRevision?f(n.latestRevision[c.name],(t||0)+1,a):void 0})["finally"](function(){delete f.ongoingOperation});return t||(f.ongoingOperation=d),d}function v(){B=null;var t=j.id;e.vip(function(){f(n.latestRevision[c.name]).then(y).then(b)["finally"](function(){j&&j.id===t&&(B=setTimeout(v,N))})})}function y(){var t=j;return t?c.transaction("rw","_syncNodes","_changes","_intercomm",function(){var i=!1;c._syncNodes.where("lastHeartBeat").below(Date.now()-x).and(function(e){return"local"===e.type}).modify(function(n){n.deleteTimeStamp&&n.deleteTimeStampi})["delete"]().then(function(){o&&setTimeout(function(){n.deleteOldChanges(e)},10)})})},n._onStorage=function(t){if(0===t.key.indexOf("Dexie.Observable/")){var i=t.key.split("/"),o=i[1],a=i[2];if("latestRevision"===o){var r=parseInt(t.newValue,10);!isNaN(r)&&r>n.latestRevision[a]&&(n.latestRevision[a]=r,e.ignoreTransaction(function(){n.on("latestRevisionIncremented").fire(a,r)}))}else if(0===o.indexOf("deadnode:")){var s=parseInt(o.split(":")[1],10);t.newValue&&n.on.suicideNurseCall.fire(a,s)}else"intercomm"===o&&t.newValue&&n.on.intercomm.fire(a)}},n._onBeforeUnload=function(){n.on.beforeunload.fire()},n.localStorageImpl=o.localStorage,o.addEventListener&&(o.addEventListener("storage",n._onStorage),o.addEventListener("beforeunload",n._onBeforeUnload)),e.Observable=n,e.addons.push(n),n}); +//# sourceMappingURL=dist/dexie-observable.min.js.map \ No newline at end of file diff --git a/addons/Dexie.Observable/dist/dexie-observable.min.js.map b/addons/Dexie.Observable/dist/dexie-observable.min.js.map new file mode 100644 index 000000000..23c44764f --- /dev/null +++ b/addons/Dexie.Observable/dist/dexie-observable.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../C:/repos/dexie-release/addons/Dexie.Observable/tools/tmp/src/Dexie.Observable.js"],"names":["Observable","db","wakeupObservers","lastWrittenRevision","latestRevision","name","Dexie","ignoreTransaction","on","fire","localStorage","setItem","crudMonitor","table","tableName","hook","subscribe","primKey","obj","trans","rv","undefined","schema","uuid","createUUID","keyPath","setByKeyPath","change","source","key","type","CREATE","promise","tables","_changes","add","then","rev","_lastWrittenRevision","Math","max","this","onsuccess","resultKey","_then","put","onerror","err","mods","oldObj","modsWithoutUndefined","anythingChanged","newObj","deepClone","propPath","mod","delByKeyPath","currentValue","getByKeyPath","JSON","stringify","UPDATE","DELETE","onLatestRevisionIncremented","dbname","handledRevision","vip","readChanges","recursion","wasPartial","ongoingOperation","partial","ourSyncNode","mySyncNode","Promise","reject","LIMIT","where","above","myRevision","limit","toArray","changes","length","lastChange","update","lastHeartBeat","Date","now","deleteTimeStamp","nodeWasUpdated","browserIsShuttingDown","Error","close","console","error","global","location","reload","poll","pollHandle","currentInstance","id","cleanup","consumeIntercommMessages","setTimeout","LOCAL_POLL","transaction","weBecameMaster","_syncNodes","below","NODE_TIMEOUT","and","node","modify","value","removeItem","isMaster","_intercomm","equals","msg","wantReply","consumeMessage","HIBERNATE_GRACE_PERIOD","deleteOldChanges","onBeforeUnload","event","wereTheOneDying","toString","onSuicide","nodeID","request","requestsWaitingForReply","requestId","isFailure","message","resolve","result","sendMessage","sender","extend","onIntercomm","localStorageImpl","SyncNode","defineClass","Number","String","url","syncProtocol","syncContext","syncOptions","Object","connected","status","appliedRemoteRevision","remoteBaseRevisions","local","remote","dbUploadState","tablesToUpload","currentTable","currentKey","localBaseRevision","defineProperty","get","fake","version","stores","_uncommittedChanges","mapToClass","DatabaseChange","Version","prototype","_parseStoresSpec","override","origFunc","dbSchema","call","keys","forEach","indexOf","substr","observable","_tableFactory","origCreateTable","mode","tableSchema","transactionPromiseFactory","apply","arguments","_transPromiseFactory","addEventType","promisableChain","nop","_createTransaction","storenames","dbschema","parent","dynamicallyOpened","addChanges","some","storeName","slice","push","rootTransaction","findRootTransaction","timeoutHandle","clearTimeout","origClose","unsubscribe","suicideNurseCall","origDelete","orderBy","last","latestRevisionIncremented","count","anyMasterNode","destinationNode","options","addMessage","messageId","intercomm","recieverAlive","first","masterNode","broadcastMessage","bIncludeSelf","mySyncNodeId","each","f1","f2","res","thiz","args","self","events","d","replace","c","r","random","floor","oldestNode","timeout","timedout","until","_onStorage","parts","split","prop","parseInt","newValue","isNaN","_onBeforeUnload","beforeunload","addEventListener","addons"],"mappings":"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","file":"dist/dexie-observable.min.js.map"} \ No newline at end of file diff --git a/addons/Dexie.Syncable/dist/README.md b/addons/Dexie.Syncable/dist/README.md deleted file mode 100644 index e2bb5cf5e..000000000 --- a/addons/Dexie.Syncable/dist/README.md +++ /dev/null @@ -1,37 +0,0 @@ -## Can't find dexie-syncable.js? -Transpiled code (dist version) IS ONLY checked in to -the [releases](https://github.com/dfahlander/Dexie.js/tree/releases/addons/Dexie.Syncable/dist). -branch. - -## Download -[npmcdn.com/dexie-syncable/dist/dexie-syncable.js](https://npmcdn.com/dexie-syncable/dist/dexie-syncable.js) - -[npmcdn.com/dexie-syncable/dist/dexie-syncable.min.js](https://npmcdn.com/dexie-syncable/dist/dexie-syncable.min.js) - -[npmcdn.com/dexie-syncable/dist/dexie-syncable.js.map](https://npmcdn.com/dexie-syncable/dist/dexie-syncable.js.map) - -[npmcdn.com/dexie-syncable/dist/dexie-syncable.min.js.map](https://npmcdn.com/dexie-syncable/dist/dexie-syncable.min.js.map) - -## npm -``` -npm install dexie-syncable --save -``` -## bower -Since Dexie v1.3.4, addons are included in the dexie bower package. -``` -$ bower install dexie --save -$ ls bower_components/dexie/addons/Dexie.Syncable/dist -dexie-syncable.js dexie-syncable.js.map dexie-syncable.min.js dexie-syncable.min.js.map - -``` -## Or build them yourself... -Fork Dexie.js, then: -``` -git clone https://github.com/YOUR-USERNAME/Dexie.js.git -cd Dexie.js -npm install -cd addons/Dexie.Syncable -npm run build # or npm run watch - -``` -If you're on windows, you need to use an elevated command prompt of some reason to get `npm install` to work. diff --git a/addons/Dexie.Syncable/dist/dexie-syncable.js b/addons/Dexie.Syncable/dist/dexie-syncable.js new file mode 100644 index 000000000..39232f2f1 --- /dev/null +++ b/addons/Dexie.Syncable/dist/dexie-syncable.js @@ -0,0 +1,1005 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('dexie'), require('dexie-observable')) : + typeof define === 'function' && define.amd ? define(['dexie', 'dexie-observable'], factory) : + global.Dexie.Syncable = factory(global.Dexie,global.dexieObservable); +}(this, function (Dexie,dexieObservable) { 'use strict'; + + Dexie = 'default' in Dexie ? Dexie['default'] : Dexie; + + var override = Dexie.override; + var Promise = Dexie.Promise; + var setByKeyPath = Dexie.setByKeyPath; + var Observable = Dexie.Observable; + function Syncable(db) { + /// + + var activePeers = []; + + // Change Types + var CREATE = 1, + UPDATE = 2, + DELETE = 3; + + // Statuses + var Statuses = Syncable.Statuses; + + var MAX_CHANGES_PER_CHUNK = 1000; + + db.on('message', function (msg) { + // Message from other local node arrives... + Dexie.vip(function () { + if (msg.type === 'connect') { + // We are master node and another non-master node wants us to do the connect. + db.syncable.connect(msg.protocolName, msg.url, msg.options).then(msg.resolve, msg.reject); + } else if (msg.type === 'disconnect') { + db.syncable.disconnect(msg.url).then(msg.resolve, msg.reject); + } else if (msg.type === 'syncStatusChanged') { + // We are client and a master node informs us about syncStatus change. + // Lookup the connectedProvider and call its event + db.syncable.on.statusChanged.fire(msg.newStatus, msg.url); + } + }); + }); + + db.on('cleanup', function (weBecameMaster) { + // A cleanup (done in Dexie.Observable) may result in that a master node is removed and we become master. + if (weBecameMaster) { + // We took over the master role in Observable's cleanup method + db._syncNodes.where('type').equals('remote').and(function (node) { + return node.status !== Statuses.OFFLINE && node.status !== Statuses.ERROR; + }).each(function (connectedRemoteNode) { + // There are connected remote nodes that we must take over + // Since we may be in the on(ready) event, we must get VIPed to continue + Dexie.ignoreTransaction(function () { + Dexie.vip(function () { + db.syncable.connect(connectedRemoteNode.syncProtocol, connectedRemoteNode.url, connectedRemoteNode.syncOptions); + }); + }); + }); + } + }); + + db.on('ready', function onReady() { + // Again, in onReady: If we ARE master, make sure to connect to remote servers that is in a connected state. + if (db._localSyncNode && db._localSyncNode.isMaster) { + // Make sure to connect to remote servers that is in a connected state (NOT OFFLINE or ERROR!) + return db._syncNodes.where('type').equals('remote').and(function (node) { + return node.status !== Statuses.OFFLINE && node.status !== Statuses.ERROR; + }).toArray(function (connectedRemoteNodes) { + // There are connected remote nodes that we must take over + if (connectedRemoteNodes.length > 0) { + return Promise.all(connectedRemoteNodes.map(function (node) { + return db.syncable.connect(node.syncProtocol, node.url, node.syncOptions).catch(function (err) { + return undefined; // If a node fails to connect, don't make db.open() reject. Accept it! + }); + })); + } + }); + } + }, true); // True means the ready event will survive a db reopen - db.close()/db.open() + + db.syncable = {}; + + db.syncable.getStatus = function (url, cb) { + if (db.isOpen()) { + return Dexie.vip(function () { + return db._syncNodes.where('url').equals(url).first(function (node) { + return node ? node.status : Statuses.OFFLINE; + }); + }).then(cb); + } else { + return Promise.resolve(Syncable.Statuses.OFFLINE).then(cb); + } + }; + + db.syncable.list = function () { + return db._syncNodes.where('type').equals('remote').toArray(function (a) { + return a.map(function (node) { + return node.url; + }); + }); + }; + + db.syncable.on = Dexie.events(db, { statusChanged: "asap" }); + + db.syncable.disconnect = function (url) { + if (db._localSyncNode && db._localSyncNode.isMaster) { + activePeers.filter(function (peer) { + return peer.url === url; + }).forEach(function (peer) { + peer.disconnect(Statuses.OFFLINE); + }); + } else { + db._syncNodes.where('isMaster').above(0).first(function (masterNode) { + db.sendMessage('disconnect', { url: url }, masterNode.id, { wantReply: true }); + }); + } + + return db._syncNodes.where("url").equals(url).modify(function (node) { + node.status = Statuses.OFFLINE; + }); + }; + + db.syncable.connect = function (protocolName, url, options) { + options = options || {}; // Make sure options is always an object because 1) Provider expects it to be. 2) We'll be persisting it and you cannot persist undefined. + var protocolInstance = Syncable.registeredProtocols[protocolName]; + + if (protocolInstance) { + if (db.isOpen() && db._localSyncNode) { + // Database is open + if (db._localSyncNode.isMaster) { + // We are master node + return connect(protocolInstance, protocolName, url, options, db._localSyncNode.id); + } else { + // We are not master node + // Request master node to do the connect: + db.table('_syncNodes').where('isMaster').above(0).first(function (masterNode) { + // There will always be a master node. In theory we may self have become master node when we come here. But that's ok. We'll request ourselves. + return db.sendMessage('connect', { protocolName: protocolName, url: url, options: options }, masterNode.id, { wantReply: true }); + }); + return Promise.resolve(); + } + } else { + // Database not yet open + // Wait for it to open + return new Promise(function (resolve, reject) { + db.on("ready", function syncWhenReady() { + return Dexie.vip(function () { + return db.syncable.connect(protocolName, url, options).then(resolve).catch(function (err) { + // Reject the promise returned to the caller of db.syncable.connect(): + reject(err); + // but resolve the promise that db.on("ready") waits for, because database should succeed to open even if the connect operation fails! + }); + }); + }); + }); + } + } else { + throw new Error("ISyncProtocol '" + protocolName + "' is not registered in Dexie.Syncable.registerSyncProtocol()"); + return new Promise(); // For code completion + } + }; + + db.syncable.delete = function (url) { + // Notice: Caller should call db.syncable.disconnect(url) and wait for it to finish before calling db.syncable.delete(url) + // Surround with a readwrite-transaction + return db.transaction('rw', db._syncNodes, db._changes, db._uncommittedChanges, function () { + // Find the node + db._syncNodes.where("url").equals(url).toArray(function (nodes) { + // If it's found (or even several found, as detected by @martindiphoorn), + // let's delete it (or them) and cleanup _changes and _uncommittedChanges + // accordingly. + if (nodes.length > 0) { + var nodeIDs = nodes.map(function (node) { + return node.id; + }); + // The following 'return' statement is not needed right now, but I leave it + // there because if we would like to add a 'then()' statement to the main , + // operation above ( db._syncNodes.where("url").equals(url).toArray(...) ) , + // this return statement will asure that the whole chain is waited for + // before entering the then() callback. + return db._syncNodes.where('id').anyOf(nodeIDs).delete().then(function () { + // When theese nodes are gone, let's clear the _changes table + // from all revisions older than the oldest node. + // Delete all changes older than revision of oldest node: + Observable.deleteOldChanges(); + // Also don't forget to delete all uncommittedChanges for the deleted node: + return db._uncommittedChanges.where('node').anyOf(nodeIDs).delete(); + }); + } + }); + }); + }; + + db.syncable.unsyncedChanges = function (url) { + return db._syncNodes.where("url").equals(url).first(function (node) { + return db._changes.where('rev').above(node.myRevision).toArray(); + }); + }; + + function connect(protocolInstance, protocolName, url, options, dbAliveID) { + /// + var existingPeer = activePeers.filter(function (peer) { + return peer.url === url; + }); + if (existingPeer.length > 0) { + // Never create multiple syncNodes with same protocolName and url. Instead, let the next call to connect() return the same promise that + // have already been started and eventually also resolved. If promise has already resolved (node connected), calling existing promise.then() will give a callback directly. + return existingPeer[0].connectPromise; + } + + var connectPromise = getOrCreateSyncNode(options).then(function (node) { + return connectProtocol(node); + }); + + var rejectConnectPromise = null; + var disconnected = false; + var hasMoreToGive = true; + var activePeer = { + url: url, + status: Statuses.OFFLINE, + connectPromise: connectPromise, + on: Dexie.events(null, "disconnect"), + disconnect: function (newStatus, error) { + if (!disconnected) { + activePeer.on.disconnect.fire(newStatus, error); + var pos = activePeers.indexOf(activePeer); + if (pos >= 0) activePeers.splice(pos, 1); + if (error && rejectConnectPromise) rejectConnectPromise(error); + } + disconnected = true; + } + }; + activePeers.push(activePeer); + + return connectPromise; + + function stillAlive() { + // A better method than doing db.isOpen() because the same db instance may have been reopened, but then this sync call should be dead + // because the new instance should be considered a fresh instance and will have another local node. + return db._localSyncNode && db._localSyncNode.id === dbAliveID; + } + + function getOrCreateSyncNode(options) { + return db.transaction('rw', db._syncNodes, function () { + if (!url) throw new Error("Url cannot be empty"); + // Returning a promise from transaction scope will make the transaction promise resolve with the value of that promise. + + return db._syncNodes.where("url").equalsIgnoreCase(url).first(function (node) { + // + // PersistedContext : IPersistedContext + // + function PersistedContext(nodeID, otherProps) { + this.nodeID = nodeID; + if (otherProps) Dexie.extend(this, otherProps); + } + + PersistedContext.prototype.save = function () { + // Store this instance in the syncContext property of the node it belongs to. + return Dexie.vip(function () { + return node.save(); + }); + }; + + if (node) { + // Node already there. Make syncContext become an instance of PersistedContext: + node.syncContext = new PersistedContext(node.id, node.syncContext); + node.syncProtocol = protocolName; // In case it was changed (would be very strange but...) could happen... + db._syncNodes.put(node); + } else { + // Create new node and sync everything + node = new db.observable.SyncNode(); + node.myRevision = -1; + node.appliedRemoteRevision = null; + node.remoteBaseRevisions = []; + node.type = "remote"; + node.syncProtocol = protocolName; + node.url = url; + node.syncOptions = options; + node.lastHeartBeat = Date.now(); + node.dbUploadState = null; + Promise.resolve(function () { + // If options.initialUpload is explicitely false, set myRevision to currentRevision. + if (options.initialUpload === false) return db._changes.lastKey(function (currentRevision) { + node.myRevision = currentRevision; + }); + }).then(function () { + db._syncNodes.add(node).then(function (nodeId) { + node.syncContext = new PersistedContext(nodeId); // Update syncContext in db with correct nodeId. + db._syncNodes.put(node); + }); + }); + } + + return node; // returning node will make the db.transaction()-promise resolve with this value. + }); + }); + } + + function connectProtocol(node) { + /// + + function changeStatusTo(newStatus) { + if (node.status !== newStatus) { + node.status = newStatus; + node.save(); + db.syncable.on.statusChanged.fire(newStatus, url); + // Also broadcast message to other nodes about the status + db.broadcastMessage("syncStatusChanged", { newStatus: newStatus, url: url }, false); + } + } + + activePeer.on('disconnect', function (newStatus) { + if (!isNaN(newStatus)) changeStatusTo(newStatus); + }); + + var connectedContinuation; + changeStatusTo(Statuses.CONNECTING); + return doSync(); + + function doSync() { + // Use enque() to ensure only a single promise execution at a time. + return enque(doSync, function () { + // By returning the Promise returned by getLocalChangesForNode() a final catch() on the sync() method will also catch error occurring in entire sequence. + return getLocalChangesForNode_autoAckIfEmpty(node, function sendChangesToProvider(changes, remoteBaseRevision, partial, nodeModificationsOnAck) { + // Create a final Promise for the entire sync() operation that will resolve when provider calls onSuccess(). + // By creating finalPromise before calling protocolInstance.sync() it is possible for provider to call onError() immediately if it wants. + var finalSyncPromise = new Promise(function (resolve, reject) { + rejectConnectPromise = function (err) { + reject(err); + }; + Dexie.asap(function () { + try { + protocolInstance.sync(node.syncContext, url, options, remoteBaseRevision, node.appliedRemoteRevision, changes, partial, applyRemoteChanges, onChangesAccepted, function (continuation) { + resolve(continuation); + }, onError); + } catch (ex) { + onError(ex, Infinity); + } + + function onError(error, again) { + reject(error); + if (stillAlive()) { + if (!isNaN(again) && again < Infinity) { + setTimeout(function () { + if (stillAlive()) { + changeStatusTo(Statuses.SYNCING); + doSync(); + } + }, again); + changeStatusTo(Statuses.ERROR_WILL_RETRY, error); + if (connectedContinuation && connectedContinuation.disconnect) connectedContinuation.disconnect(); + connectedContinuation = null; + } else { + abortTheProvider(error); // Will fire ERROR on statusChanged event. + } + } + } + }); + }); + + return finalSyncPromise.then(function () { + // Resolve caller of db.syncable.connect() with undefined. Not with continuation! + }); + + function onChangesAccepted() { + Object.keys(nodeModificationsOnAck).forEach(function (keyPath) { + Dexie.setByKeyPath(node, keyPath, nodeModificationsOnAck[keyPath]); + }); + node.save(); + // We dont know if onSuccess() was called by provider yet. If it's already called, finalPromise.then() will execute immediately, + // otherwise it will execute when finalSyncPromise resolves. + finalSyncPromise.then(continueSendingChanges); + } + }); + }, dbAliveID); + } + + function abortTheProvider(error) { + activePeer.disconnect(Statuses.ERROR, error); + } + + function getBaseRevisionAndMaxClientRevision(node) { + /// + if (node.remoteBaseRevisions.length === 0) return { + // No remoteBaseRevisions have arrived yet. No limit on clientRevision and provide null as remoteBaseRevision: + maxClientRevision: Infinity, + remoteBaseRevision: null + }; + for (var i = node.remoteBaseRevisions.length - 1; i >= 0; --i) { + if (node.myRevision >= node.remoteBaseRevisions[i].local) { + // Found a remoteBaseRevision that fits node.myRevision. Return remoteBaseRevision and eventually a roof maxClientRevision pointing out where next remoteBaseRevision bases its changes on. + return { + maxClientRevision: i === node.remoteBaseRevisions.length - 1 ? Infinity : node.remoteBaseRevisions[i + 1].local, + remoteBaseRevision: node.remoteBaseRevisions[i].remote + }; + } + } + // There are at least one item in the list but the server hasnt yet become up-to-date with the 0 revision from client. + return { + maxClientRevision: node.remoteBaseRevisions[0].local, + remoteBaseRevision: null + }; + } + + function getLocalChangesForNode_autoAckIfEmpty(node, cb) { + return getLocalChangesForNode(node, function autoAck(changes, remoteBaseRevision, partial, nodeModificationsOnAck) { + if (changes.length === 0 && 'myRevision' in nodeModificationsOnAck && nodeModificationsOnAck.myRevision !== node.myRevision) { + Object.keys(nodeModificationsOnAck).forEach(function (keyPath) { + Dexie.setByKeyPath(node, keyPath, nodeModificationsOnAck[keyPath]); + }); + node.save(); + return getLocalChangesForNode(node, autoAck); + } else { + return cb(changes, remoteBaseRevision, partial, nodeModificationsOnAck); + } + }); + } + + function getLocalChangesForNode(node, cb) { + /// + /// Based on given node's current revision and state, this function makes sure to retrieve next chunk of changes + /// for that node. + /// + /// + /// Callback that will retrieve next chunk of changes and a boolean telling if it's a partial result or not. If truthy, result is partial and there are more changes to come. If falsy, these changes are the final result. + + if (node.myRevision >= 0) { + // Node is based on a revision in our local database and will just need to get the changes that has occurred since that revision. + var brmcr = getBaseRevisionAndMaxClientRevision(node); + return getChangesSinceRevision(node.myRevision, MAX_CHANGES_PER_CHUNK, brmcr.maxClientRevision, function (changes, partial, nodeModificationsOnAck) { + return cb(changes, brmcr.remoteBaseRevision, partial, nodeModificationsOnAck); + }); + } else { + // Node hasn't got anything from our local database yet. We will need to upload entire DB to the node in the form of CREATE changes. + // Check if we're in the middle of already doing that: + if (node.dbUploadState === null) { + // Initiatalize dbUploadState + var tablesToUpload = db.tables.filter(function (table) { + return table.schema.observable; + }).map(function (table) { + return table.name; + }); + if (tablesToUpload.length === 0) return Promise.resolve(cb([], null, false, {})); // There are no synched tables at all. + var dbUploadState = { + tablesToUpload: tablesToUpload, + currentTable: tablesToUpload.shift(), + currentKey: null + }; + return db._changes.orderBy('rev').last(function (lastChange) { + dbUploadState.localBaseRevision = lastChange && lastChange.rev || 0; + var collection = db.table(dbUploadState.currentTable).orderBy(':id'); + return getTableObjectsAsChanges(dbUploadState, [], collection); + }); + } else if (node.dbUploadState.currentKey) { + var collection = db.table(node.dbUploadState.currentTable).where(':id').above(node.dbUploadState.currentKey); + return getTableObjectsAsChanges(Dexie.deepClone(node.dbUploadState), [], collection); + } else { + var collection = db.table(dbUploadState.currentTable).orderBy(':id'); + return getTableObjectsAsChanges(Dexie.deepClone(node.dbUploadState), [], collection); + } + } + + function getTableObjectsAsChanges(state, changes, collection) { + /// + /// + /// + var limitReached = false; + return collection.until(function () { + if (changes.length === MAX_CHANGES_PER_CHUNK) { + limitReached = true; + return true; + } + }).each(function (item, cursor) { + changes.push({ + type: CREATE, + table: state.currentTable, + key: cursor.key, + obj: cursor.value + }); + state.currentKey = cursor.key; + }).then(function () { + if (limitReached) { + // Limit reached. Send partial result. + hasMoreToGive = true; + return cb(changes, null, true, { dbUploadState: state }); + } else { + // Done iterating this table. Check if there are more tables to go through: + if (state.tablesToUpload.length === 0) { + // Done iterating all tables + // Now append changes occurred during our dbUpload: + var brmcr = getBaseRevisionAndMaxClientRevision(node); + return getChangesSinceRevision(state.localBaseRevision, MAX_CHANGES_PER_CHUNK - changes.length, brmcr.maxClientRevision, function (additionalChanges, partial, nodeModificationsOnAck) { + changes = changes.concat(additionalChanges); + nodeModificationsOnAck.dbUploadState = null; + return cb(changes, brmcr.remoteBaseRevision, partial, nodeModificationsOnAck); + }); + } else { + // Not done iterating all tables. Continue on next table: + state.currentTable = state.tablesToUpload.shift(); + return getTableObjectsAsChanges(state, changes, db.table(state.currentTable).orderBy(':id')); + } + } + }); + } + + function getChangesSinceRevision(revision, maxChanges, maxRevision, cb) { + /// Callback that will retrieve next chunk of changes and a boolean telling if it's a partial result or not. If truthy, result is partial and there are more changes to come. If falsy, these changes are the final result. + var changeSet = {}; + var numChanges = 0; + var partial = false; + var ignoreSource = node.id; + var nextRevision = revision; + return db.transaction('r', db._changes, function () { + var query = maxRevision === Infinity ? db._changes.where('rev').above(revision) : db._changes.where('rev').between(revision, maxRevision, false, true); + query.until(function () { + if (numChanges === maxChanges) { + partial = true; + return true; + } + }).each(function (change) { + // Note the revision in nextRevision: + nextRevision = change.rev; + if (change.source === ignoreSource) return; + // Our _changes table contains more info than required (old objs, source etc). Just make sure to include the nescessary info: + var changeToSend = { + type: change.type, + table: change.table, + key: change.key + }; + if (change.type === CREATE) changeToSend.obj = change.obj;else if (change.type === UPDATE) changeToSend.mods = change.mods; + + var id = change.table + ":" + change.key; + var prevChange = changeSet[id]; + if (!prevChange) { + // This is the first change on this key. Add it unless it comes from the source that we are working against + changeSet[id] = changeToSend; + ++numChanges; + } else { + // Merge the oldchange with the new change + var nextChange = changeToSend; + var mergedChange = function () { + switch (prevChange.type) { + case CREATE: + switch (nextChange.type) { + case CREATE: + return nextChange; // Another CREATE replaces previous CREATE. + case UPDATE: + return combineCreateAndUpdate(prevChange, nextChange); // Apply nextChange.mods into prevChange.obj + case DELETE: + return nextChange; // Object created and then deleted. If it wasnt for that we MUST handle resent changes, we would skip entire change here. But what if the CREATE was sent earlier, and then CREATE/DELETE at later stage? It would become a ghost object in DB. Therefore, we MUST keep the delete change! If object doesnt exist, it wont harm! + } + break; + case UPDATE: + switch (nextChange.type) { + case CREATE: + return nextChange; // Another CREATE replaces previous update. + case UPDATE: + return combineUpdateAndUpdate(prevChange, nextChange); // Add the additional modifications to existing modification set. + case DELETE: + return nextChange; // Only send the delete change. What was updated earlier is no longer of interest. + } + break; + case DELETE: + switch (nextChange.type) { + case CREATE: + return nextChange; // A resurection occurred. Only create change is of interest. + case UPDATE: + return prevChange; // Nothing to do. We cannot update an object that doesnt exist. Leave the delete change there. + case DELETE: + return prevChange; // Still a delete change. Leave as is. + } + break; + } + }(); + changeSet[id] = mergedChange; + } + }); + }).then(function () { + var changes = Object.keys(changeSet).map(function (key) { + return changeSet[key]; + }); + hasMoreToGive = partial; + return cb(changes, partial, { myRevision: nextRevision }); + }); + } + } + + function applyRemoteChanges(remoteChanges, remoteRevision, partial, clear) { + return enque(applyRemoteChanges, function () { + if (!stillAlive()) return Promise.reject("Database not open"); + // FIXTHIS: Check what to do if clear() is true! + return (partial ? saveToUncommitedChanges(remoteChanges) : finallyCommitAllChanges(remoteChanges, remoteRevision)).catch(function (error) { + abortTheProvider(error); + return Promise.reject(error); + }); + }, dbAliveID); + + function saveToUncommitedChanges(changes) { + return db.transaction('rw', db._uncommittedChanges, function () { + changes.forEach(function (change) { + var changeToAdd = { + node: node.id, + type: change.type, + table: change.table, + key: change.key + }; + if (change.obj) changeToAdd.obj = change.obj; + if (change.mods) changeToAdd.mods = change.mods; + db._uncommittedChanges.add(changeToAdd); + }); + }).then(function () { + node.appliedRemoteRevision = remoteRevision; + node.save(); + }); + } + + function finallyCommitAllChanges(changes, remoteRevision) { + //alert("finallyCommitAllChanges() will now start its job."); + //var tick = Date.now(); + + // 1. Open a write transaction on all tables in DB + return db.transaction('rw', db.tables.filter(function (table) { + return table.name === '_changes' || table.name === '_uncommittedChanges' || table.schema.observable; + }), function () { + var trans = Dexie.currentTransaction; + var localRevisionBeforeChanges = 0; + db._changes.orderBy('rev').last(function (lastChange) { + // Store what revision we were at before committing the changes + localRevisionBeforeChanges = lastChange && lastChange.rev || 0; + }).then(function () { + // Specify the source. Important for the change consumer to ignore changes originated from self! + trans.source = node.id; + // 2. Apply uncommitted changes and delete each uncommitted change + return db._uncommittedChanges.where('node').equals(node.id).toArray(); + }).then(function (uncommittedChanges) { + return applyChanges(uncommittedChanges, 0); + }).then(function () { + return db._uncommittedChanges.where('node').equals(node.id).delete(); + }).then(function () { + // 3. Apply last chunk of changes + return applyChanges(changes, 0); + }).then(function () { + // Get what revision we are at now: + return db._changes.orderBy('rev').last(); + }).then(function (lastChange) { + var currentLocalRevision = lastChange && lastChange.rev || 0; + // 4. Update node states (appliedRemoteRevision, remoteBaseRevisions and eventually myRevision) + node.appliedRemoteRevision = remoteRevision; + node.remoteBaseRevisions.push({ remote: remoteRevision, local: currentLocalRevision }); + if (node.myRevision === localRevisionBeforeChanges) { + // If server was up-to-date before we added new changes from the server, update myRevision to last change + // because server is still up-to-date! This is also important in order to prohibit getLocalChangesForNode() from + // ever sending an empty change list to server, which would otherwise be done every second time it would send changes. + node.myRevision = currentLocalRevision; + } + // Garbage collect remoteBaseRevisions not in use anymore: + if (node.remoteBaseRevisions.length > 1) { + for (var i = node.remoteBaseRevisions.length - 1; i > 0; --i) { + if (node.myRevision >= node.remoteBaseRevisions[i].local) { + node.remoteBaseRevisions.splice(0, i); + break; + } + } + } + node.save(); // We are not including _syncNodes in transaction, so this save() call will execute in its own transaction. + //var tock = Date.now(); + //alert("finallyCommitAllChanges() has done its job. " + changes.length + " changes applied in " + ((tock - tick) / 1000) + "seconds"); + }); + + function applyChanges(changes, offset) { + /// + /// + var lastChangeType = 0; + var lastCreatePromise = null; + if (offset >= changes.length) return Promise.resolve(null); + var change = changes[offset]; + var table = trans.tables[change.table]; + while (change && change.type === CREATE) { + // Optimize CREATE changes because on initial sync with server, the entire DB will be downloaded in forms of CREATE changes. + // Instead of waiting for each change to resolve, do all CREATE changes in bulks until another type of change is stepped upon. + // This case is the only case that allows i to increment and the for-loop to continue since it does not return anything. + var specifyKey = !table.schema.primKey.keyPath; + lastCreatePromise = function (change, table, specifyKey) { + return (specifyKey ? table.add(change.obj, change.key) : table.add(change.obj)).catch("ConstraintError", function (e) { + return specifyKey ? table.put(change.obj, change.key) : table.put(change.obj); + }); + }(change, table, specifyKey); + change = changes[++offset]; + if (change) table = trans.tables[change.table]; + } + + if (lastCreatePromise) { + // We did some CREATE changes but now stumbled upon another type of change. + // Let's wait for the last CREATE change to resolve and then call applyChanges again at current position. Next time, lastCreatePromise will be null and a case below will happen. + return lastCreatePromise.then(function () { + return offset < changes.length ? applyChanges(changes, offset) : null; + }); + } + + if (change) { + if (change.type === UPDATE) { + return table.update(change.key, change.mods).then(function () { + // Wait for update to resolve before taking next change. Why? Because it will lock transaction anyway since we are listening to CRUD events here. + return applyChanges(changes, offset + 1); + }); + } + + if (change.type === DELETE) { + return table.delete(change.key).then(function () { + // Wait for delete to resolve before taking next change. Why? Because it will lock transaction anyway since we are listening to CRUD events here. + return applyChanges(changes, offset + 1); + }); + } + } + + return Promise.resolve(null); // Will return null or a Promise and make the entire applyChanges promise finally resolve. + } + }); + } + } + + // + // + // Continuation Patterns Follows + // + // + + function continueSendingChanges(continuation) { + if (!stillAlive()) { + // Database was closed. + if (continuation.disconnect) continuation.disconnect(); + return; + } + + connectedContinuation = continuation; + activePeer.on('disconnect', function () { + if (connectedContinuation) { + if (connectedContinuation.react) { + try { + // react pattern must provide a disconnect function. + connectedContinuation.disconnect(); + } catch (e) {} + } + connectedContinuation = null; // Stop poll() pattern from polling again and abortTheProvider() from being called twice. + } + }); + + if (continuation.react) { + continueUsingReactPattern(continuation); + } else { + continueUsingPollPattern(continuation); + } + } + + // React Pattern (eager) + function continueUsingReactPattern(continuation) { + var changesWaiting, // Boolean + isWaitingForServer; // Boolean + + function onChanges() { + if (connectedContinuation) { + changeStatusTo(Statuses.SYNCING); + if (isWaitingForServer) changesWaiting = true;else { + reactToChanges(); + } + } + } + + db.on('changes', onChanges); + + // Override disconnect() to also unsubscribe to onChanges. + activePeer.on('disconnect', function () { + db.on.changes.unsubscribe(onChanges); + }); + + function reactToChanges() { + if (!connectedContinuation) return; + changesWaiting = false; + isWaitingForServer = true; + getLocalChangesForNode_autoAckIfEmpty(node, function (changes, remoteBaseRevision, partial, nodeModificationsOnAck) { + if (!connectedContinuation) return; + if (changes.length > 0) { + continuation.react(changes, remoteBaseRevision, partial, function onChangesAccepted() { + Object.keys(nodeModificationsOnAck).forEach(function (keyPath) { + Dexie.setByKeyPath(node, keyPath, nodeModificationsOnAck[keyPath]); + }); + node.save(); + // More changes may be waiting: + reactToChanges(); + }); + } else { + isWaitingForServer = false; + if (changesWaiting) { + // A change jumped in between the time-spot of quering _changes and getting called back with zero changes. + // This is an expreemely rare scenario, and eventually impossible. But need to be here because it could happen in theory. + reactToChanges(); + } else { + changeStatusTo(Statuses.ONLINE); + } + } + }).catch(abortTheProvider); + } + + reactToChanges(); + } + + // Poll Pattern + function continueUsingPollPattern() { + + function syncAgain() { + getLocalChangesForNode_autoAckIfEmpty(node, function (changes, remoteBaseRevision, partial, nodeModificationsOnAck) { + + protocolInstance.sync(node.syncContext, url, options, remoteBaseRevision, node.appliedRemoteRevision, changes, partial, applyRemoteChanges, onChangesAccepted, onSuccess, onError); + + function onChangesAccepted() { + Object.keys(nodeModificationsOnAck).forEach(function (keyPath) { + Dexie.setByKeyPath(node, keyPath, nodeModificationsOnAck[keyPath]); + }); + node.save(); + } + + function onSuccess(continuation) { + if (!connectedContinuation) { + // Got disconnected before succeeding. Quit. + return; + } + connectedContinuation = continuation; + if (partial) { + // We only sent partial changes. Need to do another round asap. + syncAgain(); + } else { + // We've sent all changes now (in sync!) + if (!isNaN(continuation.again) && continuation.again < Infinity) { + // Provider wants to keep polling. Set Status to ONLINE. + changeStatusTo(Statuses.ONLINE); + setTimeout(function () { + if (connectedContinuation) { + changeStatusTo(Statuses.SYNCING); + syncAgain(); + } + }, continuation.again); + } else { + // Provider seems finished polling. Since we are never going to poll again, + // disconnect provider and set status to OFFLINE until another call to db.syncable.connect(). + activePeer.disconnect(Statuses.OFFLINE); + } + } + } + + function onError(error, again) { + if (!isNaN(again) && again < Infinity) { + if (connectedContinuation) { + setTimeout(function () { + if (connectedContinuation) { + changeStatusTo(Statuses.SYNCING); + syncAgain(); + } + }, again); + changeStatusTo(Statuses.ERROR_WILL_RETRY); + } // else status is already changed since we got disconnected. + } else { + abortTheProvider(error); // Will fire ERROR on onStatusChanged. + } + } + }).catch(abortTheProvider); + } + + if (hasMoreToGive) { + syncAgain(); + } else if (connectedContinuation && !isNaN(connectedContinuation.again) && connectedContinuation.again < Infinity) { + changeStatusTo(Statuses.ONLINE); + setTimeout(function () { + if (connectedContinuation) { + changeStatusTo(Statuses.SYNCING); + syncAgain(); + } + }, connectedContinuation.again); + } + } + } + } + + db.close = override(db.close, function (origClose) { + return function () { + activePeers.forEach(function (peer) { + peer.disconnect(); + }); + return origClose.apply(this, arguments); + }; + }); + + var syncNodeSaveQueContexts = {}; + db.observable.SyncNode.prototype.save = function () { + var self = this; + return db.transaction('rw?', db._syncNodes, function () { + db._syncNodes.put(self); + }); + }; + + function enque(context, fn, instanceID) { + function _enque() { + if (!context.ongoingOperation) { + context.ongoingOperation = Dexie.ignoreTransaction(function () { + return Dexie.vip(function () { + return fn(); + }); + }).then(function (res) { + delete context.ongoingOperation; + return res; + }); + } else { + context.ongoingOperation = context.ongoingOperation.then(function () { + return enque(context, fn, instanceID); + }); + } + return context.ongoingOperation; + } + + if (!instanceID) { + // Caller wants to enque it until database becomes open. + if (db.isOpen()) { + return _enque(); + } else { + return Promise.reject(new Error("Database was closed")); + } + } else if (db._localSyncNode && instanceID === db._localSyncNode.id) { + // DB is already open but queuer doesnt want it to be queued if database has been closed (request bound to current instance of DB) + return _enque(); + } else { + return Promise.reject(new Error("Database was closed")); + } + } + + function combineCreateAndUpdate(prevChange, nextChange) { + var clonedChange = Dexie.deepClone(prevChange); // Clone object before modifying since the earlier change in db.changes[] would otherwise be altered. + Object.keys(nextChange.mods).forEach(function (keyPath) { + setByKeyPath(clonedChange.obj, keyPath, nextChange.mods[keyPath]); + }); + return clonedChange; + } + + function combineUpdateAndUpdate(prevChange, nextChange) { + var clonedChange = Dexie.deepClone(prevChange); // Clone object before modifying since the earlier change in db.changes[] would otherwise be altered. + Object.keys(nextChange.mods).forEach(function (keyPath) { + // If prev-change was changing a parent path of this keyPath, we must update the parent path rather than adding this keyPath + var hadParentPath = false; + Object.keys(prevChange.mods).filter(function (parentPath) { + return keyPath.indexOf(parentPath + '.') === 0; + }).forEach(function (parentPath) { + setByKeyPath(clonedChange[parentPath], keyPath.substr(parentPath.length + 1), nextChange.mods[keyPath]); + hadParentPath = true; + }); + if (!hadParentPath) { + // Add or replace this keyPath and its new value + clonedChange.mods[keyPath] = nextChange.mods[keyPath]; + } + // In case prevChange contained sub-paths to the new keyPath, we must make sure that those sub-paths are removed since + // we must mimic what would happen if applying the two changes after each other: + Object.keys(prevChange.mods).filter(function (subPath) { + return subPath.indexOf(keyPath + '.') === 0; + }).forEach(function (subPath) { + delete clonedChange[subPath]; + }); + }); + return clonedChange; + } + }; + + Syncable.Statuses = { + ERROR: -1, // An irrepairable error occurred and the sync provider is dead. + OFFLINE: 0, // The sync provider hasnt yet become online, or it has been disconnected. + CONNECTING: 1, // Trying to connect to server + ONLINE: 2, // Connected to server and currently in sync with server + SYNCING: 3, // Syncing with server. For poll pattern, this is every poll call. For react pattern, this is when local changes are being sent to server. + ERROR_WILL_RETRY: 4 // An error occured such as net down but the sync provider will retry to connect. + }; + + Syncable.StatusTexts = { + "-1": "ERROR", + "0": "OFFLINE", + "1": "CONNECTING", + "2": "ONLINE", + "3": "SYNCING", + "4": "ERROR_WILL_RETRY" + }; + + Syncable.registeredProtocols = {}; // Map when key is the provider name. + + Syncable.registerSyncProtocol = function (name, protocolInstance) { + /// + /// Register a syncronization protocol that can syncronize databases with remote servers. + /// + /// Provider name + /// Implementation of ISyncProtocol + Syncable.registeredProtocols[name] = protocolInstance; + }; + + // Register addon in Dexie: + Dexie.Syncable = Syncable; + Dexie.addons.push(Syncable); + + return Syncable; + +})); +//# sourceMappingURL=dexie-syncable.js.map \ No newline at end of file diff --git a/addons/Dexie.Syncable/dist/dexie-syncable.js.map b/addons/Dexie.Syncable/dist/dexie-syncable.js.map new file mode 100644 index 000000000..a02f51238 --- /dev/null +++ b/addons/Dexie.Syncable/dist/dexie-syncable.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dexie-syncable.js","sources":["../C:/repos/dexie-release/addons/Dexie.Syncable/tools/tmp/src/Dexie.Syncable.js"],"sourcesContent":["/// \n/// \n/// \n/**\r\n * Dexie.Syncable.js\r\n * ===================\r\n * Dexie addon for syncing indexedDB with remote endpoints.\r\n *\r\n * version: {version} Alpha, {date}\r\n *\r\n * Disclaimber: This addon is in alpha status meaning that\r\n * its API and behavior may change.\r\n *\r\n */\n\nimport Dexie from \"dexie\";\n// Depend on 'dexie-observable'\n// To support both ES6,AMD,CJS and UMD (plain script), we just import it and then access it as \"Dexie.Observable\".\n// That way, our plugin works in all UMD cases.\n// If target platform would only be module based (ES6/AMD/CJS), we could have done 'import Observable from \"dexie-observable\"'.\nimport \"dexie-observable\";\n\nvar override = Dexie.override,\n Promise = Dexie.Promise,\n setByKeyPath = Dexie.setByKeyPath,\n Observable = Dexie.Observable;\n\nexport default function Syncable(db) {\n /// \n\n var activePeers = [];\n\n // Change Types\n var CREATE = 1,\n UPDATE = 2,\n DELETE = 3;\n\n // Statuses\n var Statuses = Syncable.Statuses;\n\n var MAX_CHANGES_PER_CHUNK = 1000;\n\n db.on('message', function (msg) {\n // Message from other local node arrives...\n Dexie.vip(function () {\n if (msg.type === 'connect') {\n // We are master node and another non-master node wants us to do the connect.\n db.syncable.connect(msg.protocolName, msg.url, msg.options).then(msg.resolve, msg.reject);\n } else if (msg.type === 'disconnect') {\n db.syncable.disconnect(msg.url).then(msg.resolve, msg.reject);\n } else if (msg.type === 'syncStatusChanged') {\n // We are client and a master node informs us about syncStatus change.\n // Lookup the connectedProvider and call its event\n db.syncable.on.statusChanged.fire(msg.newStatus, msg.url);\n }\n });\n });\n\n db.on('cleanup', function (weBecameMaster) {\n // A cleanup (done in Dexie.Observable) may result in that a master node is removed and we become master.\n if (weBecameMaster) {\n // We took over the master role in Observable's cleanup method\n db._syncNodes.where('type').equals('remote').and(function (node) {\n return node.status !== Statuses.OFFLINE && node.status !== Statuses.ERROR;\n }).each(function (connectedRemoteNode) {\n // There are connected remote nodes that we must take over\n // Since we may be in the on(ready) event, we must get VIPed to continue\n Dexie.ignoreTransaction(function () {\n Dexie.vip(function () {\n db.syncable.connect(connectedRemoteNode.syncProtocol, connectedRemoteNode.url, connectedRemoteNode.syncOptions);\n });\n });\n });\n }\n });\n\n db.on('ready', function onReady() {\n // Again, in onReady: If we ARE master, make sure to connect to remote servers that is in a connected state.\n if (db._localSyncNode && db._localSyncNode.isMaster) {\n // Make sure to connect to remote servers that is in a connected state (NOT OFFLINE or ERROR!)\n return db._syncNodes.where('type').equals('remote').and(function (node) {\n return node.status !== Statuses.OFFLINE && node.status !== Statuses.ERROR;\n }).toArray(function (connectedRemoteNodes) {\n // There are connected remote nodes that we must take over\n if (connectedRemoteNodes.length > 0) {\n return Promise.all(connectedRemoteNodes.map(function (node) {\n return db.syncable.connect(node.syncProtocol, node.url, node.syncOptions).catch(function (err) {\n return undefined; // If a node fails to connect, don't make db.open() reject. Accept it!\n });\n }));\n }\n });\n }\n }, true); // True means the ready event will survive a db reopen - db.close()/db.open()\n\n db.syncable = {};\n\n db.syncable.getStatus = function (url, cb) {\n if (db.isOpen()) {\n return Dexie.vip(function () {\n return db._syncNodes.where('url').equals(url).first(function (node) {\n return node ? node.status : Statuses.OFFLINE;\n });\n }).then(cb);\n } else {\n return Promise.resolve(Syncable.Statuses.OFFLINE).then(cb);\n }\n };\n\n db.syncable.list = function () {\n return db._syncNodes.where('type').equals('remote').toArray(function (a) {\n return a.map(function (node) {\n return node.url;\n });\n });\n };\n\n db.syncable.on = Dexie.events(db, { statusChanged: \"asap\" });\n\n db.syncable.disconnect = function (url) {\n if (db._localSyncNode && db._localSyncNode.isMaster) {\n activePeers.filter(function (peer) {\n return peer.url === url;\n }).forEach(function (peer) {\n peer.disconnect(Statuses.OFFLINE);\n });\n } else {\n db._syncNodes.where('isMaster').above(0).first(function (masterNode) {\n db.sendMessage('disconnect', { url: url }, masterNode.id, { wantReply: true });\n });\n }\n\n return db._syncNodes.where(\"url\").equals(url).modify(function (node) {\n node.status = Statuses.OFFLINE;\n });\n };\n\n db.syncable.connect = function (protocolName, url, options) {\n options = options || {}; // Make sure options is always an object because 1) Provider expects it to be. 2) We'll be persisting it and you cannot persist undefined.\n var protocolInstance = Syncable.registeredProtocols[protocolName];\n\n if (protocolInstance) {\n if (db.isOpen() && db._localSyncNode) {\n // Database is open\n if (db._localSyncNode.isMaster) {\n // We are master node\n return connect(protocolInstance, protocolName, url, options, db._localSyncNode.id);\n } else {\n // We are not master node\n // Request master node to do the connect:\n db.table('_syncNodes').where('isMaster').above(0).first(function (masterNode) {\n // There will always be a master node. In theory we may self have become master node when we come here. But that's ok. We'll request ourselves.\n return db.sendMessage('connect', { protocolName: protocolName, url: url, options: options }, masterNode.id, { wantReply: true });\n });\n return Promise.resolve();\n }\n } else {\n // Database not yet open\n // Wait for it to open\n return new Promise(function (resolve, reject) {\n db.on(\"ready\", function syncWhenReady() {\n return Dexie.vip(function () {\n return db.syncable.connect(protocolName, url, options).then(resolve).catch(function (err) {\n // Reject the promise returned to the caller of db.syncable.connect():\n reject(err);\n // but resolve the promise that db.on(\"ready\") waits for, because database should succeed to open even if the connect operation fails!\n });\n });\n });\n });\n }\n } else {\n throw new Error(\"ISyncProtocol '\" + protocolName + \"' is not registered in Dexie.Syncable.registerSyncProtocol()\");\n return new Promise(); // For code completion\n }\n };\n\n db.syncable.delete = function (url) {\n // Notice: Caller should call db.syncable.disconnect(url) and wait for it to finish before calling db.syncable.delete(url)\n // Surround with a readwrite-transaction\n return db.transaction('rw', db._syncNodes, db._changes, db._uncommittedChanges, function () {\n // Find the node\n db._syncNodes.where(\"url\").equals(url).toArray(function (nodes) {\n // If it's found (or even several found, as detected by @martindiphoorn),\n // let's delete it (or them) and cleanup _changes and _uncommittedChanges\n // accordingly.\n if (nodes.length > 0) {\n var nodeIDs = nodes.map(function (node) {\n return node.id;\n });\n // The following 'return' statement is not needed right now, but I leave it\n // there because if we would like to add a 'then()' statement to the main ,\n // operation above ( db._syncNodes.where(\"url\").equals(url).toArray(...) ) ,\n // this return statement will asure that the whole chain is waited for\n // before entering the then() callback.\n return db._syncNodes.where('id').anyOf(nodeIDs).delete().then(function () {\n // When theese nodes are gone, let's clear the _changes table\n // from all revisions older than the oldest node.\n // Delete all changes older than revision of oldest node:\n Observable.deleteOldChanges();\n // Also don't forget to delete all uncommittedChanges for the deleted node:\n return db._uncommittedChanges.where('node').anyOf(nodeIDs).delete();\n });\n }\n });\n });\n };\n\n db.syncable.unsyncedChanges = function (url) {\n return db._syncNodes.where(\"url\").equals(url).first(function (node) {\n return db._changes.where('rev').above(node.myRevision).toArray();\n });\n };\n\n function connect(protocolInstance, protocolName, url, options, dbAliveID) {\n /// \n var existingPeer = activePeers.filter(function (peer) {\n return peer.url === url;\n });\n if (existingPeer.length > 0) {\n // Never create multiple syncNodes with same protocolName and url. Instead, let the next call to connect() return the same promise that\n // have already been started and eventually also resolved. If promise has already resolved (node connected), calling existing promise.then() will give a callback directly.\n return existingPeer[0].connectPromise;\n }\n\n var connectPromise = getOrCreateSyncNode(options).then(function (node) {\n return connectProtocol(node);\n });\n\n var rejectConnectPromise = null;\n var disconnected = false;\n var hasMoreToGive = true;\n var activePeer = {\n url: url,\n status: Statuses.OFFLINE,\n connectPromise: connectPromise,\n on: Dexie.events(null, \"disconnect\"),\n disconnect: function (newStatus, error) {\n if (!disconnected) {\n activePeer.on.disconnect.fire(newStatus, error);\n var pos = activePeers.indexOf(activePeer);\n if (pos >= 0) activePeers.splice(pos, 1);\n if (error && rejectConnectPromise) rejectConnectPromise(error);\n }\n disconnected = true;\n }\n };\n activePeers.push(activePeer);\n\n return connectPromise;\n\n function stillAlive() {\n // A better method than doing db.isOpen() because the same db instance may have been reopened, but then this sync call should be dead\n // because the new instance should be considered a fresh instance and will have another local node.\n return db._localSyncNode && db._localSyncNode.id === dbAliveID;\n }\n\n function getOrCreateSyncNode(options) {\n return db.transaction('rw', db._syncNodes, function () {\n if (!url) throw new Error(\"Url cannot be empty\");\n // Returning a promise from transaction scope will make the transaction promise resolve with the value of that promise.\n\n return db._syncNodes.where(\"url\").equalsIgnoreCase(url).first(function (node) {\n //\n // PersistedContext : IPersistedContext\n //\n function PersistedContext(nodeID, otherProps) {\n this.nodeID = nodeID;\n if (otherProps) Dexie.extend(this, otherProps);\n }\n\n PersistedContext.prototype.save = function () {\n // Store this instance in the syncContext property of the node it belongs to.\n return Dexie.vip(function () {\n return node.save();\n });\n };\n\n if (node) {\n // Node already there. Make syncContext become an instance of PersistedContext:\n node.syncContext = new PersistedContext(node.id, node.syncContext);\n node.syncProtocol = protocolName; // In case it was changed (would be very strange but...) could happen...\n db._syncNodes.put(node);\n } else {\n // Create new node and sync everything\n node = new db.observable.SyncNode();\n node.myRevision = -1;\n node.appliedRemoteRevision = null;\n node.remoteBaseRevisions = [];\n node.type = \"remote\";\n node.syncProtocol = protocolName;\n node.url = url;\n node.syncOptions = options;\n node.lastHeartBeat = Date.now();\n node.dbUploadState = null;\n Promise.resolve(function () {\n // If options.initialUpload is explicitely false, set myRevision to currentRevision.\n if (options.initialUpload === false) return db._changes.lastKey(function (currentRevision) {\n node.myRevision = currentRevision;\n });\n }).then(function () {\n db._syncNodes.add(node).then(function (nodeId) {\n node.syncContext = new PersistedContext(nodeId); // Update syncContext in db with correct nodeId.\n db._syncNodes.put(node);\n });\n });\n }\n\n return node; // returning node will make the db.transaction()-promise resolve with this value.\n });\n });\n }\n\n function connectProtocol(node) {\n /// \n\n function changeStatusTo(newStatus) {\n if (node.status !== newStatus) {\n node.status = newStatus;\n node.save();\n db.syncable.on.statusChanged.fire(newStatus, url);\n // Also broadcast message to other nodes about the status\n db.broadcastMessage(\"syncStatusChanged\", { newStatus: newStatus, url: url }, false);\n }\n }\n\n activePeer.on('disconnect', function (newStatus) {\n if (!isNaN(newStatus)) changeStatusTo(newStatus);\n });\n\n var connectedContinuation;\n changeStatusTo(Statuses.CONNECTING);\n return doSync();\n\n function doSync() {\n // Use enque() to ensure only a single promise execution at a time.\n return enque(doSync, function () {\n // By returning the Promise returned by getLocalChangesForNode() a final catch() on the sync() method will also catch error occurring in entire sequence.\n return getLocalChangesForNode_autoAckIfEmpty(node, function sendChangesToProvider(changes, remoteBaseRevision, partial, nodeModificationsOnAck) {\n // Create a final Promise for the entire sync() operation that will resolve when provider calls onSuccess().\n // By creating finalPromise before calling protocolInstance.sync() it is possible for provider to call onError() immediately if it wants.\n var finalSyncPromise = new Promise(function (resolve, reject) {\n rejectConnectPromise = function (err) {\n reject(err);\n };\n Dexie.asap(function () {\n try {\n protocolInstance.sync(node.syncContext, url, options, remoteBaseRevision, node.appliedRemoteRevision, changes, partial, applyRemoteChanges, onChangesAccepted, function (continuation) {\n resolve(continuation);\n }, onError);\n } catch (ex) {\n onError(ex, Infinity);\n }\n\n function onError(error, again) {\n reject(error);\n if (stillAlive()) {\n if (!isNaN(again) && again < Infinity) {\n setTimeout(function () {\n if (stillAlive()) {\n changeStatusTo(Statuses.SYNCING);\n doSync();\n }\n }, again);\n changeStatusTo(Statuses.ERROR_WILL_RETRY, error);\n if (connectedContinuation && connectedContinuation.disconnect) connectedContinuation.disconnect();\n connectedContinuation = null;\n } else {\n abortTheProvider(error); // Will fire ERROR on statusChanged event.\n }\n }\n }\n });\n });\n\n return finalSyncPromise.then(function () {\n // Resolve caller of db.syncable.connect() with undefined. Not with continuation!\n });\n\n function onChangesAccepted() {\n Object.keys(nodeModificationsOnAck).forEach(function (keyPath) {\n Dexie.setByKeyPath(node, keyPath, nodeModificationsOnAck[keyPath]);\n });\n node.save();\n // We dont know if onSuccess() was called by provider yet. If it's already called, finalPromise.then() will execute immediately,\n // otherwise it will execute when finalSyncPromise resolves.\n finalSyncPromise.then(continueSendingChanges);\n }\n });\n }, dbAliveID);\n }\n\n function abortTheProvider(error) {\n activePeer.disconnect(Statuses.ERROR, error);\n }\n\n function getBaseRevisionAndMaxClientRevision(node) {\n /// \n if (node.remoteBaseRevisions.length === 0) return {\n // No remoteBaseRevisions have arrived yet. No limit on clientRevision and provide null as remoteBaseRevision:\n maxClientRevision: Infinity,\n remoteBaseRevision: null\n };\n for (var i = node.remoteBaseRevisions.length - 1; i >= 0; --i) {\n if (node.myRevision >= node.remoteBaseRevisions[i].local) {\n // Found a remoteBaseRevision that fits node.myRevision. Return remoteBaseRevision and eventually a roof maxClientRevision pointing out where next remoteBaseRevision bases its changes on.\n return {\n maxClientRevision: i === node.remoteBaseRevisions.length - 1 ? Infinity : node.remoteBaseRevisions[i + 1].local,\n remoteBaseRevision: node.remoteBaseRevisions[i].remote\n };\n }\n }\n // There are at least one item in the list but the server hasnt yet become up-to-date with the 0 revision from client.\n return {\n maxClientRevision: node.remoteBaseRevisions[0].local,\n remoteBaseRevision: null\n };\n }\n\n function getLocalChangesForNode_autoAckIfEmpty(node, cb) {\n return getLocalChangesForNode(node, function autoAck(changes, remoteBaseRevision, partial, nodeModificationsOnAck) {\n if (changes.length === 0 && 'myRevision' in nodeModificationsOnAck && nodeModificationsOnAck.myRevision !== node.myRevision) {\n Object.keys(nodeModificationsOnAck).forEach(function (keyPath) {\n Dexie.setByKeyPath(node, keyPath, nodeModificationsOnAck[keyPath]);\n });\n node.save();\n return getLocalChangesForNode(node, autoAck);\n } else {\n return cb(changes, remoteBaseRevision, partial, nodeModificationsOnAck);\n }\n });\n }\n\n function getLocalChangesForNode(node, cb) {\n /// \n /// Based on given node's current revision and state, this function makes sure to retrieve next chunk of changes\n /// for that node.\n /// \n /// \n /// Callback that will retrieve next chunk of changes and a boolean telling if it's a partial result or not. If truthy, result is partial and there are more changes to come. If falsy, these changes are the final result.\n\n if (node.myRevision >= 0) {\n // Node is based on a revision in our local database and will just need to get the changes that has occurred since that revision.\n var brmcr = getBaseRevisionAndMaxClientRevision(node);\n return getChangesSinceRevision(node.myRevision, MAX_CHANGES_PER_CHUNK, brmcr.maxClientRevision, function (changes, partial, nodeModificationsOnAck) {\n return cb(changes, brmcr.remoteBaseRevision, partial, nodeModificationsOnAck);\n });\n } else {\n // Node hasn't got anything from our local database yet. We will need to upload entire DB to the node in the form of CREATE changes.\n // Check if we're in the middle of already doing that:\n if (node.dbUploadState === null) {\n // Initiatalize dbUploadState\n var tablesToUpload = db.tables.filter(function (table) {\n return table.schema.observable;\n }).map(function (table) {\n return table.name;\n });\n if (tablesToUpload.length === 0) return Promise.resolve(cb([], null, false, {})); // There are no synched tables at all.\n var dbUploadState = {\n tablesToUpload: tablesToUpload,\n currentTable: tablesToUpload.shift(),\n currentKey: null\n };\n return db._changes.orderBy('rev').last(function (lastChange) {\n dbUploadState.localBaseRevision = lastChange && lastChange.rev || 0;\n var collection = db.table(dbUploadState.currentTable).orderBy(':id');\n return getTableObjectsAsChanges(dbUploadState, [], collection);\n });\n } else if (node.dbUploadState.currentKey) {\n var collection = db.table(node.dbUploadState.currentTable).where(':id').above(node.dbUploadState.currentKey);\n return getTableObjectsAsChanges(Dexie.deepClone(node.dbUploadState), [], collection);\n } else {\n var collection = db.table(dbUploadState.currentTable).orderBy(':id');\n return getTableObjectsAsChanges(Dexie.deepClone(node.dbUploadState), [], collection);\n }\n }\n\n function getTableObjectsAsChanges(state, changes, collection) {\n /// \n /// \n /// \n var limitReached = false;\n return collection.until(function () {\n if (changes.length === MAX_CHANGES_PER_CHUNK) {\n limitReached = true;\n return true;\n }\n }).each(function (item, cursor) {\n changes.push({\n type: CREATE,\n table: state.currentTable,\n key: cursor.key,\n obj: cursor.value\n });\n state.currentKey = cursor.key;\n }).then(function () {\n if (limitReached) {\n // Limit reached. Send partial result.\n hasMoreToGive = true;\n return cb(changes, null, true, { dbUploadState: state });\n } else {\n // Done iterating this table. Check if there are more tables to go through:\n if (state.tablesToUpload.length === 0) {\n // Done iterating all tables\n // Now append changes occurred during our dbUpload:\n var brmcr = getBaseRevisionAndMaxClientRevision(node);\n return getChangesSinceRevision(state.localBaseRevision, MAX_CHANGES_PER_CHUNK - changes.length, brmcr.maxClientRevision, function (additionalChanges, partial, nodeModificationsOnAck) {\n changes = changes.concat(additionalChanges);\n nodeModificationsOnAck.dbUploadState = null;\n return cb(changes, brmcr.remoteBaseRevision, partial, nodeModificationsOnAck);\n });\n } else {\n // Not done iterating all tables. Continue on next table:\n state.currentTable = state.tablesToUpload.shift();\n return getTableObjectsAsChanges(state, changes, db.table(state.currentTable).orderBy(':id'));\n }\n }\n });\n }\n\n function getChangesSinceRevision(revision, maxChanges, maxRevision, cb) {\n /// Callback that will retrieve next chunk of changes and a boolean telling if it's a partial result or not. If truthy, result is partial and there are more changes to come. If falsy, these changes are the final result.\n var changeSet = {};\n var numChanges = 0;\n var partial = false;\n var ignoreSource = node.id;\n var nextRevision = revision;\n return db.transaction('r', db._changes, function () {\n var query = maxRevision === Infinity ? db._changes.where('rev').above(revision) : db._changes.where('rev').between(revision, maxRevision, false, true);\n query.until(function () {\n if (numChanges === maxChanges) {\n partial = true;\n return true;\n }\n }).each(function (change) {\n // Note the revision in nextRevision:\n nextRevision = change.rev;\n if (change.source === ignoreSource) return;\n // Our _changes table contains more info than required (old objs, source etc). Just make sure to include the nescessary info:\n var changeToSend = {\n type: change.type,\n table: change.table,\n key: change.key\n };\n if (change.type === CREATE) changeToSend.obj = change.obj;else if (change.type === UPDATE) changeToSend.mods = change.mods;\n\n var id = change.table + \":\" + change.key;\n var prevChange = changeSet[id];\n if (!prevChange) {\n // This is the first change on this key. Add it unless it comes from the source that we are working against\n changeSet[id] = changeToSend;\n ++numChanges;\n } else {\n // Merge the oldchange with the new change\n var nextChange = changeToSend;\n var mergedChange = function () {\n switch (prevChange.type) {\n case CREATE:\n switch (nextChange.type) {\n case CREATE:\n return nextChange; // Another CREATE replaces previous CREATE.\n case UPDATE:\n return combineCreateAndUpdate(prevChange, nextChange); // Apply nextChange.mods into prevChange.obj\n case DELETE:\n return nextChange; // Object created and then deleted. If it wasnt for that we MUST handle resent changes, we would skip entire change here. But what if the CREATE was sent earlier, and then CREATE/DELETE at later stage? It would become a ghost object in DB. Therefore, we MUST keep the delete change! If object doesnt exist, it wont harm!\n }\n break;\n case UPDATE:\n switch (nextChange.type) {\n case CREATE:\n return nextChange; // Another CREATE replaces previous update.\n case UPDATE:\n return combineUpdateAndUpdate(prevChange, nextChange); // Add the additional modifications to existing modification set.\n case DELETE:\n return nextChange; // Only send the delete change. What was updated earlier is no longer of interest.\n }\n break;\n case DELETE:\n switch (nextChange.type) {\n case CREATE:\n return nextChange; // A resurection occurred. Only create change is of interest.\n case UPDATE:\n return prevChange; // Nothing to do. We cannot update an object that doesnt exist. Leave the delete change there.\n case DELETE:\n return prevChange; // Still a delete change. Leave as is.\n }\n break;\n }\n }();\n changeSet[id] = mergedChange;\n }\n });\n }).then(function () {\n var changes = Object.keys(changeSet).map(function (key) {\n return changeSet[key];\n });\n hasMoreToGive = partial;\n return cb(changes, partial, { myRevision: nextRevision });\n });\n }\n }\n\n function applyRemoteChanges(remoteChanges, remoteRevision, partial, clear) {\n return enque(applyRemoteChanges, function () {\n if (!stillAlive()) return Promise.reject(\"Database not open\");\n // FIXTHIS: Check what to do if clear() is true!\n return (partial ? saveToUncommitedChanges(remoteChanges) : finallyCommitAllChanges(remoteChanges, remoteRevision)).catch(function (error) {\n abortTheProvider(error);\n return Promise.reject(error);\n });\n }, dbAliveID);\n\n function saveToUncommitedChanges(changes) {\n return db.transaction('rw', db._uncommittedChanges, function () {\n changes.forEach(function (change) {\n var changeToAdd = {\n node: node.id,\n type: change.type,\n table: change.table,\n key: change.key\n };\n if (change.obj) changeToAdd.obj = change.obj;\n if (change.mods) changeToAdd.mods = change.mods;\n db._uncommittedChanges.add(changeToAdd);\n });\n }).then(function () {\n node.appliedRemoteRevision = remoteRevision;\n node.save();\n });\n }\n\n function finallyCommitAllChanges(changes, remoteRevision) {\n //alert(\"finallyCommitAllChanges() will now start its job.\");\n //var tick = Date.now();\n\n // 1. Open a write transaction on all tables in DB\n return db.transaction('rw', db.tables.filter(function (table) {\n return table.name === '_changes' || table.name === '_uncommittedChanges' || table.schema.observable;\n }), function () {\n var trans = Dexie.currentTransaction;\n var localRevisionBeforeChanges = 0;\n db._changes.orderBy('rev').last(function (lastChange) {\n // Store what revision we were at before committing the changes\n localRevisionBeforeChanges = lastChange && lastChange.rev || 0;\n }).then(function () {\n // Specify the source. Important for the change consumer to ignore changes originated from self!\n trans.source = node.id;\n // 2. Apply uncommitted changes and delete each uncommitted change\n return db._uncommittedChanges.where('node').equals(node.id).toArray();\n }).then(function (uncommittedChanges) {\n return applyChanges(uncommittedChanges, 0);\n }).then(function () {\n return db._uncommittedChanges.where('node').equals(node.id).delete();\n }).then(function () {\n // 3. Apply last chunk of changes\n return applyChanges(changes, 0);\n }).then(function () {\n // Get what revision we are at now:\n return db._changes.orderBy('rev').last();\n }).then(function (lastChange) {\n var currentLocalRevision = lastChange && lastChange.rev || 0;\n // 4. Update node states (appliedRemoteRevision, remoteBaseRevisions and eventually myRevision)\n node.appliedRemoteRevision = remoteRevision;\n node.remoteBaseRevisions.push({ remote: remoteRevision, local: currentLocalRevision });\n if (node.myRevision === localRevisionBeforeChanges) {\n // If server was up-to-date before we added new changes from the server, update myRevision to last change\n // because server is still up-to-date! This is also important in order to prohibit getLocalChangesForNode() from\n // ever sending an empty change list to server, which would otherwise be done every second time it would send changes.\n node.myRevision = currentLocalRevision;\n }\n // Garbage collect remoteBaseRevisions not in use anymore:\n if (node.remoteBaseRevisions.length > 1) {\n for (var i = node.remoteBaseRevisions.length - 1; i > 0; --i) {\n if (node.myRevision >= node.remoteBaseRevisions[i].local) {\n node.remoteBaseRevisions.splice(0, i);\n break;\n }\n }\n }\n node.save(); // We are not including _syncNodes in transaction, so this save() call will execute in its own transaction.\n //var tock = Date.now();\n //alert(\"finallyCommitAllChanges() has done its job. \" + changes.length + \" changes applied in \" + ((tock - tick) / 1000) + \"seconds\");\n });\n\n function applyChanges(changes, offset) {\n /// \n /// \n var lastChangeType = 0;\n var lastCreatePromise = null;\n if (offset >= changes.length) return Promise.resolve(null);\n var change = changes[offset];\n var table = trans.tables[change.table];\n while (change && change.type === CREATE) {\n // Optimize CREATE changes because on initial sync with server, the entire DB will be downloaded in forms of CREATE changes.\n // Instead of waiting for each change to resolve, do all CREATE changes in bulks until another type of change is stepped upon.\n // This case is the only case that allows i to increment and the for-loop to continue since it does not return anything.\n var specifyKey = !table.schema.primKey.keyPath;\n lastCreatePromise = function (change, table, specifyKey) {\n return (specifyKey ? table.add(change.obj, change.key) : table.add(change.obj)).catch(\"ConstraintError\", function (e) {\n return specifyKey ? table.put(change.obj, change.key) : table.put(change.obj);\n });\n }(change, table, specifyKey);\n change = changes[++offset];\n if (change) table = trans.tables[change.table];\n }\n\n if (lastCreatePromise) {\n // We did some CREATE changes but now stumbled upon another type of change.\n // Let's wait for the last CREATE change to resolve and then call applyChanges again at current position. Next time, lastCreatePromise will be null and a case below will happen.\n return lastCreatePromise.then(function () {\n return offset < changes.length ? applyChanges(changes, offset) : null;\n });\n }\n\n if (change) {\n if (change.type === UPDATE) {\n return table.update(change.key, change.mods).then(function () {\n // Wait for update to resolve before taking next change. Why? Because it will lock transaction anyway since we are listening to CRUD events here.\n return applyChanges(changes, offset + 1);\n });\n }\n\n if (change.type === DELETE) {\n return table.delete(change.key).then(function () {\n // Wait for delete to resolve before taking next change. Why? Because it will lock transaction anyway since we are listening to CRUD events here.\n return applyChanges(changes, offset + 1);\n });\n }\n }\n\n return Promise.resolve(null); // Will return null or a Promise and make the entire applyChanges promise finally resolve.\n }\n });\n }\n }\n\n //\n //\n // Continuation Patterns Follows\n //\n //\n\n function continueSendingChanges(continuation) {\n if (!stillAlive()) {\n // Database was closed.\n if (continuation.disconnect) continuation.disconnect();\n return;\n }\n\n connectedContinuation = continuation;\n activePeer.on('disconnect', function () {\n if (connectedContinuation) {\n if (connectedContinuation.react) {\n try {\n // react pattern must provide a disconnect function.\n connectedContinuation.disconnect();\n } catch (e) {}\n }\n connectedContinuation = null; // Stop poll() pattern from polling again and abortTheProvider() from being called twice.\n }\n });\n\n if (continuation.react) {\n continueUsingReactPattern(continuation);\n } else {\n continueUsingPollPattern(continuation);\n }\n }\n\n // React Pattern (eager)\n function continueUsingReactPattern(continuation) {\n var changesWaiting, // Boolean\n isWaitingForServer; // Boolean\n\n function onChanges() {\n if (connectedContinuation) {\n changeStatusTo(Statuses.SYNCING);\n if (isWaitingForServer) changesWaiting = true;else {\n reactToChanges();\n }\n }\n }\n\n db.on('changes', onChanges);\n\n // Override disconnect() to also unsubscribe to onChanges.\n activePeer.on('disconnect', function () {\n db.on.changes.unsubscribe(onChanges);\n });\n\n function reactToChanges() {\n if (!connectedContinuation) return;\n changesWaiting = false;\n isWaitingForServer = true;\n getLocalChangesForNode_autoAckIfEmpty(node, function (changes, remoteBaseRevision, partial, nodeModificationsOnAck) {\n if (!connectedContinuation) return;\n if (changes.length > 0) {\n continuation.react(changes, remoteBaseRevision, partial, function onChangesAccepted() {\n Object.keys(nodeModificationsOnAck).forEach(function (keyPath) {\n Dexie.setByKeyPath(node, keyPath, nodeModificationsOnAck[keyPath]);\n });\n node.save();\n // More changes may be waiting:\n reactToChanges();\n });\n } else {\n isWaitingForServer = false;\n if (changesWaiting) {\n // A change jumped in between the time-spot of quering _changes and getting called back with zero changes.\n // This is an expreemely rare scenario, and eventually impossible. But need to be here because it could happen in theory.\n reactToChanges();\n } else {\n changeStatusTo(Statuses.ONLINE);\n }\n }\n }).catch(abortTheProvider);\n }\n\n reactToChanges();\n }\n\n // Poll Pattern\n function continueUsingPollPattern() {\n\n function syncAgain() {\n getLocalChangesForNode_autoAckIfEmpty(node, function (changes, remoteBaseRevision, partial, nodeModificationsOnAck) {\n\n protocolInstance.sync(node.syncContext, url, options, remoteBaseRevision, node.appliedRemoteRevision, changes, partial, applyRemoteChanges, onChangesAccepted, onSuccess, onError);\n\n function onChangesAccepted() {\n Object.keys(nodeModificationsOnAck).forEach(function (keyPath) {\n Dexie.setByKeyPath(node, keyPath, nodeModificationsOnAck[keyPath]);\n });\n node.save();\n }\n\n function onSuccess(continuation) {\n if (!connectedContinuation) {\n // Got disconnected before succeeding. Quit.\n return;\n }\n connectedContinuation = continuation;\n if (partial) {\n // We only sent partial changes. Need to do another round asap.\n syncAgain();\n } else {\n // We've sent all changes now (in sync!)\n if (!isNaN(continuation.again) && continuation.again < Infinity) {\n // Provider wants to keep polling. Set Status to ONLINE.\n changeStatusTo(Statuses.ONLINE);\n setTimeout(function () {\n if (connectedContinuation) {\n changeStatusTo(Statuses.SYNCING);\n syncAgain();\n }\n }, continuation.again);\n } else {\n // Provider seems finished polling. Since we are never going to poll again,\n // disconnect provider and set status to OFFLINE until another call to db.syncable.connect().\n activePeer.disconnect(Statuses.OFFLINE);\n }\n }\n }\n\n function onError(error, again) {\n if (!isNaN(again) && again < Infinity) {\n if (connectedContinuation) {\n setTimeout(function () {\n if (connectedContinuation) {\n changeStatusTo(Statuses.SYNCING);\n syncAgain();\n }\n }, again);\n changeStatusTo(Statuses.ERROR_WILL_RETRY);\n } // else status is already changed since we got disconnected.\n } else {\n abortTheProvider(error); // Will fire ERROR on onStatusChanged.\n }\n }\n }).catch(abortTheProvider);\n }\n\n if (hasMoreToGive) {\n syncAgain();\n } else if (connectedContinuation && !isNaN(connectedContinuation.again) && connectedContinuation.again < Infinity) {\n changeStatusTo(Statuses.ONLINE);\n setTimeout(function () {\n if (connectedContinuation) {\n changeStatusTo(Statuses.SYNCING);\n syncAgain();\n }\n }, connectedContinuation.again);\n }\n }\n }\n }\n\n db.close = override(db.close, function (origClose) {\n return function () {\n activePeers.forEach(function (peer) {\n peer.disconnect();\n });\n return origClose.apply(this, arguments);\n };\n });\n\n var syncNodeSaveQueContexts = {};\n db.observable.SyncNode.prototype.save = function () {\n var self = this;\n return db.transaction('rw?', db._syncNodes, function () {\n db._syncNodes.put(self);\n });\n };\n\n function enque(context, fn, instanceID) {\n function _enque() {\n if (!context.ongoingOperation) {\n context.ongoingOperation = Dexie.ignoreTransaction(function () {\n return Dexie.vip(function () {\n return fn();\n });\n }).then(function (res) {\n delete context.ongoingOperation;\n return res;\n });\n } else {\n context.ongoingOperation = context.ongoingOperation.then(function () {\n return enque(context, fn, instanceID);\n });\n }\n return context.ongoingOperation;\n }\n\n if (!instanceID) {\n // Caller wants to enque it until database becomes open.\n if (db.isOpen()) {\n return _enque();\n } else {\n return Promise.reject(new Error(\"Database was closed\"));\n }\n } else if (db._localSyncNode && instanceID === db._localSyncNode.id) {\n // DB is already open but queuer doesnt want it to be queued if database has been closed (request bound to current instance of DB)\n return _enque();\n } else {\n return Promise.reject(new Error(\"Database was closed\"));\n }\n }\n\n function combineCreateAndUpdate(prevChange, nextChange) {\n var clonedChange = Dexie.deepClone(prevChange); // Clone object before modifying since the earlier change in db.changes[] would otherwise be altered.\n Object.keys(nextChange.mods).forEach(function (keyPath) {\n setByKeyPath(clonedChange.obj, keyPath, nextChange.mods[keyPath]);\n });\n return clonedChange;\n }\n\n function combineUpdateAndUpdate(prevChange, nextChange) {\n var clonedChange = Dexie.deepClone(prevChange); // Clone object before modifying since the earlier change in db.changes[] would otherwise be altered.\n Object.keys(nextChange.mods).forEach(function (keyPath) {\n // If prev-change was changing a parent path of this keyPath, we must update the parent path rather than adding this keyPath\n var hadParentPath = false;\n Object.keys(prevChange.mods).filter(function (parentPath) {\n return keyPath.indexOf(parentPath + '.') === 0;\n }).forEach(function (parentPath) {\n setByKeyPath(clonedChange[parentPath], keyPath.substr(parentPath.length + 1), nextChange.mods[keyPath]);\n hadParentPath = true;\n });\n if (!hadParentPath) {\n // Add or replace this keyPath and its new value\n clonedChange.mods[keyPath] = nextChange.mods[keyPath];\n }\n // In case prevChange contained sub-paths to the new keyPath, we must make sure that those sub-paths are removed since\n // we must mimic what would happen if applying the two changes after each other:\n Object.keys(prevChange.mods).filter(function (subPath) {\n return subPath.indexOf(keyPath + '.') === 0;\n }).forEach(function (subPath) {\n delete clonedChange[subPath];\n });\n });\n return clonedChange;\n }\n};\n\nSyncable.Statuses = {\n ERROR: -1, // An irrepairable error occurred and the sync provider is dead.\n OFFLINE: 0, // The sync provider hasnt yet become online, or it has been disconnected.\n CONNECTING: 1, // Trying to connect to server\n ONLINE: 2, // Connected to server and currently in sync with server\n SYNCING: 3, // Syncing with server. For poll pattern, this is every poll call. For react pattern, this is when local changes are being sent to server.\n ERROR_WILL_RETRY: 4 // An error occured such as net down but the sync provider will retry to connect.\n};\n\nSyncable.StatusTexts = {\n \"-1\": \"ERROR\",\n \"0\": \"OFFLINE\",\n \"1\": \"CONNECTING\",\n \"2\": \"ONLINE\",\n \"3\": \"SYNCING\",\n \"4\": \"ERROR_WILL_RETRY\"\n};\n\nSyncable.registeredProtocols = {}; // Map when key is the provider name.\n\nSyncable.registerSyncProtocol = function (name, protocolInstance) {\n /// \n /// Register a syncronization protocol that can syncronize databases with remote servers.\n /// \n /// Provider name\n /// Implementation of ISyncProtocol\n Syncable.registeredProtocols[name] = protocolInstance;\n};\n\n// Register addon in Dexie:\nDexie.Syncable = Syncable;\nDexie.addons.push(Syncable);"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/addons/Dexie.Syncable/dist/dexie-syncable.min.js b/addons/Dexie.Syncable/dist/dexie-syncable.min.js new file mode 100644 index 000000000..d92c350f4 --- /dev/null +++ b/addons/Dexie.Syncable/dist/dexie-syncable.min.js @@ -0,0 +1,2 @@ +!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n(require("dexie"),require("dexie-observable")):"function"==typeof define&&define.amd?define(["dexie","dexie-observable"],n):e.Dexie.Syncable=n(e.Dexie,e.dexieObservable)}(this,function(e,n){"use strict";function t(n){function s(t,o,i,c,s){function p(){return n._localSyncNode&&n._localSyncNode.id===s}function m(t){return n.transaction("rw",n._syncNodes,function(){if(!i)throw new Error("Url cannot be empty");return n._syncNodes.where("url").equalsIgnoreCase(i).first(function(c){function s(n,t){this.nodeID=n,t&&e.extend(this,t)}return s.prototype.save=function(){return e.vip(function(){return c.save()})},c?(c.syncContext=new s(c.id,c.syncContext),c.syncProtocol=o,n._syncNodes.put(c)):(c=new n.observable.SyncNode,c.myRevision=-1,c.appliedRemoteRevision=null,c.remoteBaseRevisions=[],c.type="remote",c.syncProtocol=o,c.url=i,c.syncOptions=t,c.lastHeartBeat=Date.now(),c.dbUploadState=null,r.resolve(function(){return t.initialUpload===!1?n._changes.lastKey(function(e){c.myRevision=e}):void 0}).then(function(){n._syncNodes.add(c).then(function(e){c.syncContext=new s(e),n._syncNodes.put(c)})})),c})})}function N(o){function f(e){o.status!==e&&(o.status=e,o.save(),n.syncable.on.statusChanged.fire(e,i),n.broadcastMessage("syncStatusChanged",{newStatus:e,url:i},!1))}function m(){return a(m,function(){return g(o,function(n,s,a,u){function l(){Object.keys(u).forEach(function(n){e.setByKeyPath(o,n,u[n])}),o.save(),d.then(C)}var d=new r(function(r,u){O=function(e){u(e)},e.asap(function(){function e(e,n){u(e),p()&&(!isNaN(n)&&1/0>n?(setTimeout(function(){p()&&(f(h.SYNCING),m())},n),f(h.ERROR_WILL_RETRY,e),j&&j.disconnect&&j.disconnect(),j=null):N(e))}try{t.sync(o.syncContext,i,c,s,o.appliedRemoteRevision,n,a,S,l,function(e){r(e)},e)}catch(d){e(d,1/0)}})});return d.then(function(){})})},s)}function N(e){w.disconnect(h.ERROR,e)}function R(e){if(0===e.remoteBaseRevisions.length)return{maxClientRevision:1/0,remoteBaseRevision:null};for(var n=e.remoteBaseRevisions.length-1;n>=0;--n)if(e.myRevision>=e.remoteBaseRevisions[n].local)return{maxClientRevision:n===e.remoteBaseRevisions.length-1?1/0:e.remoteBaseRevisions[n+1].local,remoteBaseRevision:e.remoteBaseRevisions[n].remote};return{maxClientRevision:e.remoteBaseRevisions[0].local,remoteBaseRevision:null}}function g(n,t){return _(n,function o(r,i,c,s){return 0===r.length&&"myRevision"in s&&s.myRevision!==n.myRevision?(Object.keys(s).forEach(function(t){e.setByKeyPath(n,t,s[t])}),n.save(),_(n,o)):t(r,i,c,s)})}function _(t,o){function i(e,r,s){var a=!1;return s.until(function(){return r.length===b?(a=!0,!0):void 0}).each(function(n,t){r.push({type:d,table:e.currentTable,key:t.key,obj:t.value}),e.currentKey=t.key}).then(function(){if(a)return E=!0,o(r,null,!0,{dbUploadState:e});if(0===e.tablesToUpload.length){var s=R(t);return c(e.localBaseRevision,b-r.length,s.maxClientRevision,function(e,n,t){return r=r.concat(e),t.dbUploadState=null,o(r,s.remoteBaseRevision,n,t)})}return e.currentTable=e.tablesToUpload.shift(),i(e,r,n.table(e.currentTable).orderBy(":id"))})}function c(e,o,r,i){var c={},s=0,a=!1,f=t.id,h=e;return n.transaction("r",n._changes,function(){var t=r===1/0?n._changes.where("rev").above(e):n._changes.where("rev").between(e,r,!1,!0);t.until(function(){return s===o?(a=!0,!0):void 0}).each(function(e){if(h=e.rev,e.source!==f){var n={type:e.type,table:e.table,key:e.key};e.type===d?n.obj=e.obj:e.type===y&&(n.mods=e.mods);var t=e.table+":"+e.key,o=c[t];if(o){var r=n,i=function(){switch(o.type){case d:switch(r.type){case d:return r;case y:return u(o,r);case v:return r}break;case y:switch(r.type){case d:return r;case y:return l(o,r);case v:return r}break;case v:switch(r.type){case d:return r;case y:return o;case v:return o}}}();c[t]=i}else c[t]=n,++s}})}).then(function(){var e=Object.keys(c).map(function(e){return c[e]});return E=a,i(e,a,{myRevision:h})})}if(t.myRevision>=0){var s=R(t);return c(t.myRevision,b,s.maxClientRevision,function(e,n,t){return o(e,s.remoteBaseRevision,n,t)})}if(null===t.dbUploadState){var a=n.tables.filter(function(e){return e.schema.observable}).map(function(e){return e.name});if(0===a.length)return r.resolve(o([],null,!1,{}));var f={tablesToUpload:a,currentTable:a.shift(),currentKey:null};return n._changes.orderBy("rev").last(function(e){f.localBaseRevision=e&&e.rev||0;var t=n.table(f.currentTable).orderBy(":id");return i(f,[],t)})}if(t.dbUploadState.currentKey){var h=n.table(t.dbUploadState.currentTable).where(":id").above(t.dbUploadState.currentKey);return i(e.deepClone(t.dbUploadState),[],h)}var h=n.table(f.currentTable).orderBy(":id");return i(e.deepClone(t.dbUploadState),[],h)}function S(t,i,c,u){function l(e){return n.transaction("rw",n._uncommittedChanges,function(){e.forEach(function(e){var t={node:o.id,type:e.type,table:e.table,key:e.key};e.obj&&(t.obj=e.obj),e.mods&&(t.mods=e.mods),n._uncommittedChanges.add(t)})}).then(function(){o.appliedRemoteRevision=i,o.save()})}function f(t,i){return n.transaction("rw",n.tables.filter(function(e){return"_changes"===e.name||"_uncommittedChanges"===e.name||e.schema.observable}),function(){function c(e,n){var t=null;if(n>=e.length)return r.resolve(null);for(var o=e[n],i=s.tables[o.table];o&&o.type===d;){var a=!i.schema.primKey.keyPath;t=function(e,n,t){return(t?n.add(e.obj,e.key):n.add(e.obj))["catch"]("ConstraintError",function(o){return t?n.put(e.obj,e.key):n.put(e.obj)})}(o,i,a),o=e[++n],o&&(i=s.tables[o.table])}if(t)return t.then(function(){return n1)for(var t=o.remoteBaseRevisions.length-1;t>0;--t)if(o.myRevision>=o.remoteBaseRevisions[t].local){o.remoteBaseRevisions.splice(0,t);break}o.save()})})}return a(S,function(){return p()?(c?l(t):f(t,i))["catch"](function(e){return N(e),r.reject(e)}):r.reject("Database not open")},s)}function C(e){return p()?(j=e,w.on("disconnect",function(){if(j){if(j.react)try{j.disconnect()}catch(e){}j=null}}),void(e.react?B(e):I(e))):void(e.disconnect&&e.disconnect())}function B(t){function r(){j&&(f(h.SYNCING),s?c=!0:i())}function i(){j&&(c=!1,s=!0,g(o,function(n,r,a,u){j&&(n.length>0?t.react(n,r,a,function(){Object.keys(u).forEach(function(n){e.setByKeyPath(o,n,u[n])}),o.save(),i()}):(s=!1,c?i():f(h.ONLINE)))})["catch"](N))}var c,s;n.on("changes",r),w.on("disconnect",function(){n.on.changes.unsubscribe(r)}),i()}function I(){function n(){g(o,function(r,s,a,u){function l(){Object.keys(u).forEach(function(n){e.setByKeyPath(o,n,u[n])}),o.save()}function d(e){j&&(j=e,a?n():!isNaN(e.again)&&e.again<1/0?(f(h.ONLINE),setTimeout(function(){j&&(f(h.SYNCING),n())},e.again)):w.disconnect(h.OFFLINE))}function y(e,t){!isNaN(t)&&1/0>t?j&&(setTimeout(function(){j&&(f(h.SYNCING),n())},t),f(h.ERROR_WILL_RETRY)):N(e)}t.sync(o.syncContext,i,c,s,o.appliedRemoteRevision,r,a,S,l,d,y)})["catch"](N)}E?n():j&&!isNaN(j.again)&&j.again<1/0&&(f(h.ONLINE),setTimeout(function(){j&&(f(h.SYNCING),n())},j.again))}w.on("disconnect",function(e){isNaN(e)||f(e)});var j;return f(h.CONNECTING),m()}var R=f.filter(function(e){return e.url===i});if(R.length>0)return R[0].connectPromise;var g=m(c).then(function(e){return N(e)}),O=null,_=!1,E=!0,w={url:i,status:h.OFFLINE,connectPromise:g,on:e.events(null,"disconnect"),disconnect:function(e,n){if(!_){w.on.disconnect.fire(e,n);var t=f.indexOf(w);t>=0&&f.splice(t,1),n&&O&&O(n)}_=!0}};return f.push(w),g}function a(t,o,i){function c(){return t.ongoingOperation?t.ongoingOperation=t.ongoingOperation.then(function(){return a(t,o,i)}):t.ongoingOperation=e.ignoreTransaction(function(){return e.vip(function(){return o()})}).then(function(e){return delete t.ongoingOperation,e}),t.ongoingOperation}return i?n._localSyncNode&&i===n._localSyncNode.id?c():r.reject(new Error("Database was closed")):n.isOpen()?c():r.reject(new Error("Database was closed"))}function u(n,t){var o=e.deepClone(n);return Object.keys(t.mods).forEach(function(e){i(o.obj,e,t.mods[e])}),o}function l(n,t){var o=e.deepClone(n);return Object.keys(t.mods).forEach(function(e){var r=!1;Object.keys(n.mods).filter(function(n){return 0===e.indexOf(n+".")}).forEach(function(n){i(o[n],e.substr(n.length+1),t.mods[e]),r=!0}),r||(o.mods[e]=t.mods[e]),Object.keys(n.mods).filter(function(n){return 0===n.indexOf(e+".")}).forEach(function(e){delete o[e]})}),o}var f=[],d=1,y=2,v=3,h=t.Statuses,b=1e3;n.on("message",function(t){e.vip(function(){"connect"===t.type?n.syncable.connect(t.protocolName,t.url,t.options).then(t.resolve,t.reject):"disconnect"===t.type?n.syncable.disconnect(t.url).then(t.resolve,t.reject):"syncStatusChanged"===t.type&&n.syncable.on.statusChanged.fire(t.newStatus,t.url)})}),n.on("cleanup",function(t){t&&n._syncNodes.where("type").equals("remote").and(function(e){return e.status!==h.OFFLINE&&e.status!==h.ERROR}).each(function(t){e.ignoreTransaction(function(){e.vip(function(){n.syncable.connect(t.syncProtocol,t.url,t.syncOptions)})})})}),n.on("ready",function(){return n._localSyncNode&&n._localSyncNode.isMaster?n._syncNodes.where("type").equals("remote").and(function(e){return e.status!==h.OFFLINE&&e.status!==h.ERROR}).toArray(function(e){return e.length>0?r.all(e.map(function(e){return n.syncable.connect(e.syncProtocol,e.url,e.syncOptions)["catch"](function(e){})})):void 0}):void 0},!0),n.syncable={},n.syncable.getStatus=function(o,i){return n.isOpen()?e.vip(function(){return n._syncNodes.where("url").equals(o).first(function(e){return e?e.status:h.OFFLINE})}).then(i):r.resolve(t.Statuses.OFFLINE).then(i)},n.syncable.list=function(){return n._syncNodes.where("type").equals("remote").toArray(function(e){return e.map(function(e){return e.url})})},n.syncable.on=e.events(n,{statusChanged:"asap"}),n.syncable.disconnect=function(e){return n._localSyncNode&&n._localSyncNode.isMaster?f.filter(function(n){return n.url===e}).forEach(function(e){e.disconnect(h.OFFLINE)}):n._syncNodes.where("isMaster").above(0).first(function(t){n.sendMessage("disconnect",{url:e},t.id,{wantReply:!0})}),n._syncNodes.where("url").equals(e).modify(function(e){e.status=h.OFFLINE})},n.syncable.connect=function(o,i,c){c=c||{};var a=t.registeredProtocols[o];if(a)return n.isOpen()&&n._localSyncNode?n._localSyncNode.isMaster?s(a,o,i,c,n._localSyncNode.id):(n.table("_syncNodes").where("isMaster").above(0).first(function(e){return n.sendMessage("connect",{protocolName:o,url:i,options:c},e.id,{wantReply:!0})}),r.resolve()):new r(function(t,r){n.on("ready",function(){return e.vip(function(){return n.syncable.connect(o,i,c).then(t)["catch"](function(e){r(e)})})})});throw new Error("ISyncProtocol '"+o+"' is not registered in Dexie.Syncable.registerSyncProtocol()")},n.syncable["delete"]=function(e){return n.transaction("rw",n._syncNodes,n._changes,n._uncommittedChanges,function(){n._syncNodes.where("url").equals(e).toArray(function(e){if(e.length>0){var t=e.map(function(e){return e.id});return n._syncNodes.where("id").anyOf(t)["delete"]().then(function(){return c.deleteOldChanges(),n._uncommittedChanges.where("node").anyOf(t)["delete"]()})}})})},n.syncable.unsyncedChanges=function(e){return n._syncNodes.where("url").equals(e).first(function(e){return n._changes.where("rev").above(e.myRevision).toArray()})},n.close=o(n.close,function(e){return function(){return f.forEach(function(e){e.disconnect()}),e.apply(this,arguments)}});n.observable.SyncNode.prototype.save=function(){var e=this;return n.transaction("rw?",n._syncNodes,function(){n._syncNodes.put(e)})}}e="default"in e?e["default"]:e;var o=e.override,r=e.Promise,i=e.setByKeyPath,c=e.Observable;return t.Statuses={ERROR:-1,OFFLINE:0,CONNECTING:1,ONLINE:2,SYNCING:3,ERROR_WILL_RETRY:4},t.StatusTexts={"-1":"ERROR",0:"OFFLINE",1:"CONNECTING",2:"ONLINE",3:"SYNCING",4:"ERROR_WILL_RETRY"},t.registeredProtocols={},t.registerSyncProtocol=function(e,n){t.registeredProtocols[e]=n},e.Syncable=t,e.addons.push(t),t}); +//# sourceMappingURL=dist/dexie-syncable.min.js.map \ No newline at end of file diff --git a/addons/Dexie.Syncable/dist/dexie-syncable.min.js.map b/addons/Dexie.Syncable/dist/dexie-syncable.min.js.map new file mode 100644 index 000000000..1cb1479d9 --- /dev/null +++ b/addons/Dexie.Syncable/dist/dexie-syncable.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../C:/repos/dexie-release/addons/Dexie.Syncable/tools/tmp/src/Dexie.Syncable.js"],"names":["Syncable","db","connect","protocolInstance","protocolName","url","options","dbAliveID","stillAlive","_localSyncNode","id","getOrCreateSyncNode","transaction","_syncNodes","Error","where","equalsIgnoreCase","first","node","PersistedContext","nodeID","otherProps","this","Dexie","extend","prototype","save","vip","syncContext","syncProtocol","put","observable","SyncNode","myRevision","appliedRemoteRevision","remoteBaseRevisions","type","syncOptions","lastHeartBeat","Date","now","dbUploadState","Promise","resolve","initialUpload","_changes","lastKey","currentRevision","then","add","nodeId","connectProtocol","changeStatusTo","newStatus","status","syncable","on","statusChanged","fire","broadcastMessage","doSync","enque","getLocalChangesForNode_autoAckIfEmpty","changes","remoteBaseRevision","partial","nodeModificationsOnAck","onChangesAccepted","Object","keys","forEach","keyPath","setByKeyPath","finalSyncPromise","continueSendingChanges","reject","rejectConnectPromise","err","asap","onError","error","again","isNaN","Infinity","setTimeout","Statuses","SYNCING","ERROR_WILL_RETRY","connectedContinuation","disconnect","abortTheProvider","sync","applyRemoteChanges","continuation","ex","activePeer","ERROR","getBaseRevisionAndMaxClientRevision","length","maxClientRevision","i","local","remote","cb","getLocalChangesForNode","autoAck","getTableObjectsAsChanges","state","collection","limitReached","until","MAX_CHANGES_PER_CHUNK","each","item","cursor","push","CREATE","table","currentTable","key","obj","value","currentKey","hasMoreToGive","tablesToUpload","brmcr","getChangesSinceRevision","localBaseRevision","additionalChanges","concat","shift","orderBy","revision","maxChanges","maxRevision","changeSet","numChanges","ignoreSource","nextRevision","query","above","between","change","rev","source","changeToSend","UPDATE","mods","prevChange","nextChange","mergedChange","combineCreateAndUpdate","DELETE","combineUpdateAndUpdate","map","tables","filter","schema","name","last","lastChange","deepClone","remoteChanges","remoteRevision","clear","saveToUncommitedChanges","_uncommittedChanges","changeToAdd","finallyCommitAllChanges","applyChanges","offset","lastCreatePromise","trans","specifyKey","primKey","e","update","currentTransaction","localRevisionBeforeChanges","equals","toArray","uncommittedChanges","currentLocalRevision","splice","react","continueUsingReactPattern","continueUsingPollPattern","onChanges","isWaitingForServer","changesWaiting","reactToChanges","ONLINE","unsubscribe","syncAgain","onSuccess","OFFLINE","CONNECTING","existingPeer","activePeers","peer","connectPromise","disconnected","events","pos","indexOf","context","fn","instanceID","_enque","ongoingOperation","ignoreTransaction","res","isOpen","clonedChange","hadParentPath","parentPath","substr","subPath","msg","weBecameMaster","and","connectedRemoteNode","isMaster","connectedRemoteNodes","all","getStatus","list","a","masterNode","sendMessage","wantReply","modify","registeredProtocols","nodes","nodeIDs","anyOf","Observable","deleteOldChanges","unsyncedChanges","close","override","origClose","apply","arguments","self","StatusTexts","-1","0","1","2","3","4","registerSyncProtocol","addons"],"mappings":"8RA2Be,SAASA,GAASC,GA2L7B,QAASC,GAAQC,EAAkBC,EAAcC,EAAKC,EAASC,GAqC3D,QAASC,KAGL,MAAOP,GAAGQ,gBAAkBR,EAAGQ,eAAeC,KAAOH,EAGzD,QAASI,GAAoBL,GACzB,MAAOL,GAAGW,YAAY,KAAMX,EAAGY,WAAY,WACvC,IAAKR,EAAK,KAAM,IAAIS,OAAM,sBAG1B,OAAOb,GAAGY,WAAWE,MAAM,OAAOC,iBAAiBX,GAAKY,MAAM,SAAUC,GAIpE,QAASC,GAAiBC,EAAQC,GAC9BC,KAAKF,OAASA,EACVC,GAAYE,EAAMC,OAAOF,KAAMD,GAwCvC,MArCAF,GAAiBM,UAAUC,KAAO,WAE9B,MAAOH,GAAMI,IAAI,WACb,MAAOT,GAAKQ,UAIhBR,GAEAA,EAAKU,YAAc,GAAIT,GAAiBD,EAAKR,GAAIQ,EAAKU,aACtDV,EAAKW,aAAezB,EACpBH,EAAGY,WAAWiB,IAAIZ,KAGlBA,EAAO,GAAIjB,GAAG8B,WAAWC,SACzBd,EAAKe,WAAa,GAClBf,EAAKgB,sBAAwB,KAC7BhB,EAAKiB,uBACLjB,EAAKkB,KAAO,SACZlB,EAAKW,aAAezB,EACpBc,EAAKb,IAAMA,EACXa,EAAKmB,YAAc/B,EACnBY,EAAKoB,cAAgBC,KAAKC,MAC1BtB,EAAKuB,cAAgB,KACrBC,EAAQC,QAAQ,WAEZ,MAAIrC,GAAQsC,iBAAkB,EAAc3C,EAAG4C,SAASC,QAAQ,SAAUC,GACtE7B,EAAKe,WAAac,IADtB,SAGDC,KAAK,WACJ/C,EAAGY,WAAWoC,IAAI/B,GAAM8B,KAAK,SAAUE,GACnChC,EAAKU,YAAc,GAAIT,GAAiB+B,GACxCjD,EAAGY,WAAWiB,IAAIZ,QAKvBA,MAKnB,QAASiC,GAAgBjC,GAGrB,QAASkC,GAAeC,GAChBnC,EAAKoC,SAAWD,IAChBnC,EAAKoC,OAASD,EACdnC,EAAKQ,OACLzB,EAAGsD,SAASC,GAAGC,cAAcC,KAAKL,EAAWhD,GAE7CJ,EAAG0D,iBAAiB,qBAAuBN,UAAWA,EAAWhD,IAAKA,IAAO,IAYrF,QAASuD,KAEL,MAAOC,GAAMD,EAAQ,WAEjB,MAAOE,GAAsC5C,EAAM,SAA+B6C,EAASC,EAAoBC,EAASC,GAyCpH,QAASC,KACLC,OAAOC,KAAKH,GAAwBI,QAAQ,SAAUC,GAClDhD,EAAMiD,aAAatD,EAAMqD,EAASL,EAAuBK,MAE7DrD,EAAKQ,OAGL+C,EAAiBzB,KAAK0B,GA7C1B,GAAID,GAAmB,GAAI/B,GAAQ,SAAUC,EAASgC,GAClDC,EAAuB,SAAUC,GAC7BF,EAAOE,IAEXtD,EAAMuD,KAAK,WASP,QAASC,GAAQC,EAAOC,GACpBN,EAAOK,GACHxE,OACK0E,MAAMD,IAAkBE,EAAAA,EAARF,GACjBG,WAAW,WACH5E,MACA4C,EAAeiC,EAASC,SACxB1B,MAELqB,GACH7B,EAAeiC,EAASE,iBAAkBP,GACtCQ,GAAyBA,EAAsBC,YAAYD,EAAsBC,aACrFD,EAAwB,MAExBE,EAAiBV,IAtB7B,IACI7E,EAAiBwF,KAAKzE,EAAKU,YAAavB,EAAKC,EAAS0D,EAAoB9C,EAAKgB,sBAAuB6B,EAASE,EAAS2B,EAAoBzB,EAAmB,SAAU0B,GACrKlD,EAAQkD,IACTd,GACL,MAAOe,GACLf,EAAQe,EAAIX,EAAAA,OAwBxB,OAAOV,GAAiBzB,KAAK,iBAclCzC,GAGP,QAASmF,GAAiBV,GACtBe,EAAWN,WAAWJ,EAASW,MAAOhB,GAG1C,QAASiB,GAAoC/E,GAEzC,GAAwC,IAApCA,EAAKiB,oBAAoB+D,OAAc,OAEvCC,kBAAmBhB,EAAAA,EACnBnB,mBAAoB,KAExB,KAAK,GAAIoC,GAAIlF,EAAKiB,oBAAoB+D,OAAS,EAAGE,GAAK,IAAKA,EACxD,GAAIlF,EAAKe,YAAcf,EAAKiB,oBAAoBiE,GAAGC,MAE/C,OACIF,kBAAmBC,IAAMlF,EAAKiB,oBAAoB+D,OAAS,EAAIf,EAAAA,EAAWjE,EAAKiB,oBAAoBiE,EAAI,GAAGC,MAC1GrC,mBAAoB9C,EAAKiB,oBAAoBiE,GAAGE,OAK5D,QACIH,kBAAmBjF,EAAKiB,oBAAoB,GAAGkE,MAC/CrC,mBAAoB,MAI5B,QAASF,GAAsC5C,EAAMqF,GACjD,MAAOC,GAAuBtF,EAAM,QAASuF,GAAQ1C,EAASC,EAAoBC,EAASC,GACvF,MAAuB,KAAnBH,EAAQmC,QAAgB,cAAgBhC,IAA0BA,EAAuBjC,aAAef,EAAKe,YAC7GmC,OAAOC,KAAKH,GAAwBI,QAAQ,SAAUC,GAClDhD,EAAMiD,aAAatD,EAAMqD,EAASL,EAAuBK,MAE7DrD,EAAKQ,OACE8E,EAAuBtF,EAAMuF,IAE7BF,EAAGxC,EAASC,EAAoBC,EAASC,KAK5D,QAASsC,GAAuBtF,EAAMqF,GA4ClC,QAASG,GAAyBC,EAAO5C,EAAS6C,GAI9C,GAAIC,IAAe,CACnB,OAAOD,GAAWE,MAAM,WACpB,MAAI/C,GAAQmC,SAAWa,GACnBF,GAAe,GACR,GAFX,SAIDG,KAAK,SAAUC,EAAMC,GACpBnD,EAAQoD,MACJ/E,KAAMgF,EACNC,MAAOV,EAAMW,aACbC,IAAKL,EAAOK,IACZC,IAAKN,EAAOO,QAEhBd,EAAMe,WAAaR,EAAOK,MAC3BvE,KAAK,WACJ,GAAI6D,EAGA,MADAc,IAAgB,EACTpB,EAAGxC,EAAS,MAAM,GAAQtB,cAAekE,GAGhD,IAAoC,IAAhCA,EAAMiB,eAAe1B,OAAc,CAGnC,GAAI2B,GAAQ5B,EAAoC/E,EAChD,OAAO4G,GAAwBnB,EAAMoB,kBAAmBhB,EAAwBhD,EAAQmC,OAAQ2B,EAAM1B,kBAAmB,SAAU6B,EAAmB/D,EAASC,GAG3J,MAFAH,GAAUA,EAAQkE,OAAOD,GACzB9D,EAAuBzB,cAAgB,KAChC8D,EAAGxC,EAAS8D,EAAM7D,mBAAoBC,EAASC,KAK1D,MADAyC,GAAMW,aAAeX,EAAMiB,eAAeM,QACnCxB,EAAyBC,EAAO5C,EAAS9D,EAAGoH,MAAMV,EAAMW,cAAca,QAAQ,UAMrG,QAASL,GAAwBM,EAAUC,EAAYC,EAAa/B,GAEhE,GAAIgC,MACAC,EAAa,EACbvE,GAAU,EACVwE,EAAevH,EAAKR,GACpBgI,EAAeN,CACnB,OAAOnI,GAAGW,YAAY,IAAKX,EAAG4C,SAAU,WACpC,GAAI8F,GAAQL,IAAgBnD,EAAAA,EAAWlF,EAAG4C,SAAS9B,MAAM,OAAO6H,MAAMR,GAAYnI,EAAG4C,SAAS9B,MAAM,OAAO8H,QAAQT,EAAUE,GAAa,GAAO,EACjJK,GAAM7B,MAAM,WACR,MAAI0B,KAAeH,GACfpE,GAAU,GACH,GAFX,SAID+C,KAAK,SAAU8B,GAGd,GADAJ,EAAeI,EAAOC,IAClBD,EAAOE,SAAWP,EAAtB,CAEA,GAAIQ,IACA7G,KAAM0G,EAAO1G,KACbiF,MAAOyB,EAAOzB,MACdE,IAAKuB,EAAOvB,IAEZuB,GAAO1G,OAASgF,EAAQ6B,EAAazB,IAAMsB,EAAOtB,IAAasB,EAAO1G,OAAS8G,IAAQD,EAAaE,KAAOL,EAAOK,KAEtH,IAAIzI,GAAKoI,EAAOzB,MAAQ,IAAMyB,EAAOvB,IACjC6B,EAAab,EAAU7H,EAC3B,IAAK0I,EAIE,CAEH,GAAIC,GAAaJ,EACbK,EAAe,WACf,OAAQF,EAAWhH,MACf,IAAKgF,GACD,OAAQiC,EAAWjH,MACf,IAAKgF,GACD,MAAOiC,EACX,KAAKH,GACD,MAAOK,GAAuBH,EAAYC,EAC9C,KAAKG,GACD,MAAOH,GAEf,KACJ,KAAKH,GACD,OAAQG,EAAWjH,MACf,IAAKgF,GACD,MAAOiC,EACX,KAAKH,GACD,MAAOO,GAAuBL,EAAYC,EAC9C,KAAKG,GACD,MAAOH,GAEf,KACJ,KAAKG,GACD,OAAQH,EAAWjH,MACf,IAAKgF,GACD,MAAOiC,EACX,KAAKH,GACD,MAAOE,EACX,KAAKI,GACD,MAAOJ,OAK3Bb,GAAU7H,GAAM4I,MAvChBf,GAAU7H,GAAMuI,IACdT,OAyCXxF,KAAK,WACJ,GAAIe,GAAUK,OAAOC,KAAKkE,GAAWmB,IAAI,SAAUnC,GAC/C,MAAOgB,GAAUhB,IAGrB,OADAI,GAAgB1D,EACTsC,EAAGxC,EAASE,GAAWhC,WAAYyG,MA5JlD,GAAIxH,EAAKe,YAAc,EAAG,CAEtB,GAAI4F,GAAQ5B,EAAoC/E,EAChD,OAAO4G,GAAwB5G,EAAKe,WAAY8E,EAAuBc,EAAM1B,kBAAmB,SAAUpC,EAASE,EAASC,GACxH,MAAOqC,GAAGxC,EAAS8D,EAAM7D,mBAAoBC,EAASC,KAK1D,GAA2B,OAAvBhD,EAAKuB,cAAwB,CAE7B,GAAImF,GAAiB3H,EAAG0J,OAAOC,OAAO,SAAUvC,GAC5C,MAAOA,GAAMwC,OAAO9H,aACrB2H,IAAI,SAAUrC,GACb,MAAOA,GAAMyC,MAEjB,IAA8B,IAA1BlC,EAAe1B,OAAc,MAAOxD,GAAQC,QAAQ4D,KAAO,MAAM,MACrE,IAAI9D,IACAmF,eAAgBA,EAChBN,aAAcM,EAAeM,QAC7BR,WAAY,KAEhB,OAAOzH,GAAG4C,SAASsF,QAAQ,OAAO4B,KAAK,SAAUC,GAC7CvH,EAAcsF,kBAAoBiC,GAAcA,EAAWjB,KAAO,CAClE,IAAInC,GAAa3G,EAAGoH,MAAM5E,EAAc6E,cAAca,QAAQ,MAC9D,OAAOzB,GAAyBjE,KAAmBmE,KAEpD,GAAI1F,EAAKuB,cAAciF,WAAY,CACtC,GAAId,GAAa3G,EAAGoH,MAAMnG,EAAKuB,cAAc6E,cAAcvG,MAAM,OAAO6H,MAAM1H,EAAKuB,cAAciF,WACjG,OAAOhB,GAAyBnF,EAAM0I,UAAU/I,EAAKuB,kBAAoBmE,GAEzE,GAAIA,GAAa3G,EAAGoH,MAAM5E,EAAc6E,cAAca,QAAQ,MAC9D,OAAOzB,GAAyBnF,EAAM0I,UAAU/I,EAAKuB,kBAAoBmE,GAiIrF,QAAShB,GAAmBsE,EAAeC,EAAgBlG,EAASmG,GAUhE,QAASC,GAAwBtG,GAC7B,MAAO9D,GAAGW,YAAY,KAAMX,EAAGqK,oBAAqB,WAChDvG,EAAQO,QAAQ,SAAUwE,GACtB,GAAIyB,IACArJ,KAAMA,EAAKR,GACX0B,KAAM0G,EAAO1G,KACbiF,MAAOyB,EAAOzB,MACdE,IAAKuB,EAAOvB,IAEZuB,GAAOtB,MAAK+C,EAAY/C,IAAMsB,EAAOtB,KACrCsB,EAAOK,OAAMoB,EAAYpB,KAAOL,EAAOK,MAC3ClJ,EAAGqK,oBAAoBrH,IAAIsH,OAEhCvH,KAAK,WACJ9B,EAAKgB,sBAAwBiI,EAC7BjJ,EAAKQ,SAIb,QAAS8I,GAAwBzG,EAASoG,GAKtC,MAAOlK,GAAGW,YAAY,KAAMX,EAAG0J,OAAOC,OAAO,SAAUvC,GACnD,MAAsB,aAAfA,EAAMyC,MAAsC,wBAAfzC,EAAMyC,MAAkCzC,EAAMwC,OAAO9H,aACzF,WA8CA,QAAS0I,GAAa1G,EAAS2G,GAG3B,GACIC,GAAoB,IACxB,IAAID,GAAU3G,EAAQmC,OAAQ,MAAOxD,GAAQC,QAAQ,KAGrD,KAFA,GAAImG,GAAS/E,EAAQ2G,GACjBrD,EAAQuD,EAAMjB,OAAOb,EAAOzB,OACzByB,GAAUA,EAAO1G,OAASgF,GAAQ,CAIrC,GAAIyD,IAAcxD,EAAMwC,OAAOiB,QAAQvG,OACvCoG,GAAoB,SAAU7B,EAAQzB,EAAOwD,GACzC,OAAQA,EAAaxD,EAAMpE,IAAI6F,EAAOtB,IAAKsB,EAAOvB,KAAOF,EAAMpE,IAAI6F,EAAOtB,MAAnE,SAA+E,kBAAmB,SAAUuD,GAC/G,MAAOF,GAAaxD,EAAMvF,IAAIgH,EAAOtB,IAAKsB,EAAOvB,KAAOF,EAAMvF,IAAIgH,EAAOtB,QAE/EsB,EAAQzB,EAAOwD,GACjB/B,EAAS/E,IAAU2G,GACf5B,IAAQzB,EAAQuD,EAAMjB,OAAOb,EAAOzB,QAG5C,GAAIsD,EAGA,MAAOA,GAAkB3H,KAAK,WAC1B,MAAO0H,GAAS3G,EAAQmC,OAASuE,EAAa1G,EAAS2G,GAAU,MAIzE,IAAI5B,EAAQ,CACR,GAAIA,EAAO1G,OAAS8G,EAChB,MAAO7B,GAAM2D,OAAOlC,EAAOvB,IAAKuB,EAAOK,MAAMnG,KAAK,WAE9C,MAAOyH,GAAa1G,EAAS2G,EAAS,IAI9C,IAAI5B,EAAO1G,OAASoH,EAChB,MAAOnC,GAAAA,UAAayB,EAAOvB,KAAKvE,KAAK,WAEjC,MAAOyH,GAAa1G,EAAS2G,EAAS,KAKlD,MAAOhI,GAAQC,QAAQ,MA3F3B,GAAIiI,GAAQrJ,EAAM0J,mBACdC,EAA6B,CACjCjL,GAAG4C,SAASsF,QAAQ,OAAO4B,KAAK,SAAUC,GAEtCkB,EAA6BlB,GAAcA,EAAWjB,KAAO,IAC9D/F,KAAK,WAIJ,MAFA4H,GAAM5B,OAAS9H,EAAKR,GAEbT,EAAGqK,oBAAoBvJ,MAAM,QAAQoK,OAAOjK,EAAKR,IAAI0K,YAC7DpI,KAAK,SAAUqI,GACd,MAAOZ,GAAaY,EAAoB,KACzCrI,KAAK,WACJ,MAAO/C,GAAGqK,oBAAoBvJ,MAAM,QAAQoK,OAAOjK,EAAKR,IAAjDT,cACR+C,KAAK,WAEJ,MAAOyH,GAAa1G,EAAS,KAC9Bf,KAAK,WAEJ,MAAO/C,GAAG4C,SAASsF,QAAQ,OAAO4B,SACnC/G,KAAK,SAAUgH,GACd,GAAIsB,GAAuBtB,GAAcA,EAAWjB,KAAO,CAW3D,IATA7H,EAAKgB,sBAAwBiI,EAC7BjJ,EAAKiB,oBAAoBgF,MAAOb,OAAQ6D,EAAgB9D,MAAOiF,IAC3DpK,EAAKe,aAAeiJ,IAIpBhK,EAAKe,WAAaqJ,GAGlBpK,EAAKiB,oBAAoB+D,OAAS,EAClC,IAAK,GAAIE,GAAIlF,EAAKiB,oBAAoB+D,OAAS,EAAGE,EAAI,IAAKA,EACvD,GAAIlF,EAAKe,YAAcf,EAAKiB,oBAAoBiE,GAAGC,MAAO,CACtDnF,EAAKiB,oBAAoBoJ,OAAO,EAAGnF,EACnC,OAIZlF,EAAKQ,WA5EjB,MAAOmC,GAAM+B,EAAoB,WAC7B,MAAKpF,MAEGyD,EAAUoG,EAAwBH,GAAiBM,EAAwBN,EAAeC,IAA3F,SAAkH,SAAUnF,GAE/H,MADAU,GAAiBV,GACVtC,EAAQiC,OAAOK,KAJAtC,EAAQiC,OAAO,sBAM1CpE,GAoIP,QAASmE,GAAuBmB,GAC5B,MAAKrF,MAMLgF,EAAwBK,EACxBE,EAAWvC,GAAG,aAAc,WACxB,GAAIgC,EAAuB,CACvB,GAAIA,EAAsBgG,MACtB,IAEIhG,EAAsBC,aACxB,MAAOsF,IAEbvF,EAAwB,aAI5BK,EAAa2F,MACbC,EAA0B5F,GAE1B6F,EAAyB7F,UApBrBA,EAAaJ,YAAYI,EAAaJ,cAyBlD,QAASgG,GAA0B5F,GAI/B,QAAS8F,KACDnG,IACApC,EAAeiC,EAASC,SACpBsG,EAAoBC,GAAiB,EACrCC,KAYZ,QAASA,KACAtG,IACLqG,GAAiB,EACjBD,GAAqB,EACrB9H,EAAsC5C,EAAM,SAAU6C,EAASC,EAAoBC,EAASC,GACnFsB,IACDzB,EAAQmC,OAAS,EACjBL,EAAa2F,MAAMzH,EAASC,EAAoBC,EAAS,WACrDG,OAAOC,KAAKH,GAAwBI,QAAQ,SAAUC,GAClDhD,EAAMiD,aAAatD,EAAMqD,EAASL,EAAuBK,MAE7DrD,EAAKQ,OAELoK,OAGJF,GAAqB,EACjBC,EAGAC,IAEA1I,EAAeiC,EAAS0G,YAlBpCjI,SAqBS4B,IA5Cb,GAAImG,GACJD,CAWA3L,GAAGuD,GAAG,UAAWmI,GAGjB5F,EAAWvC,GAAG,aAAc,WACxBvD,EAAGuD,GAAGO,QAAQiI,YAAYL,KA+B9BG,IAIJ,QAASJ,KAEL,QAASO,KACLnI,EAAsC5C,EAAM,SAAU6C,EAASC,EAAoBC,EAASC,GAIxF,QAASC,KACLC,OAAOC,KAAKH,GAAwBI,QAAQ,SAAUC,GAClDhD,EAAMiD,aAAatD,EAAMqD,EAASL,EAAuBK,MAE7DrD,EAAKQ,OAGT,QAASwK,GAAUrG,GACVL,IAILA,EAAwBK,EACpB5B,EAEAgI,KAGK/G,MAAMW,EAAaZ,QAAUY,EAAaZ,MAAQE,EAAAA,GAEnD/B,EAAeiC,EAAS0G,QACxB3G,WAAW,WACHI,IACApC,EAAeiC,EAASC,SACxB2G,MAELpG,EAAaZ,QAIhBc,EAAWN,WAAWJ,EAAS8G,UAK3C,QAASpH,GAAQC,EAAOC,IACfC,MAAMD,IAAkBE,EAAAA,EAARF,EACbO,IACAJ,WAAW,WACHI,IACApC,EAAeiC,EAASC,SACxB2G,MAELhH,GACH7B,EAAeiC,EAASE,mBAGxBG,EAAiBV,GAjD7B7E,EAAiBwF,KAAKzE,EAAKU,YAAavB,EAAKC,EAAS0D,EAAoB9C,EAAKgB,sBAAuB6B,EAASE,EAAS2B,EAAoBzB,EAAmB+H,EAAWnH,KAF9KjB,SAsDS4B,GAGTiC,EACAsE,IACOzG,IAA0BN,MAAMM,EAAsBP,QAAUO,EAAsBP,MAAQE,EAAAA,IACrG/B,EAAeiC,EAAS0G,QACxB3G,WAAW,WACHI,IACApC,EAAeiC,EAASC,SACxB2G,MAELzG,EAAsBP,QArjBjCc,EAAWvC,GAAG,aAAc,SAAUH,GAC7B6B,MAAM7B,IAAYD,EAAeC,IAG1C,IAAImC,EAEJ,OADApC,GAAeiC,EAAS+G,YACjBxI,IApHX,GAAIyI,GAAeC,EAAY1C,OAAO,SAAU2C,GAC5C,MAAOA,GAAKlM,MAAQA,GAExB,IAAIgM,EAAanG,OAAS,EAGtB,MAAOmG,GAAa,GAAGG,cAG3B,IAAIA,GAAiB7L,EAAoBL,GAAS0C,KAAK,SAAU9B,GAC7D,MAAOiC,GAAgBjC,KAGvB0D,EAAuB,KACvB6H,GAAe,EACf9E,GAAgB,EAChB5B,GACA1F,IAAKA,EACLiD,OAAQ+B,EAAS8G,QACjBK,eAAgBA,EAChBhJ,GAAIjC,EAAMmL,OAAO,KAAM,cACvBjH,WAAY,SAAUpC,EAAW2B,GAC7B,IAAKyH,EAAc,CACf1G,EAAWvC,GAAGiC,WAAW/B,KAAKL,EAAW2B,EACzC,IAAI2H,GAAML,EAAYM,QAAQ7G,EAC1B4G,IAAO,GAAGL,EAAYf,OAAOoB,EAAK,GAClC3H,GAASJ,GAAsBA,EAAqBI,GAE5DyH,GAAe,GAKvB,OAFAH,GAAYnF,KAAKpB,GAEVyG,EAypBX,QAAS3I,GAAMgJ,EAASC,EAAIC,GACxB,QAASC,KAeL,MAdKH,GAAQI,iBAUTJ,EAAQI,iBAAmBJ,EAAQI,iBAAiBjK,KAAK,WACrD,MAAOa,GAAMgJ,EAASC,EAAIC,KAV9BF,EAAQI,iBAAmB1L,EAAM2L,kBAAkB,WAC/C,MAAO3L,GAAMI,IAAI,WACb,MAAOmL,SAEZ9J,KAAK,SAAUmK,GAEd,aADON,GAAQI,iBACRE,IAORN,EAAQI,iBAGnB,MAAKF,GAOM9M,EAAGQ,gBAAkBsM,IAAe9M,EAAGQ,eAAeC,GAEtDsM,IAEAtK,EAAQiC,OAAO,GAAI7D,OAAM,wBAT5Bb,EAAGmN,SACIJ,IAEAtK,EAAQiC,OAAO,GAAI7D,OAAM,wBAU5C,QAASyI,GAAuBH,EAAYC,GACxC,GAAIgE,GAAe9L,EAAM0I,UAAUb,EAInC,OAHAhF,QAAOC,KAAKgF,EAAWF,MAAM7E,QAAQ,SAAUC,GAC3CC,EAAa6I,EAAa7F,IAAKjD,EAAS8E,EAAWF,KAAK5E,MAErD8I,EAGX,QAAS5D,GAAuBL,EAAYC,GACxC,GAAIgE,GAAe9L,EAAM0I,UAAUb,EAsBnC,OArBAhF,QAAOC,KAAKgF,EAAWF,MAAM7E,QAAQ,SAAUC,GAE3C,GAAI+I,IAAgB,CACpBlJ,QAAOC,KAAK+E,EAAWD,MAAMS,OAAO,SAAU2D,GAC1C,MAA6C,KAAtChJ,EAAQqI,QAAQW,EAAa,OACrCjJ,QAAQ,SAAUiJ,GACjB/I,EAAa6I,EAAaE,GAAahJ,EAAQiJ,OAAOD,EAAWrH,OAAS,GAAImD,EAAWF,KAAK5E,IAC9F+I,GAAgB,IAEfA,IAEDD,EAAalE,KAAK5E,GAAW8E,EAAWF,KAAK5E,IAIjDH,OAAOC,KAAK+E,EAAWD,MAAMS,OAAO,SAAU6D,GAC1C,MAA0C,KAAnCA,EAAQb,QAAQrI,EAAU,OAClCD,QAAQ,SAAUmJ,SACVJ,GAAaI,OAGrBJ,EAr7BX,GAAIf,MAGAlF,EAAS,EACT8B,EAAS,EACTM,EAAS,EAGTnE,EAAWrF,EAASqF,SAEpB0B,EAAwB,GAE5B9G,GAAGuD,GAAG,UAAW,SAAUkK,GAEvBnM,EAAMI,IAAI,WACW,YAAb+L,EAAItL,KAEJnC,EAAGsD,SAASrD,QAAQwN,EAAItN,aAAcsN,EAAIrN,IAAKqN,EAAIpN,SAAS0C,KAAK0K,EAAI/K,QAAS+K,EAAI/I,QAC9D,eAAb+I,EAAItL,KACXnC,EAAGsD,SAASkC,WAAWiI,EAAIrN,KAAK2C,KAAK0K,EAAI/K,QAAS+K,EAAI/I,QAClC,sBAAb+I,EAAItL,MAGXnC,EAAGsD,SAASC,GAAGC,cAAcC,KAAKgK,EAAIrK,UAAWqK,EAAIrN,SAKjEJ,EAAGuD,GAAG,UAAW,SAAUmK,GAEnBA,GAEA1N,EAAGY,WAAWE,MAAM,QAAQoK,OAAO,UAAUyC,IAAI,SAAU1M,GACvD,MAAOA,GAAKoC,SAAW+B,EAAS8G,SAAWjL,EAAKoC,SAAW+B,EAASW,QACrEgB,KAAK,SAAU6G,GAGdtM,EAAM2L,kBAAkB,WACpB3L,EAAMI,IAAI,WACN1B,EAAGsD,SAASrD,QAAQ2N,EAAoBhM,aAAcgM,EAAoBxN,IAAKwN,EAAoBxL,qBAOvHpC,EAAGuD,GAAG,QAAS,WAEX,MAAIvD,GAAGQ,gBAAkBR,EAAGQ,eAAeqN,SAEhC7N,EAAGY,WAAWE,MAAM,QAAQoK,OAAO,UAAUyC,IAAI,SAAU1M,GAC9D,MAAOA,GAAKoC,SAAW+B,EAAS8G,SAAWjL,EAAKoC,SAAW+B,EAASW,QACrEoF,QAAQ,SAAU2C,GAEjB,MAAIA,GAAqB7H,OAAS,EACvBxD,EAAQsL,IAAID,EAAqBrE,IAAI,SAAUxI,GAClD,MAAOjB,GAAGsD,SAASrD,QAAQgB,EAAKW,aAAcX,EAAKb,IAAKa,EAAKmB,aAAtDpC,SAAyE,SAAU4E,SAFlG,SANR,SAeD,GAEH5E,EAAGsD,YAEHtD,EAAGsD,SAAS0K,UAAY,SAAU5N,EAAKkG,GACnC,MAAItG,GAAGmN,SACI7L,EAAMI,IAAI,WACb,MAAO1B,GAAGY,WAAWE,MAAM,OAAOoK,OAAO9K,GAAKY,MAAM,SAAUC,GAC1D,MAAOA,GAAOA,EAAKoC,OAAS+B,EAAS8G,YAE1CnJ,KAAKuD,GAED7D,EAAQC,QAAQ3C,EAASqF,SAAS8G,SAASnJ,KAAKuD,IAI/DtG,EAAGsD,SAAS2K,KAAO,WACf,MAAOjO,GAAGY,WAAWE,MAAM,QAAQoK,OAAO,UAAUC,QAAQ,SAAU+C,GAClE,MAAOA,GAAEzE,IAAI,SAAUxI,GACnB,MAAOA,GAAKb,SAKxBJ,EAAGsD,SAASC,GAAKjC,EAAMmL,OAAOzM,GAAMwD,cAAe,SAEnDxD,EAAGsD,SAASkC,WAAa,SAAUpF,GAa/B,MAZIJ,GAAGQ,gBAAkBR,EAAGQ,eAAeqN,SACvCxB,EAAY1C,OAAO,SAAU2C,GACzB,MAAOA,GAAKlM,MAAQA,IACrBiE,QAAQ,SAAUiI,GACjBA,EAAK9G,WAAWJ,EAAS8G,WAG7BlM,EAAGY,WAAWE,MAAM,YAAY6H,MAAM,GAAG3H,MAAM,SAAUmN,GACrDnO,EAAGoO,YAAY,cAAgBhO,IAAKA,GAAO+N,EAAW1N,IAAM4N,WAAW,MAIxErO,EAAGY,WAAWE,MAAM,OAAOoK,OAAO9K,GAAKkO,OAAO,SAAUrN,GAC3DA,EAAKoC,OAAS+B,EAAS8G,WAI/BlM,EAAGsD,SAASrD,QAAU,SAAUE,EAAcC,EAAKC,GAC/CA,EAAUA,KACV,IAAIH,GAAmBH,EAASwO,oBAAoBpO,EAEpD,IAAID,EACA,MAAIF,GAAGmN,UAAYnN,EAAGQ,eAEdR,EAAGQ,eAAeqN,SAEX5N,EAAQC,EAAkBC,EAAcC,EAAKC,EAASL,EAAGQ,eAAeC,KAI/ET,EAAGoH,MAAM,cAActG,MAAM,YAAY6H,MAAM,GAAG3H,MAAM,SAAUmN,GAE9D,MAAOnO,GAAGoO,YAAY,WAAajO,aAAcA,EAAcC,IAAKA,EAAKC,QAASA,GAAW8N,EAAW1N,IAAM4N,WAAW,MAEtH5L,EAAQC,WAKZ,GAAID,GAAQ,SAAUC,EAASgC,GAClC1E,EAAGuD,GAAG,QAAS,WACX,MAAOjC,GAAMI,IAAI,WACb,MAAO1B,GAAGsD,SAASrD,QAAQE,EAAcC,EAAKC,GAAS0C,KAAKL,GAArD1C,SAAoE,SAAU4E,GAEjFF,EAAOE,UAQvB,MAAM,IAAI/D,OAAM,kBAAoBV,EAAe,iEAK/DH,EAAGsD,SAAHtD,UAAqB,SAAUI,GAG3B,MAAOJ,GAAGW,YAAY,KAAMX,EAAGY,WAAYZ,EAAG4C,SAAU5C,EAAGqK,oBAAqB,WAE5ErK,EAAGY,WAAWE,MAAM,OAAOoK,OAAO9K,GAAK+K,QAAQ,SAAUqD,GAIrD,GAAIA,EAAMvI,OAAS,EAAG,CAClB,GAAIwI,GAAUD,EAAM/E,IAAI,SAAUxI,GAC9B,MAAOA,GAAKR,IAOhB,OAAOT,GAAGY,WAAWE,MAAM,MAAM4N,MAAMD,GAAhCzO,YAAkD+C,KAAK,WAM1D,MAFA4L,GAAWC,mBAEJ5O,EAAGqK,oBAAoBvJ,MAAM,QAAQ4N,MAAMD,GAA3CzO,oBAO3BA,EAAGsD,SAASuL,gBAAkB,SAAUzO,GACpC,MAAOJ,GAAGY,WAAWE,MAAM,OAAOoK,OAAO9K,GAAKY,MAAM,SAAUC,GAC1D,MAAOjB,GAAG4C,SAAS9B,MAAM,OAAO6H,MAAM1H,EAAKe,YAAYmJ,aA+qB/DnL,EAAG8O,MAAQC,EAAS/O,EAAG8O,MAAO,SAAUE,GACpC,MAAO,YAIH,MAHA3C,GAAYhI,QAAQ,SAAUiI,GAC1BA,EAAK9G,eAEFwJ,EAAUC,MAAM5N,KAAM6N,aAKrClP,GAAG8B,WAAWC,SAASP,UAAUC,KAAO,WACpC,GAAI0N,GAAO9N,IACX,OAAOrB,GAAGW,YAAY,MAAOX,EAAGY,WAAY,WACxCZ,EAAGY,WAAWiB,IAAIsN,wCAx3B1BJ,GAAWzN,EAAMyN,SACjBtM,EAAUnB,EAAMmB,QAChB8B,EAAejD,EAAMiD,aACrBoK,EAAarN,EAAMqN,iBA87BvB5O,GAASqF,UACLW,MAAO,GACPmG,QAAS,EACTC,WAAY,EACZL,OAAQ,EACRzG,QAAS,EACTC,iBAAkB,GAGtBvF,EAASqP,aACLC,KAAM,QACNC,EAAK,UACLC,EAAK,aACLC,EAAK,SACLC,EAAK,UACLC,EAAK,oBAGT3P,EAASwO,uBAETxO,EAAS4P,qBAAuB,SAAU9F,EAAM3J,GAM5CH,EAASwO,oBAAoB1E,GAAQ3J,GAIzCoB,EAAMvB,SAAWA,EACjBuB,EAAMsO,OAAO1I,KAAKnH","file":"dist/dexie-syncable.min.js.map"} \ No newline at end of file diff --git a/dist/README.md b/dist/README.md deleted file mode 100644 index d28890585..000000000 --- a/dist/README.md +++ /dev/null @@ -1,51 +0,0 @@ -## Can't find dexie.js? -Dexie's dist files are no longer checked in to github except temporarily when tagging -a release version (just so that bower will continue to work). The reason for this is because -checking in dist files bloats the commit history and makes it error prone to contribute to the -repo. To support bower though, we have to continue checking in dist files when releasing, -but that is now handled by the release.sh script, who also removes them directly afterwards. - -If you still just want to download dexie.js to include in a test HTML page, go -to the following download site: - -### Download -[dexie.min.js](https://npmcdn.com/dexie/dist/dexie.min.js) - -[dexie.min.js.map](https://npmcdn.com/dexie/dist/dexie.min.js.map) - -### Typings -[dexie.d.ts](https://npmcdn.com/dexie/dist/dexie.d.ts) - -### Optional Stuff -[dexie.js (non-minified version)](https://npmcdn.com/dexie/dist/dexie.js) - -[dexie.js.map](https://npmcdn.com/dexie/dist/dexie.js.map) - -[dexie.min.js.gz (Minified and gzipped)](https://npmcdn.com/dexie/dist/dexie.min.js.gz) - -## Install from NPM -``` -npm install dexie --save -``` - -## Install from bower -``` -bower install dexie --save -``` - -## How to build -1. cd to dexie package -2. npm install -3. npm run build - -## Contributing to Dexie.js? - -Watch: -``` -npm run watch -``` - -Test: -``` -npm test -``` diff --git a/dist/dexie.d.ts b/dist/dexie.d.ts new file mode 100644 index 000000000..558b6b5d1 --- /dev/null +++ b/dist/dexie.d.ts @@ -0,0 +1,448 @@ +// Type definitions for Dexie v1.3.6-rc.1 +// Project: https://github.com/dfahlander/Dexie.js +// Definitions by: David Fahlander +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +interface Thenable { + then(onFulfilled: (value: R) => Thenable, onRejected: (error: any) => Thenable): Thenable; + then(onFulfilled: (value: R) => Thenable, onRejected?: (error: any) => U): Thenable; + then(onFulfilled: (value: R) => U, onRejected: (error: any) => Thenable): Thenable; + then(onFulfilled?: (value: R) => U, onRejected?: (error: any) => U): Thenable; +} + +declare type IndexableType = string | number | Date | Array; + +declare class Dexie { + constructor(databaseName: string, options?: { + addons?: Array<(db: Dexie) => void>, + autoOpen?: boolean, + indexedDB?: IDBDatabase, + IDBKeyRange?: IDBKeyRange + }); + + name: string; + tables: Dexie.Table[]; + verno: number; + + static addons: Array<(db: Dexie) => void>; + static version: number; + static semVer: string; + static currentTransaction: Dexie.Transaction; + + static getDatabaseNames(): Dexie.Promise>; + + static getDatabaseNames(onFulfilled: (value: Array) => Thenable): Dexie.Promise; + + static getDatabaseNames(onFulfilled: (value: Array) => U): Dexie.Promise; + + static override (origFunc:F, overridedFactory: (fn:any)=>any) : F; + + static getByKeyPath(obj: Object, keyPath: string): any; + + static setByKeyPath(obj: Object, keyPath: string, value: any): void; + + static delByKeyPath(obj: Object, keyPath: string): void; + + static shallowClone (obj: T): T; + + static deepClone(obj: T): T; + + static asap(fn: Function) : void; + + static maxKey: Array; + + static dump(error:any):string; + + static dependencies: { + indexedDB: IDBFactory, + IDBKeyRange: IDBKeyRange, + localStorage?: Storage + }; + + static default: Dexie; + + version(versionNumber: Number): Dexie.Version; + + on: { + (eventName: string, subscriber: Function, ...args : any[]): void; + (eventName: 'ready', subscriber: () => any, bSticky: boolean): void; + (eventName: 'error', subscriber: (error: any) => any): void; + (eventName: 'populate', subscriber: () => any): void; + (eventName: 'blocked', subscriber: () => any): void; + (eventName: 'versionchange', subscriber: (event: IDBVersionChangeEvent) => any): void; + ready: Dexie.DexieOnReadyEvent; + error: Dexie.DexieErrorEvent; + populate: Dexie.DexieEvent; + blocked: Dexie.DexieEvent; + versionchange: Dexie.DexieVersionChangeEvent; + } + + open(): Dexie.Promise; + + table(tableName: string): Dexie.Table; + + table(tableName: string): Dexie.Table; + + table(tableName: string): Dexie.Table; + + transaction(mode: string, table: Dexie.Table, scope: () => Thenable): Dexie.Promise; + + transaction(mode: string, table: Dexie.Table, table2: Dexie.Table, scope: () => Thenable): Dexie.Promise; + + transaction(mode: string, table: Dexie.Table, table2: Dexie.Table, table3: Dexie.Table, scope: () => Thenable): Dexie.Promise; + + transaction(mode: string, tables: Dexie.Table[], scope: () => Thenable): Dexie.Promise; + + transaction(mode: string, table: Dexie.Table, scope: () => U): Dexie.Promise; + + transaction(mode: string, table: Dexie.Table, table2: Dexie.Table, scope: () => U): Dexie.Promise; + + transaction(mode: string, table: Dexie.Table, table2: Dexie.Table, table3: Dexie.Table, scope: () => U): Dexie.Promise; + + transaction(mode: string, tables: Dexie.Table[], scope: () => U): Dexie.Promise; + + close(): void; + + delete(): Dexie.Promise; + + exists(name : string) : Dexie.Promise; + + isOpen(): boolean; + + hasFailed(): boolean; + + backendDB(): IDBDatabase; + + vip(scopeFunction: () => U): U; + + // Make it possible to touch physical class constructors where they reside - as properties on db instance. + // For example, checking if (x instanceof db.Table). Can't do (x instanceof Dexie.Table because it's just a virtual interface) + Table : new()=>Dexie.Table; + WhereClause: new()=>Dexie.WhereClause; + Version: new()=>Dexie.Version; + WriteableTable: new()=>Dexie.Table; + Transaction: new()=>Dexie.Transaction; + Collection: new()=>Dexie.Collection; + WriteableCollection: new()=>Dexie.Collection; +} + +declare module Dexie { + + class Promise implements Thenable { + constructor(callback: (resolve: (value?: Thenable) => void, reject: (error?: any) => void) => void); + + constructor(callback: (resolve: (value?: R) => void, reject: (error?: any) => void) => void); + + then(onFulfilled: (value: R) => Thenable, onRejected: (error: any) => Thenable): Promise; + + then(onFulfilled: (value: R) => Thenable, onRejected?: (error: any) => U): Promise; + + then(onFulfilled: (value: R) => U, onRejected: (error: any) => Thenable): Promise; + + then(onFulfilled?: (value: R) => U, onRejected?: (error: any) => U): Promise; + + catch(onRejected: (error: any) => Thenable): Promise; + + catch(onRejected: (error: any) => U): Promise; + + catch(ExceptionType: (new() => ET), onRejected: (error: ET) => Promise): Promise; + + catch(ExceptionType: (new() => ET), onRejected: (error: ET) => U): Promise; + + catch(errorName: string, onRejected: (error: {name: string}) => Promise): Promise; + + catch(errorName: string, onRejected: (error: {name: string}) => U): Promise; + + finally(onFinally: () => any): Promise; + + onuncatched: () => any; + } + + module Promise { + function resolve(value?: Thenable): Promise; + + function resolve(value?: R): Promise; + + function reject(error: any): Promise; + + function all(promises: Thenable[]): Promise; + + function all(...promises: Thenable[]): Promise; + + function race(promises: Thenable[]): Promise; + + function newPSD(scope: () => R): R; + + var PSD: any; + + var on: { + (eventName: string, subscriber: Function): void; + (eventName: 'error', subscriber: (error: any) => any): void; + error: DexieErrorEvent; + } + } + + + interface Version { + stores(schema: { [key: string]: string }): Version; + upgrade(fn: (trans: Transaction) => void): Version; + } + + interface Transaction { + active: boolean; + db: Dexie; + mode: string; + idbtrans: IDBTransaction; + tables: { [type: string]: Table }; + storeNames: Array; + on: { + (eventName: string, subscriber: () => any): void; + (eventName: 'complete', subscriber: () => any): void; + (eventName: 'abort', subscriber: () => any): void; + (eventName: 'error', subscriber: (error:any) => any): void; + complete: DexieEvent; + abort: DexieEvent; + error: DexieEvent; + } + abort(): void; + table(tableName: string): Table; + table(tableName: string): Table; + table(tableName: string): Table; + } + + interface DexieEvent { + subscribe(fn: () => any): void; + unsubscribe(fn: () => any): void; + fire(): any; + } + + interface DexieErrorEvent { + subscribe(fn: (error: any) => any): void; + unsubscribe(fn: (error: any) => any): void; + fire(error: any): any; + } + + interface DexieVersionChangeEvent { + subscribe(fn: (event: IDBVersionChangeEvent) => any): void; + unsubscribe(fn: (event: IDBVersionChangeEvent) => any): void; + fire(event: IDBVersionChangeEvent): any; + } + + interface DexieOnReadyEvent { + subscribe(fn: () => any, bSticky: boolean): void; + unsubscribe(fn: () => any): void; + fire(): any; + } + + interface Table { + name: string; + schema: TableSchema; + hook: { + (eventName: string, subscriber: () => any): void; + creating: DexieEvent; + reading: DexieEvent; + updating: DexieEvent; + deleting: DexieEvent; + } + + get(key: Key): Promise; + where(index: string): WhereClause; + + filter(fn: (obj: T) => boolean): Collection; + + count(): Promise; + count(onFulfilled: (value: number) => Thenable): Promise; + count(onFulfilled: (value: number) => U): Promise; + + offset(n: number): Collection; + + limit(n: number): Collection; + + each(callback: (obj: T, cursor: IDBCursor) => any): Promise; + + toArray(): Promise>; + toArray(onFulfilled: (value: Array) => Thenable): Promise; + toArray(onFulfilled: (value: Array) => U): Promise; + + toCollection(): Collection; + orderBy(index: string): Collection; + reverse(): Collection; + mapToClass(constructor: Function): Function; + add(item: T, key?: Key): Promise; + update(key: Key, changes: { [keyPath: string]: any }): Promise; + put(item: T, key?: Key): Promise; + delete(key: Key): Promise; + clear(): Promise; + bulkAdd(items: T[], keys?: IndexableType[]): Promise; + bulkPut(items: T[], keys?: IndexableType[]): Promise; + bulkDelete(keys: IndexableType[]) : Promise; + } + + interface WhereClause { + above(key: IndexableType): Collection; + aboveOrEqual(key: IndexableType): Collection; + anyOf(keys: IndexableType[]): Collection; + anyOf(...keys: IndexableType[]): Collection; + anyOfIgnoreCase(keys: string[]): Collection; + anyOfIgnoreCase(...keys: string[]): Collection; + below(key: IndexableType): Collection; + belowOrEqual(key: IndexableType): Collection; + between(lower: IndexableType, upper: IndexableType, includeLower?: boolean, includeUpper?: boolean): Collection; + equals(key: IndexableType): Collection; + equalsIgnoreCase(key: string): Collection; + inAnyRange(ranges: Array): Collection; + startsWith(key: string): Collection; + startsWithAnyOf(prefixes: string[]): Collection; + startsWithAnyOf(...prefixes: string[]): Collection; + startsWithIgnoreCase(key: string): Collection; + startsWithAnyOfIgnoreCase(prefixes: string[]): Collection; + startsWithAnyOfIgnoreCase(...prefixes: string[]): Collection; + noneOf(keys: Array): Collection; + notEqual(key: IndexableType): Collection; + } + + interface Collection { + and(filter: (x: T) => boolean): Collection; + clone(props?: Object): Collection; + count(): Promise; + count(onFulfilled: (value: number) => Thenable): Promise; + count(onFulfilled: (value: number) => U): Promise; + distinct(): Collection; + each(callback: (obj: T, cursor: IDBCursor) => any): Promise; + eachKey(callback: (key: Key, cursor: IDBCursor) => any): Promise; + eachUniqueKey(callback: (key: Key, cursor: IDBCursor) => any): Promise; + filter(filter: (x: T) => boolean): Collection; + first(): Promise; + first(onFulfilled: (value: T) => Thenable): Promise; + first(onFulfilled: (value: T) => U): Promise; + keys(): Promise; + keys(onFulfilled: (value: Key[]) => Thenable): Promise; + keys(onFulfilled: (value: Key[]) => U): Promise; + last(): Promise; + last(onFulfilled: (value: T) => Thenable): Promise; + last(onFulfilled: (value: T) => U): Promise; + limit(n: number): Collection; + offset(n: number): Collection; + or(indexOrPrimayKey: string): WhereClause; + raw(): Collection; + reverse(): Collection; + sortBy(keyPath: string): Promise; + sortBy(keyPath: string, onFulfilled: (value: T[]) => Thenable): Promise; + sortBy(keyPath: string, onFulfilled: (value: T[]) => U): Promise; + toArray(): Promise>; + toArray(onFulfilled: (value: Array) => Thenable): Promise; + toArray(onFulfilled: (value: Array) => U): Promise; + uniqueKeys(): Promise; + uniqueKeys(onFulfilled: (value: Key[]) => Thenable): Promise; + uniqueKeys(onFulfilled: (value: Key[]) => U): Promise; + until(filter: (value: T) => boolean, includeStopEntry?: boolean): Collection; + // WriteableCollection: + delete(): Promise; + modify(changeCallback: (obj: T, ctx:{value: T}) => void): Promise; + modify(changes: { [keyPath: string]: any } ): Promise; + } + + interface TableSchema { + name: string; + primKey: IndexSpec; + indexes: IndexSpec[]; + mappedClass: Function; + } + + interface IndexSpec { + name: string; + keyPath: string | Array; + unique: boolean; + multi: boolean; + auto: boolean; + compound: boolean; + src: string; + } + + // Make it possible to touch physical classes as they are + var TableSchema: new()=>TableSchema, + IndexSpec: new()=>IndexSpec, + Events: any; // Too complex to define correctly right now. + + // errnames - handy spellcheck in switch (error.name) {} cases. + var errnames: { + // Error names generated by indexedDB: + Unknown: 'UnknownError'; + Constraint: 'ConstraintError'; + Data: 'DataError'; + TransactionInactive: 'TransactionInactiveError'; + ReadOnly: 'ReadOnlyError'; + Version: 'VersionError'; + NotFound: 'NotFoundError'; + InvalidState: 'InvalidStateError'; + InvalidAccess: 'InvalidAccessError'; + Abort: 'AbortError'; + Timeout: 'TimeoutError'; + QuotaExceeded: 'QuotaExceededError'; + Syntax: 'SyntaxError'; + DataClone: 'DataCloneError'; + + // Dexie-specific error names: + Modify: 'ModifyError'; + OpenFailed: 'OpenFailedError'; + VersionChange: 'VersionChangeError'; + Schema: 'SchemaError'; + Upgrade: 'UpgradeError'; + InvalidTable: 'InvalidTableError'; + MissingAPI: 'MissingAPIError'; + NoSuchDatabase: 'NoSuchDatabaseError'; + InvalidArgument: 'InvalidArgumentError'; + SubTransaction: 'Error'; + Unsupported: 'UnsupportedError'; + Internal: 'InternalError'; + DatabaseClosed: 'DatabaseClosedError'; + }; + + class DexieError extends Error { + name: string; + message: string; + stack: string; + inner: any; + + constructor (name?:string, message?:string); + toString(): string; + dump(): string; + } + + class ModifyError extends DexieError{ + constructor (msg?:string, failures?: any[], successCount?: number, failedKeys?: IndexableType[]); + failures: Array; + failedKeys: Array; + successCount: number; + } + + class OpenFailedError extends DexieError {constructor (msg?: string, inner?: Object);constructor (inner: Object);} + class VersionChangeError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class SchemaError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class UpgradeError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class InvalidTableError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class MissingAPIError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class NoSuchDatabaseError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class InvalidArgumentError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class SubTransactionError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class UnsupportedError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class InternalError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class DatabaseClosedError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class IncompatiblePromiseError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class UnknownError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class ConstraintError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class DataError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class TransactionInactiveError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class ReadOnlyError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class VersionError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class NotFoundError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class InvalidStateError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class InvalidAccessError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class AbortError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class TimeoutError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class QuotaExceededError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class SyntaxError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} + class DataCloneError extends DexieError {constructor (msg?: string, inner?: Object); constructor (inner: Object);} +} + +export default Dexie; diff --git a/dist/dexie.js b/dist/dexie.js new file mode 100644 index 000000000..d1486befd --- /dev/null +++ b/dist/dexie.js @@ -0,0 +1,4187 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + global.Dexie = factory(); +}(this, function () { 'use strict'; + + function nop() {} + function mirror(val) { + return val; + } + function pureFunctionChain(f1, f2) { + // Enables chained events that takes ONE argument and returns it to the next function in chain. + // This pattern is used in the hook("reading") event. + if (f1 == null || f1 === mirror) return f2; + return function (val) { + return f2(f1(val)); + }; + } + + function callBoth(on1, on2) { + return function () { + on1.apply(this, arguments); + on2.apply(this, arguments); + }; + } + + function hookCreatingChain(f1, f2) { + // Enables chained events that takes several arguments and may modify first argument by making a modification and then returning the same instance. + // This pattern is used in the hook("creating") event. + if (f1 === nop) return f2; + return function () { + var res = f1.apply(this, arguments); + if (res !== undefined) arguments[0] = res; + var onsuccess = this.onsuccess, + // In case event listener has set this.onsuccess + onerror = this.onerror; // In case event listener has set this.onerror + this.onsuccess = null; + this.onerror = null; + var res2 = f2.apply(this, arguments); + if (onsuccess) this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess; + if (onerror) this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror; + return res2 !== undefined ? res2 : res; + }; + } + + function hookDeletingChain(f1, f2) { + if (f1 === nop) return f2; + return function () { + f1.apply(this, arguments); + var onsuccess = this.onsuccess, + // In case event listener has set this.onsuccess + onerror = this.onerror; // In case event listener has set this.onerror + this.onsuccess = this.onerror = null; + f2.apply(this, arguments); + if (onsuccess) this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess; + if (onerror) this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror; + }; + } + + function hookUpdatingChain(f1, f2) { + if (f1 === nop) return f2; + return function () { + var res = f1.apply(this, arguments); + extend(arguments[0], res); // If f1 returns new modifications, extend caller's modifications with the result before calling next in chain. + var onsuccess = this.onsuccess, + // In case event listener has set this.onsuccess + onerror = this.onerror; // In case event listener has set this.onerror + this.onsuccess = null; + this.onerror = null; + var res2 = f2.apply(this, arguments); + if (onsuccess) this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess; + if (onerror) this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror; + return res === undefined ? res2 === undefined ? undefined : res2 : extend(res, res2); + }; + } + + function stoppableEventChain(f1, f2) { + // Enables chained events that may return false to stop the event chain. + if (f1 === nop) return f2; + return function () { + if (f1.apply(this, arguments) === false) return false; + return f2.apply(this, arguments); + }; + } + + function reverseStoppableEventChain(f1, f2) { + if (f1 === nop) return f2; + return function () { + if (f2.apply(this, arguments) === false) return false; + return f1.apply(this, arguments); + }; + } + + function promisableChain(f1, f2) { + if (f1 === nop) return f2; + return function () { + var res = f1.apply(this, arguments); + if (res && typeof res.then === 'function') { + var thiz = this, + args = arguments; + return res.then(function () { + return f2.apply(thiz, args); + }); + } + return f2.apply(this, arguments); + }; + } + + var keys = Object.keys; + var isArray = Array.isArray; + var _global = typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : global; + + function extend(obj, extension) { + if (typeof extension !== 'object') return obj; + keys(extension).forEach(function (key) { + obj[key] = extension[key]; + }); + return obj; + } + + function extendProto(proto, extension) { + if (typeof extension === 'function') extension = extension(Object.getPrototypeOf(proto)); + keys(extension).forEach(function (key) { + setProp(proto, key, extension[key]); + }); + } + + function setProp(obj, prop, functionOrGetSet, options) { + Object.defineProperty(obj, prop, extend(typeof functionOrGetSet.get === 'function' ? { get: functionOrGetSet.get, set: functionOrGetSet.set, configurable: true } : { value: functionOrGetSet, configurable: true, writable: true }, options)); + } + + function derive(Child) { + return { + from: function (Parent) { + Child.prototype = Object.create(Parent.prototype); + setProp(Child.prototype, "constructor", Child); + return { + extend: extendProto.bind(null, Child.prototype) + }; + } + }; + } + + var _slice = [].slice; + function slice(args, start, end) { + return _slice.call(args, start, end); + } + + function override(origFunc, overridedFactory) { + return overridedFactory(origFunc); + } + + function doFakeAutoComplete(fn) { + var to = setTimeout(fn, 1000); + clearTimeout(to); + } + + function assert(b) { + if (!b) throw new exceptions.Internal("Assertion failed"); + } + + function asap(fn) { + if (_global.setImmediate) setImmediate(fn);else setTimeout(fn, 0); + } + + function miniTryCatch(fn, onerror) { + try { + fn(); + } catch (ex) { + onerror && onerror(ex); + } + } + + function messageAndStack(e) { + var stack = e && e.stack; + return stack ? stack.indexOf(e + '') > 0 ? stack : e + ". " + stack : e; + } + + function stack(error) { + if (error.stack) return error; // Provided error already has a stack + try { + var err = new Error(error.message || error); // In Chrome, stack is generated here. + if (err.stack) { + error.stack = err.stack;return error; + } // If stack was generated, set it. + // No stack. Other browsers only put the stack if we throw the error: + throw err; + } catch (e) { + error.stack = e.stack; + } + return error; + } + + function fail(err) { + // Get the call stack and return a rejected promise. + return Promise.reject(stack(err)); + } + + function getByKeyPath(obj, keyPath) { + // http://www.w3.org/TR/IndexedDB/#steps-for-extracting-a-key-from-a-value-using-a-key-path + if (obj.hasOwnProperty(keyPath)) return obj[keyPath]; // This line is moved from last to first for optimization purpose. + if (!keyPath) return obj; + if (typeof keyPath !== 'string') { + var rv = []; + for (var i = 0, l = keyPath.length; i < l; ++i) { + var val = getByKeyPath(obj, keyPath[i]); + rv.push(val); + } + return rv; + } + var period = keyPath.indexOf('.'); + if (period !== -1) { + var innerObj = obj[keyPath.substr(0, period)]; + return innerObj === undefined ? undefined : getByKeyPath(innerObj, keyPath.substr(period + 1)); + } + return undefined; + } + + function setByKeyPath(obj, keyPath, value) { + if (!obj || keyPath === undefined) return; + if ('isFrozen' in Object && Object.isFrozen(obj)) return; + if (typeof keyPath !== 'string' && 'length' in keyPath) { + assert(typeof value !== 'string' && 'length' in value); + for (var i = 0, l = keyPath.length; i < l; ++i) { + setByKeyPath(obj, keyPath[i], value[i]); + } + } else { + var period = keyPath.indexOf('.'); + if (period !== -1) { + var currentKeyPath = keyPath.substr(0, period); + var remainingKeyPath = keyPath.substr(period + 1); + if (remainingKeyPath === "") { + if (value === undefined) delete obj[currentKeyPath];else obj[currentKeyPath] = value; + } else { + var innerObj = obj[currentKeyPath]; + if (!innerObj) innerObj = obj[currentKeyPath] = {}; + setByKeyPath(innerObj, remainingKeyPath, value); + } + } else { + if (value === undefined) delete obj[keyPath];else obj[keyPath] = value; + } + } + } + + function delByKeyPath(obj, keyPath) { + if (typeof keyPath === 'string') setByKeyPath(obj, keyPath, undefined);else if ('length' in keyPath) [].map.call(keyPath, function (kp) { + setByKeyPath(obj, kp, undefined); + }); + } + + function shallowClone(obj) { + var rv = {}; + for (var m in obj) { + if (obj.hasOwnProperty(m)) rv[m] = obj[m]; + } + return rv; + } + + function deepClone(any) { + if (!any || typeof any !== 'object') return any; + var rv; + if (isArray(any)) { + rv = []; + for (var i = 0, l = any.length; i < l; ++i) { + rv.push(deepClone(any[i])); + } + } else if (any instanceof Date) { + rv = new Date(); + rv.setTime(any.getTime()); + } else { + rv = any.constructor ? Object.create(any.constructor.prototype) : {}; + for (var prop in any) { + if (any.hasOwnProperty(prop)) { + rv[prop] = deepClone(any[prop]); + } + } + } + return rv; + } + + function getObjectDiff(a, b, rv, prfx) { + // Compares objects a and b and produces a diff object. + rv = rv || {}; + prfx = prfx || ''; + for (var prop in a) { + if (a.hasOwnProperty(prop)) { + if (!b.hasOwnProperty(prop)) rv[prfx + prop] = undefined; // Property removed + else { + var ap = a[prop], + bp = b[prop]; + if (typeof ap === 'object' && typeof bp === 'object') getObjectDiff(ap, bp, rv, prfx + prop + ".");else if (ap !== bp) rv[prfx + prop] = b[prop]; // Primitive value changed + } + } + }for (prop in b) { + if (b.hasOwnProperty(prop) && !a.hasOwnProperty(prop)) { + rv[prfx + prop] = b[prop]; // Property added + } + }return rv; + } + + var dexieErrorNames = ['Modify', 'Bulk', 'OpenFailed', 'VersionChange', 'Schema', 'Upgrade', 'InvalidTable', 'MissingAPI', 'NoSuchDatabase', 'InvalidArgument', 'SubTransaction', 'Unsupported', 'Internal', 'DatabaseClosed', 'IncompatiblePromise']; + + var idbDomErrorNames = ['Unknown', 'Constraint', 'Data', 'TransactionInactive', 'ReadOnly', 'Version', 'NotFound', 'InvalidState', 'InvalidAccess', 'Abort', 'Timeout', 'QuotaExceeded', 'Syntax', 'DataClone']; + + var errorList = dexieErrorNames.concat(idbDomErrorNames); + + var defaultTexts = { + VersionChanged: "Database version changed by other database connection", + DatabaseClosed: "Database has been closed", + IncompatiblePromise: "Incompatible Promise used in transaction scope. See http://tinyurl.com/znyqjqc" + }; + + // + // DexieError - base class of all out exceptions. + // + function DexieError(name, msg) { + // Reason we don't use ES6 classes is because: + // 1. It bloats transpiled code and increases size of minified code. + // 2. It doesn't give us much in this case. + // 3. It would require sub classes to call super(), which + // is not needed when deriving from Error. + this.name = name; + this.message = msg; + } + derive(DexieError).from(Error).extend({ + dump: function () { + return messageAndStack(this); + } + }); + + function getMultiErrorMessage(msg, failures) { + return msg + ". Errors: " + failures.map(function (f) { + return f.toString(); + }).filter(function (v, i, s) { + return s.indexOf(v) === i; + }) // Only unique error strings + .join('\n'); + } + // + // ModifyError - thrown in WriteableCollection.modify() + // Specific constructor because it contains members failures and failedKeys. + // + function ModifyError(msg, failures, successCount, failedKeys) { + this.name = "ModifyError"; + this.failures = failures; + this.failedKeys = failedKeys; + this.successCount = successCount; + this.message = getMultiErrorMessage(msg, failures); + } + derive(ModifyError).from(DexieError); + + function BulkError(msg, failures) { + this.name = "BulkError"; + this.failures = failures; + this.message = getMultiErrorMessage(msg, failures); + } + derive(BulkError).from(DexieError); + + // + // + // Dynamically generate error names and exception classes based + // on the names in errorList. + // + // + + // Map of {ErrorName -> ErrorName + "Error"} + var errnames = errorList.reduce(function (obj, name) { + return obj[name] = name + "Error", obj; + }, {}); + + // Need an alias for DexieError because we're gonna create subclasses with the same name. + var BaseException = DexieError; + // Map of {ErrorName -> exception constructor} + var exceptions = errorList.reduce(function (obj, name) { + // Let the name be "DexieError" because this name may + // be shown in call stack and when debugging. DexieError is + // the most true name because it derives from DexieError, + // and we cannot change Function.name programatically without + // dynamically create a Function object, which would be considered + // 'eval-evil'. + var fullName = name + "Error"; + function DexieError(msgOrInner, inner) { + this.name = fullName; + if (typeof msgOrInner === 'string') { + this.message = msgOrInner; + this.inner = inner || null; + } else if (typeof msgOrInner === 'object') { + this.message = msgOrInner.name + ' ' + msgOrInner.message; + this.inner = msgOrInner; + } else { + this.message = defaultTexts[name]; + this.inner = null; + } + } + derive(DexieError).from(BaseException); + obj[name] = DexieError; + return obj; + }, {}); + + // Use ECMASCRIPT standard exceptions where applicable: + exceptions.Syntax = SyntaxError; + exceptions.Type = TypeError; + exceptions.Range = RangeError; + + var exceptionMap = idbDomErrorNames.reduce(function (obj, name) { + obj[name + "Error"] = exceptions[name]; + return obj; + }, {}); + + function mapError(domError, message) { + var rv = domError; + if (!(domError instanceof DexieError) && domError.name && exceptionMap[domError.name]) { + rv = new exceptionMap[domError.name](message || domError.message, domError); + if (domError.stack) rv.stack = domError.stack; + } + return rv; + } + + var fullNameExceptions = errorList.reduce(function (obj, name) { + if (["Syntax", "Type", "Range"].indexOf(name) === -1) obj[name + "Error"] = exceptions[name]; + return obj; + }, {}); + + fullNameExceptions.ModifyError = ModifyError; + fullNameExceptions.DexieError = DexieError; + fullNameExceptions.BulkError = BulkError; + + function Events(ctx) { + var args = arguments; + var evs = {}; + var rv = function (eventName, subscriber) { + if (subscriber) { + // Subscribe + var args = slice(arguments, 1); + var ev = evs[eventName]; + ev.subscribe.apply(ev, args); + return ctx; + } else if (typeof eventName === 'string') { + // Return interface allowing to fire or unsubscribe from event + return evs[eventName]; + } + }; + rv.addEventType = add; + + function add(eventName, chainFunction, defaultFunction) { + if (isArray(eventName)) return addEventGroup(eventName); + if (typeof eventName === 'object') return addConfiguredEvents(eventName); + if (!chainFunction) chainFunction = stoppableEventChain; + if (!defaultFunction) defaultFunction = nop; + + var context = { + subscribers: [], + fire: defaultFunction, + subscribe: function (cb) { + context.subscribers.push(cb); + context.fire = chainFunction(context.fire, cb); + }, + unsubscribe: function (cb) { + context.subscribers = context.subscribers.filter(function (fn) { + return fn !== cb; + }); + context.fire = context.subscribers.reduce(chainFunction, defaultFunction); + } + }; + evs[eventName] = rv[eventName] = context; + return context; + } + + function addConfiguredEvents(cfg) { + // events(this, {reading: [functionChain, nop]}); + keys(cfg).forEach(function (eventName) { + var args = cfg[eventName]; + if (isArray(args)) { + add(eventName, cfg[eventName][0], cfg[eventName][1]); + } else if (args === 'asap') { + // 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 + // enabling that any exception that occur wont disturb the initiator and also not nescessary be catched and forgotten. + var context = add(eventName, null, function fire() { + var args = arguments; + context.subscribers.forEach(function (fn) { + asap(function fireEvent() { + fn.apply(_global, args); + }); + }); + }); + context.subscribe = function (fn) { + // Change how subscribe works to not replace the fire function but to just add the subscriber to subscribers + if (context.subscribers.indexOf(fn) === -1) context.subscribers.push(fn); + }; + context.unsubscribe = function (fn) { + // Change how unsubscribe works for the same reason as above. + var idxOfFn = context.subscribers.indexOf(fn); + if (idxOfFn !== -1) context.subscribers.splice(idxOfFn, 1); + }; + } else throw new exceptions.InvalidArgument("Invalid event config"); + }); + } + + function addEventGroup(eventGroup) { + // promise-based event group (i.e. we promise to call one and only one of the events in the pair, and to only call it once. + var done = false; + eventGroup.forEach(function (name) { + add(name).subscribe(checkDone); + }); + function checkDone() { + if (done) return false; + done = true; + } + } + + for (var i = 1, l = args.length; i < l; ++i) { + add(args[i]); + } + + return rv; + } + + // + // Promise Class + // + // A variant of promise-light (https://github.com/taylorhakes/promise-light) by https://github.com/taylorhakes - an A+ and ECMASCRIPT 6 compliant Promise implementation. + // + // Modified by David Fahlander to be indexedDB compliant (See discussion: https://github.com/promises-aplus/promises-spec/issues/45) . + // This implementation will not use setTimeout or setImmediate when it's not needed. The behavior is 100% Promise/A+ compliant since + // the caller of new Promise() can be certain that the promise wont be triggered the lines after constructing the promise. We fix this by using the member variable constructing to check + // whether the object is being constructed when reject or resolve is called. If so, the use setTimeout/setImmediate to fulfill the promise, otherwise, we know that it's not needed. + // + // This topic was also discussed in the following thread: https://github.com/promises-aplus/promises-spec/issues/45 and this implementation solves that issue. + // + // Another feature with this Promise implementation is that reject will return false in case no one catched the reject call. This is used + // to stopPropagation() on the IDBRequest error event in case it was catched but not otherwise. + // + // Also, the event new Promise().onuncatched is called in case no one catches a reject call. This is used for us to manually bubble any request + // errors to the transaction. We must not rely on IndexedDB implementation to do this, because it only does so when the source of the rejection + // is an error event on a request, not in case an ordinary exception is thrown. + + var _asap = _global.setImmediate || function (fn) { + var args = slice(arguments, 1); + + // If not FF13 and earlier failed, we could use this call here instead: setTimeout.call(this, [fn, 0].concat(arguments)); + setTimeout(function () { + fn.apply(_global, args); + }, 0); + }; + + doFakeAutoComplete(function () { + // Simplify the job for VS Intellisense. This piece of code is one of the keys to the new marvellous intellisense support in Dexie. + _asap = asap$1 = enqueueImmediate = function (fn) { + var args = arguments;setTimeout(function () { + fn.apply(_global, slice(args, 1)); + }, 0); + }; + }); + + var asap$1 = _asap; + var isRootExecution = true; + var operationsQueue = []; + var tickFinalizers = []; + var enqueueImmediate = function (fn) { + operationsQueue.push([fn, slice(arguments, 1)]); + }; + + function executeOperationsQueue() { + var queue = operationsQueue; + operationsQueue = []; + for (var i = 0, l = queue.length; i < l; ++i) { + var item = queue[i]; + item[0].apply(_global, item[1]); + } + } + + function Promise(fn) { + if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new'); + if (typeof fn !== 'function') throw new TypeError('not a function'); + this._state = null; // null (=pending), false (=rejected) or true (=resolved) + this._value = null; // error or result + this._deferreds = []; + this._catched = false; // for onuncatched + //this._id = ++PromiseID; + var self = this; + var constructing = true; + this._PSD = Promise.PSD; + + try { + doResolve(this, fn, function (data) { + if (constructing) asap$1(resolve, self, data);else resolve(self, data); + }, function (reason) { + if (constructing) { + asap$1(reject, self, reason); + return false; + } else { + return reject(self, reason); + } + }); + } finally { + constructing = false; + } + } + + function handle(self, deferred) { + if (self._state === null) { + self._deferreds.push(deferred); + return; + } + + var cb = self._state ? deferred.onFulfilled : deferred.onRejected; + if (cb === null) { + // This Deferred 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() + return (self._state ? deferred.resolve : deferred.reject)(self._value); + } + var ret, + isRootExec = isRootExecution; + isRootExecution = false; + asap$1 = enqueueImmediate; + try { + var outerPSD = Promise.PSD; + Promise.PSD = self._PSD; + ret = cb(self._value); + if (!self._state && (!ret || typeof ret.then !== 'function' || ret._state !== false)) setCatched(self); // Caller did 'return Promise.reject(err);' - don't regard it as catched! + deferred.resolve(ret); + } catch (e) { + deferred.reject(e); + } finally { + Promise.PSD = outerPSD; + if (isRootExec) { + do { + while (operationsQueue.length > 0) { + executeOperationsQueue(); + }var finalizer = tickFinalizers.pop(); + if (finalizer) try { + finalizer(); + } catch (e) {} + } while (tickFinalizers.length > 0 || operationsQueue.length > 0); + asap$1 = _asap; + isRootExecution = true; + } + } + } + + function _rootExec(fn) { + var isRootExec = isRootExecution; + isRootExecution = false; + asap$1 = enqueueImmediate; + try { + return fn(); + } finally { + if (isRootExec) { + do { + while (operationsQueue.length > 0) { + executeOperationsQueue(); + }var finalizer = tickFinalizers.pop(); + if (finalizer) try { + finalizer(); + } catch (e) {} + } while (tickFinalizers.length > 0 || operationsQueue.length > 0); + asap$1 = _asap; + isRootExecution = true; + } + } + } + + function setCatched(promise) { + promise._catched = true; + if (promise._parent && !promise._parent._catched) setCatched(promise._parent); + } + + function resolve(promise, newValue) { + var outerPSD = Promise.PSD; + Promise.PSD = promise._PSD; + try { + //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure + if (newValue === promise) throw new TypeError('A promise cannot be resolved with itself.'); + if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { + if (typeof newValue.then === 'function') { + if (newValue instanceof Promise && newValue._state !== null) { + promise._state = newValue._state; + promise._value = newValue._value; + finale.call(promise); + return; + } + doResolve(promise, function (resolve, reject) { + //newValue instanceof Promise ? newValue._then(resolve, reject) : newValue.then(resolve, reject); + newValue.then(resolve, reject); + }, function (data) { + resolve(promise, data); + }, function (reason) { + reject(promise, reason); + }); + return; + } + } + promise._state = true; + promise._value = newValue; + finale.call(promise); + } catch (e) { + reject(e); + } finally { + Promise.PSD = outerPSD; + } + } + + function reject(promise, newValue) { + var outerPSD = Promise.PSD; + Promise.PSD = promise._PSD; + promise._state = false; + promise._value = newValue; + + finale.call(promise); + if (!promise._catched) { + try { + if (promise.onuncatched) promise.onuncatched(promise._value);else Promise.on.error.fire(promise._value); + } catch (e) {} + } + Promise.PSD = outerPSD; + return promise._catched; + } + + function finale() { + for (var i = 0, len = this._deferreds.length; i < len; i++) { + handle(this, this._deferreds[i]); + } + this._deferreds = []; + } + + function Deferred(onFulfilled, onRejected, resolve, reject) { + this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; + this.onRejected = typeof onRejected === 'function' ? onRejected : null; + this.resolve = resolve; + this.reject = reject; + } + + /** + * Take a potentially misbehaving resolver function and make sure + * onFulfilled and onRejected are only called once. + * + * Makes no guarantees about asynchrony. + */ + function doResolve(promise, fn, onFulfilled, onRejected) { + var done = false; + try { + fn(function Promise_resolve(value) { + if (done) return; + done = true; + onFulfilled(value); + }, function Promise_reject(reason) { + if (done) return promise._catched; + done = true; + return onRejected(reason); + }); + } catch (ex) { + if (done) return; + return onRejected(ex); + } + } + + Promise.all = function () { + var args = slice(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments); + + return new Promise(function (resolve, reject) { + if (args.length === 0) return resolve([]); + var remaining = args.length; + function res(i, val) { + try { + if (val && (typeof val === 'object' || typeof val === 'function')) { + var then = val.then; + if (typeof then === 'function') { + then.call(val, function (val) { + res(i, val); + }, reject); + return; + } + } + args[i] = val; + if (--remaining === 0) { + resolve(args); + } + } catch (ex) { + reject(ex); + } + } + for (var i = 0; i < args.length; i++) { + res(i, args[i]); + } + }); + }; + + /* Prototype Methods */ + Promise.prototype.then = function (onFulfilled, onRejected) { + var self = this; + var p = new Promise(function (resolve, reject) { + if (self._state === null) handle(self, new Deferred(onFulfilled, onRejected, resolve, reject));else asap$1(handle, self, new Deferred(onFulfilled, onRejected, resolve, reject)); + }); + p._PSD = this._PSD; + p.onuncatched = this.onuncatched; // Needed when exception occurs in a then() clause of a successful parent promise. Want onuncatched to be called even in callbacks of callbacks of the original promise. + p._parent = this; // Used for recursively calling onuncatched event on self and all parents. + return p; + }; + + Promise.prototype._then = function (onFulfilled, onRejected) { + handle(this, new Deferred(onFulfilled, onRejected, nop, nop)); + }; + + Promise.prototype['catch'] = function (onRejected) { + if (arguments.length === 1) return this.then(null, onRejected); + // First argument is the Error type to catch + var type = arguments[0], + callback = arguments[1]; + if (typeof type === 'function') return this.then(null, function (e) { + // Catching errors by its constructor type (similar to java / c++ / c#) + // Sample: promise.catch(TypeError, function (e) { ... }); + if (e instanceof type) return callback(e);else return Promise.reject(e); + });else return this.then(null, function (e) { + // Catching errors by the error.name property. Makes sense for indexedDB where error type + // is always DOMError but where e.name tells the actual error type. + // Sample: promise.catch('ConstraintError', function (e) { ... }); + if (e && e.name === type) return callback(e);else return Promise.reject(e); + }); + }; + + Promise.prototype['finally'] = function (onFinally) { + return this.then(function (value) { + onFinally(); + return value; + }, function (err) { + onFinally(); + return Promise.reject(err); + }); + }; + + Promise.prototype.onuncatched = null; // Optional event triggered if promise is rejected but no one listened. + + Promise.resolve = function (value) { + if (value && typeof value.then === 'function') return value; + var p = new Promise(function () {}); + p._state = true; + p._value = value; + return p; + }; + + Promise.reject = function (value) { + var p = new Promise(function () {}); + p._state = false; + p._value = value; + return p; + }; + + Promise.race = function (values) { + return new Promise(function (resolve, reject) { + values.map(function (value) { + value.then(resolve, reject); + }); + }); + }; + + Promise.PSD = null; // Promise Specific Data - a TLS Pattern (Thread Local Storage) for Promises. TODO: Rename Promise.PSD to Promise.data + + Promise.newPSD = function (fn) { + // Create new PSD scope (Promise Specific Data) + var outerScope = Promise.PSD; + Promise.PSD = outerScope ? Object.create(outerScope) : {}; + try { + return fn(); + } finally { + Promise.PSD = outerScope; + } + }; + + Promise.usePSD = function (psd, fn) { + var outerScope = Promise.PSD; + Promise.PSD = psd; + try { + return fn(); + } finally { + Promise.PSD = outerScope; + } + }; + + Promise._rootExec = _rootExec; + Promise._tickFinalize = function (callback) { + if (isRootExecution) throw new Error("Not in a virtual tick"); + tickFinalizers.push(callback); + }; + + Promise.on = Events(null, { "error": [function (f1, f2) { + return f2; + }, // Only use the most recent handler (only allow one handler at a time). + defaultErrorHandler] // Default to defaultErrorHandler + }); + + // By default, log uncaught errors to the console + function defaultErrorHandler(e) { + console.warn('Uncaught Promise: ' + messageAndStack(e)); + } + + var maxString = String.fromCharCode(65535); + var maxKey = function () { + try { + IDBKeyRange.only([[]]);return [[]]; + } catch (e) { + return maxString; + } + }(); + var INVALID_KEY_ARGUMENT = "Invalid key provided. Keys must be of type string, number, Date or Array."; + var STRING_EXPECTED = "String expected."; + var connections = []; + var isIEOrEdge = typeof navigator !== 'undefined' && /(MSIE|Trident|Edge)/.test(navigator.userAgent); + var hasIEDeleteObjectStoreBug = isIEOrEdge; + var hangsOnDeleteLargeKeyRange = isIEOrEdge; + function Dexie(dbName, options) { + /// Specify only if you wich to control which addons that should run on this instance + var deps = Dexie.dependencies; + var opts = extend({ + // Default Options + addons: Dexie.addons, // Pick statically registered addons by default + autoOpen: true, // Don't require db.open() explicitely. + indexedDB: deps.indexedDB, // Backend IndexedDB api. Default to IDBShim or browser env. + IDBKeyRange: deps.IDBKeyRange // Backend IDBKeyRange api. Default to IDBShim or browser env. + }, options); + var addons = opts.addons, + autoOpen = opts.autoOpen, + indexedDB = opts.indexedDB, + IDBKeyRange = opts.IDBKeyRange; + + var globalSchema = this._dbSchema = {}; + var versions = []; + var dbStoreNames = []; + var allTables = {}; + var notInTransFallbackTables = {}; + /// + var idbdb = null; // Instance of IDBDatabase + var db_is_blocked = true; + var dbOpenError = null; + var isBeingOpened = false; + var READONLY = "readonly", + READWRITE = "readwrite"; + var db = this; + var pausedResumeables = []; + var autoSchema = true; + var hasNativeGetDatabaseNames = !!getNativeGetDatabaseNamesFn(indexedDB); + + function init() { + // Default subscribers to "versionchange" and "blocked". + // Can be overridden by custom handlers. If custom handlers return false, these default + // behaviours will be prevented. + db.on("versionchange", function (ev) { + // Default behavior for versionchange event is to close database connection. + // Caller can override this behavior by doing db.on("versionchange", function(){ return false; }); + // Let's not block the other window from making it's delete() or open() call. + // NOTE! This event is never fired in IE,Edge or Safari. + 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.'); + db.close(); + // In many web applications, it would be recommended to force window.reload() + // when this event occurs. To do that, subscribe to the versionchange event + // and call window.location.reload(true) if ev.newVersion > 0 (not a deletion) + // The reason for this is that your current web app obviously has old schema code that needs + // to be updated. Another window got a newer version of the app and needs to upgrade DB but + // your window is blocking it unless we close it here. + }); + db.on("blocked", function (ev) { + 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); + }); + } + + // + // + // + // ------------------------- Versioning Framework--------------------------- + // + // + // + + this.version = function (versionNumber) { + /// + /// + if (idbdb || isBeingOpened) throw new exceptions.Schema("Cannot add version when database is open"); + this.verno = Math.max(this.verno, versionNumber); + var versionInstance = versions.filter(function (v) { + return v._cfg.version === versionNumber; + })[0]; + if (versionInstance) return versionInstance; + versionInstance = new Version(versionNumber); + versions.push(versionInstance); + versions.sort(lowerVersionFirst); + return versionInstance; + }; + + function Version(versionNumber) { + this._cfg = { + version: versionNumber, + storesSource: null, + dbschema: {}, + tables: {}, + contentUpgrade: null + }; + this.stores({}); // Derive earlier schemas by default. + } + + extend(Version.prototype, { + stores: function (stores) { + /// + /// Defines the schema for a particular version + /// + /// + /// Example:
+ /// {users: "id++,first,last,&username,*email",
+ /// passwords: "id++,&username"}
+ ///
+ /// Syntax: {Table: "[primaryKey][++],[&][*]index1,[&][*]index2,..."}

+ /// Special characters:
+ /// "&" means unique key,
+ /// "*" means value is multiEntry,
+ /// "++" means auto-increment and only applicable for primary key
+ /// + 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. + var storesSpec = {}; + versions.forEach(function (version) { + // 'versions' is always sorted by lowest version first. + extend(storesSpec, version._cfg.storesSource); + }); + + var dbschema = this._cfg.dbschema = {}; + this._parseStoresSpec(storesSpec, dbschema); + // Update the latest schema to this version + // Update API + globalSchema = db._dbSchema = dbschema; + removeTablesApi([allTables, db, notInTransFallbackTables]); + setApiOnPlace([notInTransFallbackTables], tableNotInTransaction, keys(dbschema), READWRITE, dbschema); + setApiOnPlace([allTables, db, this._cfg.tables], db._transPromiseFactory, keys(dbschema), READWRITE, dbschema, true); + dbStoreNames = keys(dbschema); + return this; + }, + upgrade: function (upgradeFunction) { + /// Function that performs upgrading actions. + var self = this; + fakeAutoComplete(function () { + upgradeFunction(db._createTransaction(READWRITE, keys(self._cfg.dbschema), self._cfg.dbschema)); // BUGBUG: No code completion for prev version's tables wont appear. + }); + this._cfg.contentUpgrade = upgradeFunction; + return this; + }, + _parseStoresSpec: function (stores, outSchema) { + keys(stores).forEach(function (tableName) { + if (stores[tableName] !== null) { + var instanceTemplate = {}; + var indexes = parseIndexSyntax(stores[tableName]); + var primKey = indexes.shift(); + if (primKey.multi) throw new exceptions.Schema("Primary key cannot be multi-valued"); + if (primKey.keyPath) setByKeyPath(instanceTemplate, primKey.keyPath, primKey.auto ? 0 : primKey.keyPath); + indexes.forEach(function (idx) { + if (idx.auto) throw new exceptions.Schema("Only primary key can be marked as autoIncrement (++)"); + if (!idx.keyPath) throw new exceptions.Schema("Index must have a name and cannot be an empty string"); + setByKeyPath(instanceTemplate, idx.keyPath, idx.compound ? idx.keyPath.map(function () { + return ""; + }) : ""); + }); + outSchema[tableName] = new TableSchema(tableName, primKey, indexes, instanceTemplate); + } + }); + } + }); + + function runUpgraders(oldVersion, idbtrans, reject, openReq) { + if (oldVersion === 0) { + //globalSchema = versions[versions.length - 1]._cfg.dbschema; + // Create tables: + keys(globalSchema).forEach(function (tableName) { + createTable(idbtrans, tableName, globalSchema[tableName].primKey, globalSchema[tableName].indexes); + }); + // Populate data + var t = db._createTransaction(READWRITE, dbStoreNames, globalSchema); + t.idbtrans = idbtrans; + t.idbtrans.onerror = eventRejectHandler(reject, ["populating database"]); + t.on('error').subscribe(reject); + Promise.newPSD(function () { + Promise.PSD.trans = t; + try { + db.on("populate").fire(t); + } catch (err) { + openReq.onerror = idbtrans.onerror = function (ev) { + ev.preventDefault(); + }; // Prohibit AbortError fire on db.on("error") in Firefox. + try { + idbtrans.abort(); + } catch (e) {} + idbtrans.db.close(); + reject(err); + } + }); + } else { + // Upgrade version to version, step-by-step from oldest to newest version. + // Each transaction object will contain the table set that was current in that version (but also not-yet-deleted tables from its previous version) + var queue = []; + var oldVersionStruct = versions.filter(function (version) { + return version._cfg.version === oldVersion; + })[0]; + if (!oldVersionStruct) throw new exceptions.Upgrade("Dexie specification of currently installed DB version is missing"); + globalSchema = db._dbSchema = oldVersionStruct._cfg.dbschema; + var anyContentUpgraderHasRun = false; + + var versToRun = versions.filter(function (v) { + return v._cfg.version > oldVersion; + }); + versToRun.forEach(function (version) { + /// + var oldSchema = globalSchema; + var newSchema = version._cfg.dbschema; + adjustToExistingIndexNames(oldSchema, idbtrans); + adjustToExistingIndexNames(newSchema, idbtrans); + globalSchema = db._dbSchema = newSchema; + { + var diff = getSchemaDiff(oldSchema, newSchema); + diff.add.forEach(function (tuple) { + queue.push(function (idbtrans, cb) { + createTable(idbtrans, tuple[0], tuple[1].primKey, tuple[1].indexes); + cb(); + }); + }); + diff.change.forEach(function (change) { + if (change.recreate) { + throw new exceptions.Upgrade("Not yet support for changing primary key"); + } else { + queue.push(function (idbtrans, cb) { + var store = idbtrans.objectStore(change.name); + change.add.forEach(function (idx) { + addIndex(store, idx); + }); + change.change.forEach(function (idx) { + store.deleteIndex(idx.name); + addIndex(store, idx); + }); + change.del.forEach(function (idxName) { + store.deleteIndex(idxName); + }); + cb(); + }); + } + }); + if (version._cfg.contentUpgrade) { + queue.push(function (idbtrans, cb) { + anyContentUpgraderHasRun = true; + var t = db._createTransaction(READWRITE, slice(idbtrans.db.objectStoreNames), newSchema); + t.idbtrans = idbtrans; + var uncompletedRequests = 0; + t._promise = override(t._promise, function (orig_promise) { + return function (mode, fn, writeLock) { + ++uncompletedRequests; + function proxy(fn) { + return function () { + fn.apply(this, arguments); + if (--uncompletedRequests === 0) cb(); // A called db operation has completed without starting a new operation. The flow is finished, now run next upgrader. + }; + } + return orig_promise.call(this, mode, function (resolve, reject) { + arguments[0] = proxy(resolve); + arguments[1] = proxy(reject); + fn.apply(this, arguments); + }, writeLock); + }; + }); + idbtrans.onerror = eventRejectHandler(reject, ["running upgrader function for version", version._cfg.version]); + t.on('error').subscribe(reject); + version._cfg.contentUpgrade(t); + if (uncompletedRequests === 0) cb(); // contentUpgrade() didnt call any db operations at all. + }); + } + if (!anyContentUpgraderHasRun || hasIEDeleteObjectStoreBug) { + // Dont delete old tables if ieBug is present and a content upgrader has run. Let tables be left in DB so far. This needs to be taken care of. + queue.push(function (idbtrans, cb) { + // Delete old tables + deleteRemovedTables(newSchema, idbtrans); + cb(); + }); + } + } + }); + + // Now, create a queue execution engine + var runNextQueuedFunction = function () { + try { + if (queue.length) queue.shift()(idbtrans, runNextQueuedFunction);else createMissingTables(globalSchema, idbtrans); // At last, make sure to create any missing tables. (Needed by addons that add stores to DB without specifying version) + } catch (err) { + openReq.onerror = idbtrans.onerror = function (ev) { + ev.preventDefault(); + }; // Prohibit AbortError fire on db.on("error") in Firefox. + try { + idbtrans.abort(); + } catch (e) {} + idbtrans.db.close(); + reject(err); + } + }; + runNextQueuedFunction(); + } + } + + function getSchemaDiff(oldSchema, newSchema) { + var diff = { + del: [], // Array of table names + add: [], // Array of [tableName, newDefinition] + change: [] // Array of {name: tableName, recreate: newDefinition, del: delIndexNames, add: newIndexDefs, change: changedIndexDefs} + }; + for (var table in oldSchema) { + if (!newSchema[table]) diff.del.push(table); + } + for (table in newSchema) { + var oldDef = oldSchema[table], + newDef = newSchema[table]; + if (!oldDef) diff.add.push([table, newDef]);else { + var change = { + name: table, + def: newSchema[table], + recreate: false, + del: [], + add: [], + change: [] + }; + if (oldDef.primKey.src !== newDef.primKey.src) { + // Primary key has changed. Remove and re-add table. + change.recreate = true; + diff.change.push(change); + } else { + var oldIndexes = oldDef.indexes.reduce(function (prev, current) { + prev[current.name] = current;return prev; + }, {}); + var newIndexes = newDef.indexes.reduce(function (prev, current) { + prev[current.name] = current;return prev; + }, {}); + for (var idxName in oldIndexes) { + if (!newIndexes[idxName]) change.del.push(idxName); + } + for (idxName in newIndexes) { + var oldIdx = oldIndexes[idxName], + newIdx = newIndexes[idxName]; + if (!oldIdx) change.add.push(newIdx);else if (oldIdx.src !== newIdx.src) change.change.push(newIdx); + } + if (change.recreate || change.del.length > 0 || change.add.length > 0 || change.change.length > 0) { + diff.change.push(change); + } + } + } + } + return diff; + } + + function createTable(idbtrans, tableName, primKey, indexes) { + /// + var store = idbtrans.db.createObjectStore(tableName, primKey.keyPath ? { keyPath: primKey.keyPath, autoIncrement: primKey.auto } : { autoIncrement: primKey.auto }); + indexes.forEach(function (idx) { + addIndex(store, idx); + }); + return store; + } + + function createMissingTables(newSchema, idbtrans) { + keys(newSchema).forEach(function (tableName) { + if (!idbtrans.db.objectStoreNames.contains(tableName)) { + createTable(idbtrans, tableName, newSchema[tableName].primKey, newSchema[tableName].indexes); + } + }); + } + + function deleteRemovedTables(newSchema, idbtrans) { + for (var i = 0; i < idbtrans.db.objectStoreNames.length; ++i) { + var storeName = idbtrans.db.objectStoreNames[i]; + if (newSchema[storeName] === null || newSchema[storeName] === undefined) { + idbtrans.db.deleteObjectStore(storeName); + } + } + } + + function addIndex(store, idx) { + store.createIndex(idx.name, idx.keyPath, { unique: idx.unique, multiEntry: idx.multi }); + } + + function executePausedResumeables() { + pausedResumeables.forEach(function (resumable) { + // Resume all stalled operations. They will fail once they wake up. + resumable.resume(); + }); + } + + // + // + // Dexie Protected API + // + // + + this._allTables = allTables; + + this._tableFactory = function createTable(mode, tableSchema, transactionPromiseFactory) { + /// + if (mode === READONLY) return new Table(tableSchema.name, transactionPromiseFactory, tableSchema, Collection);else return new WriteableTable(tableSchema.name, transactionPromiseFactory, tableSchema); + }; + + this._createTransaction = function (mode, storeNames, dbschema, parentTransaction) { + return new Transaction(mode, storeNames, dbschema, parentTransaction); + }; + + function tableNotInTransaction(mode, storeNames) { + throw new exceptions.InvalidTable("Table " + storeNames[0] + " not part of transaction. Original Scope Function Source: " + Dexie.Promise.PSD.trans.scopeFunc.toString()); + } + + this._transPromiseFactory = function transactionPromiseFactory(mode, storeNames, fn) { + // Last argument is "writeLocked". But this doesnt apply to oneshot direct db operations, so we ignore it. + if (db_is_blocked && (!Promise.PSD || !Promise.PSD.letThrough)) { + // Database is paused. Wait til resumed. + if (!isBeingOpened && !autoOpen) { + return fail(new exceptions.DatabaseClosed()); + } + var blockedPromise = new Promise(function (resolve, reject) { + pausedResumeables.push({ + resume: function () { + var p = db._transPromiseFactory(mode, storeNames, fn); + blockedPromise.onuncatched = p.onuncatched; + p.then(resolve, reject); + } + }); + }); + if (autoOpen && !isBeingOpened) { + db.open().catch(nop); // catching to get rid of error logging of uncaught Promise. dbOpenError will be returned again as a rejected Promise. + } + return blockedPromise; + } else { + var trans = db._createTransaction(mode, storeNames, globalSchema); + return trans._promise(mode, function (resolve, reject) { + // An uncatched operation will bubble to this anonymous transaction. Make sure + // to continue bubbling it up to db.on('error'): + trans.error(function (err) { + db.on('error').fire(err); + }); + Promise.newPSD(function () { + Promise.PSD.trans = trans; + fn(function (value) { + // Instead of resolving value directly, wait with resolving it until transaction has completed. + // Otherwise the data would not be in the DB if requesting it in the then() operation. + // Specifically, to ensure that the following expression will work: + // + // db.friends.put({name: "Arne"}).then(function () { + // db.friends.where("name").equals("Arne").count(function(count) { + // assert (count === 1); + // }); + // }); + // + trans.complete(function () { + resolve(value); + }); + }, reject, trans); + }); + }); + } + }; + + this._whenReady = function (fn) { + if (!fake && db_is_blocked && (!Promise.PSD || !Promise.PSD.letThrough)) { + if (!isBeingOpened) { + if (autoOpen) { + db.open().catch(nop); // catching to get rid of error logging of uncaught Promise. dbOpenError will be returned again as a rejected Promise. + } else { + return fail(new exceptions.DatabaseClosed()); + } + } + return new Promise(function (resolve, reject) { + pausedResumeables.push({ + resume: function () { + fn(resolve, reject); + } + }); + }); + } + return new Promise(fn); + }; + + // + // + // + // + // Dexie API + // + // + // + + this.verno = 0; + + this.open = function () { + if (idbdb) return Promise.resolve(db); + if (isBeingOpened) return new Promise(function (resolve, reject) { + return db._whenReady(function () { + resolve(db); + }, function (e) { + reject(e); + }); + }); + dbOpenError = null; + isBeingOpened = true; + db_is_blocked = true; + return new Promise(function (resolve, reject) { + if (fake) resolve(); + var req; + function openError(err) { + try { + req.transaction.abort(); + } catch (e) {} + if (idbdb) try { + idbdb.close(); + } catch (e) {} + idbdb = null; + isBeingOpened = false; + dbOpenError = mapError(err); + db_is_blocked = false; + reject(dbOpenError); + executePausedResumeables(); + } + try { + // Make sure caller has specified at least one version + if (versions.length > 0) autoSchema = false; + + // Multiply db.verno with 10 will be needed to workaround upgrading bug in IE: + // IE fails when deleting objectStore after reading from it. + // A future version of Dexie.js will stopover an intermediate version to workaround this. + // 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. + if (!indexedDB) throw new exceptions.MissingAPI("indexedDB API not found. If using IE10+, make sure to run your code on a server URL " + "(not locally). If using Safari, make sure to include indexedDB polyfill."); + req = autoSchema ? indexedDB.open(dbName) : indexedDB.open(dbName, Math.round(db.verno * 10)); + 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 + req.onerror = eventRejectHandler(openError, ["opening database", dbName]); + req.onblocked = fireOnBlocked; + req.onupgradeneeded = trycatch(function (e) { + if (autoSchema && !db._allowEmptyDB) { + // Unless an addon has specified db._allowEmptyDB, lets make the call fail. + // Caller did not specify a version or schema. Doing that is only acceptable for opening alread existing databases. + // If onupgradeneeded is called it means database did not exist. Reject the open() promise and make sure that we + // do not create a new database by accident here. + req.onerror = function (event) { + event.preventDefault(); + }; // Prohibit onabort error from firing before we're done! + req.transaction.abort(); // Abort transaction (would hope that this would make DB disappear but it doesnt.) + // Close database and delete it. + req.result.close(); + 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! + delreq.onsuccess = delreq.onerror = function () { + openError(new exceptions.NoSuchDatabase('Database ' + dbName + ' doesnt exist')); + }; + } else { + req.transaction.onerror = eventRejectHandler(openError); + var oldVer = e.oldVersion > Math.pow(2, 62) ? 0 : e.oldVersion; // Safari 8 fix. + runUpgraders(oldVer / 10, req.transaction, openError, req); + } + }, openError); + req.onsuccess = trycatch(function () { + isBeingOpened = false; + idbdb = req.result; + if (autoSchema) readGlobalSchema();else if (idbdb.objectStoreNames.length > 0) { + try { + adjustToExistingIndexNames(globalSchema, idbdb.transaction(safariMultiStoreFix(idbdb.objectStoreNames), READONLY)); + } catch (e) { + // Safari may bail out if > 1 store names. However, this shouldnt be a showstopper. Issue #120. + } + } + + idbdb.onversionchange = function (ev) { + db._vcFired = true; // detect implementations that not support versionchange (IE/Edge/Safari) + db.on("versionchange").fire(ev); + }; + if (!hasNativeGetDatabaseNames) { + // Update localStorage with list of database names + globalDatabaseList(function (databaseNames) { + if (databaseNames.indexOf(dbName) === -1) return databaseNames.push(dbName); + }); + } + // Now, let any subscribers to the on("ready") fire BEFORE any other db operations resume! + // If an the on("ready") subscriber returns a Promise, we will wait til promise completes or rejects before + Promise.newPSD(function () { + Promise.PSD.letThrough = true; // Set a Promise-Specific Data property informing that onready is firing. This will make db._whenReady() let the subscribers use the DB but block all others (!). Quite cool ha? + try { + var res = db.on.ready.fire(); + if (res && typeof res.then === 'function') { + // If on('ready') returns a promise, wait for it to complete and then resume any pending operations. + res.then(resume, function (err) { + idbdb.close(); + idbdb = null; + openError(err); + }); + } else { + asap(resume); // Cannot call resume directly because then the pauseResumables would inherit from our PSD scope. + } + } catch (e) { + openError(e); + } + + function resume() { + db_is_blocked = false; + executePausedResumeables(); + resolve(); + } + }); + }, openError); + } catch (err) { + openError(err); + } + }).then(function () { + connections.push(db); + return db; + }); + }; + + this.close = function () { + var idx = connections.indexOf(db); + if (idx >= 0) connections.splice(idx, 1); + if (idbdb) { + idbdb.close(); + idbdb = null; + autoOpen = false; + if (db_is_blocked) { + executePausedResumeables(); + } + db_is_blocked = false; + dbOpenError = new exceptions.DatabaseClosed(); + } else if (isBeingOpened) { + db.on('ready', function () { + return Promise.reject(new exceptions.DatabaseClosed()); + }); + } + }; + + this.delete = function () { + var args = arguments; + return new Promise(function (resolve, reject) { + if (args.length > 0) throw new exceptions.InvalidArgument("Arguments not allowed in db.delete()"); + function doDelete() { + db.close(); + var req = indexedDB.deleteDatabase(dbName); + req.onsuccess = function () { + if (!hasNativeGetDatabaseNames) { + globalDatabaseList(function (databaseNames) { + var pos = databaseNames.indexOf(dbName); + if (pos >= 0) return databaseNames.splice(pos, 1); + }); + } + resolve(); + }; + req.onerror = eventRejectHandler(reject, ["deleting", dbName]); + req.onblocked = fireOnBlocked; + } + if (isBeingOpened) { + pausedResumeables.push({ resume: doDelete }); + } else { + doDelete(); + } + }); + }; + + this.backendDB = function () { + return idbdb; + }; + + this.isOpen = function () { + return idbdb !== null; + }; + this.hasFailed = function () { + return dbOpenError !== null; + }; + this.dynamicallyOpened = function () { + return autoSchema; + }; + + // + // Properties + // + this.name = dbName; + + // db.tables - an array of all Table instances. + setProp(this, "tables", { + get: function () { + /// + return keys(allTables).map(function (name) { + return allTables[name]; + }); + } + }); + + // + // Events + // + this.on = Events(this, "error", "populate", { blocked: [reverseStoppableEventChain, nop], "ready": [promisableChain, nop], "versionchange": [reverseStoppableEventChain, nop] }); + + // Handle on('ready') specifically: If DB is already open, trigger the event immediately. Also, default to unsubscribe immediately after being triggered. + this.on.ready.subscribe = override(this.on.ready.subscribe, function (origSubscribe) { + return function (subscriber, bSticky) { + function proxy() { + if (!bSticky) db.on.ready.unsubscribe(proxy); + return subscriber.apply(this, arguments); + } + origSubscribe.call(this, proxy); + if (db.isOpen()) { + if (db_is_blocked) { + pausedResumeables.push({ resume: proxy }); + } else { + proxy(); + } + } + }; + }); + + fakeAutoComplete(function () { + db.on("populate").fire(db._createTransaction(READWRITE, dbStoreNames, globalSchema)); + db.on("error").fire(new Error()); + }); + + this.transaction = function (mode, tableInstances, scopeFunc) { + /// + /// + /// + /// "r" for readonly, or "rw" for readwrite + /// Table instance, Array of Table instances, String or String Array of object stores to include in the transaction + /// Function to execute with transaction + + // Let table arguments be all arguments between mode and last argument. + tableInstances = slice(arguments, 1, arguments.length - 1); + // Let scopeFunc be the last argument + scopeFunc = arguments[arguments.length - 1]; + var parentTransaction = Promise.PSD && Promise.PSD.trans; + // Check if parent transactions is bound to this db instance, and if caller wants to reuse it + if (!parentTransaction || parentTransaction.db !== db || mode.indexOf('!') !== -1) parentTransaction = null; + var onlyIfCompatible = mode.indexOf('?') !== -1; + mode = mode.replace('!', '').replace('?', ''); + // + // Get storeNames from arguments. Either through given table instances, or through given table names. + // + var tables = isArray(tableInstances[0]) ? tableInstances.reduce(function (a, b) { + return a.concat(b); + }) : tableInstances; + var error = null; + var storeNames = tables.map(function (tableInstance) { + if (typeof tableInstance === "string") { + return tableInstance; + } else { + if (!(tableInstance instanceof Table)) error = error || new TypeError("Invalid type. Arguments following mode must be instances of Table or String"); + return tableInstance.name; + } + }); + + // + // Resolve mode. Allow shortcuts "r" and "rw". + // + if (mode == "r" || mode == READONLY) mode = READONLY;else if (mode == "rw" || mode == READWRITE) mode = READWRITE;else error = new exceptions.InvalidArgument("Invalid transaction mode: " + mode); + + if (parentTransaction) { + // Basic checks + if (!error) { + if (parentTransaction && parentTransaction.mode === READONLY && mode === READWRITE) { + if (onlyIfCompatible) parentTransaction = null; // Spawn new transaction instead. + else error = error || new exceptions.SubTransaction("Cannot enter a sub-transaction with READWRITE mode when parent transaction is READONLY"); + } + if (parentTransaction) { + storeNames.forEach(function (storeName) { + if (!parentTransaction.tables.hasOwnProperty(storeName)) { + if (onlyIfCompatible) parentTransaction = null; // Spawn new transaction instead. + else error = error || new exceptions.SubTransaction("Table " + storeName + " not included in parent transaction. Parent Transaction function: " + parentTransaction.scopeFunc.toString()); + } + }); + } + } + } + if (parentTransaction) { + // If this is a sub-transaction, lock the parent and then launch the sub-transaction. + return parentTransaction._promise(mode, enterTransactionScope, "lock"); + } else { + // If this is a root-level transaction, wait til database is ready and then launch the transaction. + return db._whenReady(enterTransactionScope); + } + + function enterTransactionScope(resolve, reject) { + // Our transaction. To be set later. + var trans = null; + var isConstructing = true; + + try { + // Throw any error if any of the above checks failed. + // Real error defined some lines up. We throw it here from within a Promise to reject Promise + // rather than make caller need to both use try..catch and promise catching. The reason we still + // throw here rather than do Promise.reject(error) is that we like to have the stack attached to the + // error. Also because there is a catch() clause bound to this try() that will bubble the error + // to the parent transaction. + if (error) throw error; + + // + // Create Transaction instance + // + trans = db._createTransaction(mode, storeNames, globalSchema, parentTransaction); + + // Provide arguments to the scope function (for backward compatibility) + var tableArgs = storeNames.map(function (name) { + return trans.tables[name]; + }); + tableArgs.push(trans); + + // If transaction completes, resolve the Promise with the return value of scopeFunc. + var returnValue; + var uncompletedRequests = 0; + + // Create a new PSD frame to hold Promise.PSD.trans. Must not be bound to the current PSD frame since we want + // it to pop before then() callback is called of our returned Promise. + Promise.newPSD(function () { + // Let the transaction instance be part of a Promise-specific data (PSD) value. + Promise.PSD.trans = trans; + trans.scopeFunc = scopeFunc; // For Error ("Table " + storeNames[0] + " not part of transaction") when it happens. This may help localizing the code that started a transaction used on another place. + + if (parentTransaction) { + // Emulate transaction commit awareness for inner transaction (must 'commit' when the inner transaction has no more operations ongoing) + trans.idbtrans = parentTransaction.idbtrans; + trans._promise = override(trans._promise, function (orig) { + return function (mode, fn, writeLock) { + ++uncompletedRequests; + function proxy(fn2) { + return function (val) { + var retval; + // _rootExec needed so that we do not loose any IDBTransaction in a setTimeout() call. + Promise._rootExec(function () { + retval = fn2(val); + // _tickFinalize makes sure to support lazy micro tasks executed in Promise._rootExec(). + // We certainly do not want to copy the bad pattern from IndexedDB but instead allow + // execution of Promise.then() callbacks until the're all done. + Promise._tickFinalize(function () { + if (--uncompletedRequests === 0 && trans.active) { + trans.active = false; + trans.on.complete.fire(); // A called db operation has completed without starting a new operation. The flow is finished + } + }); + }); + return retval; + }; + } + return orig.call(this, mode, function (resolve2, reject2, trans) { + return fn(proxy(resolve2), proxy(reject2), trans); + }, writeLock); + }; + }); + } + trans.complete(function () { + resolve(returnValue); + }); + // If transaction fails, reject the Promise and bubble to db if noone catched this rejection. + trans.error(function (e) { + if (trans.idbtrans) trans.idbtrans.onerror = preventDefault; // Prohibit AbortError from firing. + try { + trans.abort(); + } catch (e2) {} + if (parentTransaction) { + parentTransaction.active = false; + parentTransaction.on.error.fire(e); // Bubble to parent transaction + } + + if (isConstructing) asap(doReject);else doReject(); + function doReject() { + var catched = reject(e); + if (!parentTransaction && !catched) { + db.on.error.fire(e); // If not catched, bubble error to db.on("error"). + } + } + }); + + // Finally, call the scope function with our table and transaction arguments. + Promise._rootExec(function () { + returnValue = scopeFunc.apply(trans, tableArgs); // NOTE: returnValue is used in trans.on.complete() not as a returnValue to this func. + if (returnValue) { + if (typeof returnValue.next === 'function' && typeof returnValue.throw === 'function') { + // scopeFunc returned an iterable. Handle yield as await. + returnValue = awaitIterable(returnValue); + } else if (typeof returnValue.then === 'function' && !returnValue.hasOwnProperty('_PSD')) { + throw new exceptions.IncompatiblePromise(); + } + } + }); + }); + if (!trans.idbtrans || parentTransaction && uncompletedRequests === 0) { + trans._nop(); // Make sure transaction is being used so that it will resolve. + } + } catch (e) { + // If exception occur, abort the transaction and reject Promise. + if (trans && trans.idbtrans) trans.idbtrans.onerror = preventDefault; // Prohibit AbortError from firing. + if (trans) trans.abort(); + if (parentTransaction) parentTransaction.on.error.fire(e); + asap(function () { + // Need to use asap(=setImmediate/setTimeout) before calling reject because we are in the Promise constructor and reject() will always return false if so. + if (!reject(e)) db.on("error").fire(e); // If not catched, bubble exception to db.on("error"); + }); + } + isConstructing = false; + } + }; + + this.table = function (tableName) { + /// + if (fake && autoSchema) return new WriteableTable(tableName); + if (!allTables.hasOwnProperty(tableName)) { + throw new exceptions.InvalidTable('Table ' + tableName + ' does not exist'); + } + return allTables[tableName]; + }; + + // + // + // + // Table Class + // + // + // + function Table(name, transactionPromiseFactory, tableSchema, collClass) { + /// + this.name = name; + this.schema = tableSchema; + this.hook = allTables[name] ? allTables[name].hook : Events(null, { + "creating": [hookCreatingChain, nop], + "reading": [pureFunctionChain, mirror], + "updating": [hookUpdatingChain, nop], + "deleting": [hookDeletingChain, nop] + }); + this._tpf = transactionPromiseFactory; + this._collClass = collClass || Collection; + } + + extendProto(Table.prototype, function () { + function failReadonly() { + // It's ok to throw here because this can only happen within a transaction, + // and will always be caught by the transaction scope and returned as a + // failed promise. + throw new exceptions.ReadOnly("Current Transaction is READONLY"); + } + return { + // + // Table Protected Methods + // + + _trans: function getTransaction(mode, fn, writeLocked) { + return this._tpf(mode, [this.name], fn, writeLocked); + }, + _idbstore: function getIDBObjectStore(mode, fn, writeLocked) { + if (fake) return new Promise(fn); // Simplify the work for Intellisense/Code completion. + var self = this; + return this._tpf(mode, [this.name], function (resolve, reject, trans) { + fn(resolve, reject, trans.idbtrans.objectStore(self.name), trans); + }, writeLocked); + }, + + // + // Table Public Methods + // + get: function (key, cb) { + var self = this; + return this._idbstore(READONLY, function (resolve, reject, idbstore) { + fake && resolve(self.schema.instanceTemplate); + var req = idbstore.get(key); + req.onerror = eventRejectHandler(reject, ["getting", key, "from", self.name]); + req.onsuccess = function () { + resolve(self.hook.reading.fire(req.result)); + }; + }).then(cb); + }, + where: function (indexName) { + return new WhereClause(this, indexName); + }, + count: function (cb) { + return this.toCollection().count(cb); + }, + offset: function (offset) { + return this.toCollection().offset(offset); + }, + limit: function (numRows) { + return this.toCollection().limit(numRows); + }, + reverse: function () { + return this.toCollection().reverse(); + }, + filter: function (filterFunction) { + return this.toCollection().and(filterFunction); + }, + each: function (fn) { + return this.toCollection().each(fn); + }, + toArray: function (cb) { + return this.toCollection().toArray(cb); + }, + orderBy: function (index) { + return new this._collClass(new WhereClause(this, index)); + }, + + toCollection: function () { + return new this._collClass(new WhereClause(this)); + }, + + mapToClass: function (constructor, structure) { + /// + /// Map table to a javascript constructor function. Objects returned from the database will be instances of this class, making + /// it possible to the instanceOf operator as well as extending the class using constructor.prototype.method = function(){...}. + /// + /// Constructor function representing the class. + /// Helps IDE code completion by knowing the members that objects contain and not just the indexes. Also + /// know what type each member has. Example: {name: String, emailAddresses: [String], password} + this.schema.mappedClass = constructor; + var instanceTemplate = Object.create(constructor.prototype); + if (structure) { + // structure and instanceTemplate is for IDE code competion only while constructor.prototype is for actual inheritance. + applyStructure(instanceTemplate, structure); + } + 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 + // no matter which method to use for reading (Table.get() or Table.where(...)... ) + var readHook = function (obj) { + if (!obj) return obj; // No valid object. (Value is null). Return as is. + // Create a new object that derives from constructor: + var res = Object.create(constructor.prototype); + // Clone members: + for (var m in obj) { + if (obj.hasOwnProperty(m)) res[m] = obj[m]; + }return res; + }; + + if (this.schema.readHook) { + this.hook.reading.unsubscribe(this.schema.readHook); + } + this.schema.readHook = readHook; + this.hook("reading", readHook); + return constructor; + }, + defineClass: function (structure) { + /// + /// Define all members of the class that represents the table. This will help code completion of when objects are read from the database + /// as well as making it possible to extend the prototype of the returned constructor function. + /// + /// Helps IDE code completion by knowing the members that objects contain and not just the indexes. Also + /// know what type each member has. Example: {name: String, emailAddresses: [String], properties: {shoeSize: Number}} + return this.mapToClass(Dexie.defineClass(structure), structure); + }, + add: failReadonly, + put: failReadonly, + 'delete': failReadonly, + clear: failReadonly, + update: failReadonly + }; + }); + + // + // + // + // WriteableTable Class (extends Table) + // + // + // + function WriteableTable(name, transactionPromiseFactory, tableSchema, collClass) { + Table.call(this, name, transactionPromiseFactory, tableSchema, collClass || WriteableCollection); + } + + function BulkErrorHandlerCatchAll(errorList, done) { + var psd = Promise.PSD; + return function (ev) { + try { + if (ev.stopPropagation) ev.stopPropagation(); + if (ev.preventDefault) ev.preventDefault(); + var err = ev.target.error; + errorList.push(err); + if (ev.target._err) { + Promise.usePSD(psd, ev.target._err.bind(null, err)); + } + } finally { + if (done) done(); + } + }; + } + + function BulkErrorHandler(done) { + var psd = Promise.PSD; + return function (ev) { + var err; + try { + err = ev.target.error; + if (ev.target._err) { + Promise.usePSD(psd, ev.target._err.bind(null, err)); + } + } finally { + done(err); + } + }; + } + + function BulkSuccessHandler(done, hookListener) { + var psd = Promise.PSD; + return hookListener ? function (ev) { + var res; + try { + res = ev.target.result; + ev.target._suc && Promise.usePSD(psd, ev.target._suc.bind(null, res)); + } finally { + if (done) done(res); + } + } : function (ev) { + done(ev.target.result); + }; + } + + function bulkDelete(idbstore, trans, keysOrTuples, hasDeleteHook, deletingHook) { + // If hasDeleteHook, keysOrTuples must be an array of tuples: [[key1, value2],[key2,value2],...], + // else keysOrTuples must be just an array of keys: [key1, key2, ...]. + return new Promise(function (resolve, reject) { + var len = keysOrTuples.length, + lastItem = len - 1; + if (len === 0) return resolve(); + if (!hasDeleteHook) { + for (var i = 0; i < len; ++i) { + var req = idbstore.delete(keysOrTuples[i]); + req.onerror = function (ev) { + return reject(mapError(ev.target.error)); + }; + if (i === lastItem) req.onsuccess = function () { + return resolve(); + }; + } + } else { + var hookCtx = { onsuccess: null, onerror: null }, + errorHandler = BulkErrorHandler(function (e) { + return reject(mapError(e)); + }), + successHandler = BulkSuccessHandler(null, true); + miniTryCatch(function () { + for (var i = 0; i < len; ++i) { + var tuple = keysOrTuples[i]; + deletingHook.call(hookCtx, tuple[0], tuple[1], trans); + var req = idbstore.delete(tuple[0]); + if (hookCtx.onerror) req._err = hookCtx.onerror; + if (hookCtx.onsuccess) req._suc = hookCtx.onsuccess; + req.onerror = errorHandler; + if (i === lastItem) req.onsuccess = BulkSuccessHandler(resolve, true);else req.onsuccess = successHandler; + hookCtx.onsuccess = null; + hookCtx.onerror = null; + } + }, function (err) { + hookCtx.onerror && hookCtx.onerror(err); + throw err; + }); + } + }); + } + + derive(WriteableTable).from(Table).extend(function () { + + return { + bulkDelete: function (keys) { + if (this.hook.deleting.fire === nop) { + return this._idbstore(READWRITE, function (resolve, reject, idbstore, trans) { + resolve(bulkDelete(idbstore, trans, keys, false, nop)); + }); + } else { + return this.where(':id').anyOf(keys).delete().then(function () {}); // Resolve with undefined. + } + }, + bulkPut: function (objects, keys) { + var _this = this; + + return this._idbstore(READWRITE, function (resolve, reject, idbstore, trans) { + if (!idbstore.keyPath && !_this.schema.primKey.auto && !keys) throw new exceptions.InvalidArgument("bulkPut() with non-inbound keys requires keys array in second argument"); + if (idbstore.keyPath && keys) throw new exceptions.InvalidArgument("bulkPut(): keys argument invalid on tables with inbound keys"); + if (keys && keys.length !== objects.length) throw new exceptions.InvalidArgument("Arguments objects and keys must have the same length"); + if (objects.length === 0) return resolve(); // Caller provided empty list. + var done = function (result) { + if (errorList.length === 0) resolve(result);else reject(new BulkError(_this.name + '.bulkPut(): ' + errorList.length + ' of ' + numObjs + ' operations failed', errorList)); + }; + var req, + errorList = [], + errorHandler, + numObjs = objects.length, + table = trans.tables[_this.name]; // Enable us to do stuff in several steps with same transaction. + if (_this.hook.creating.fire === nop && _this.hook.updating.fire === nop) { + // + // Standard Bulk (no 'creating' or 'updating' hooks to care about) + // + errorHandler = BulkErrorHandlerCatchAll(errorList); + for (var i = 0, l = objects.length; i < l; ++i) { + req = keys ? idbstore.put(objects[i], keys[i]) : idbstore.put(objects[i]); + req.onerror = errorHandler; + } + // Only need to catch success or error on the last operation + // according to the IDB spec. + req.onerror = BulkErrorHandlerCatchAll(errorList, done); + req.onsuccess = BulkSuccessHandler(done); + } else { + var effectiveKeys = keys || idbstore.keyPath && objects.map(function (o) { + return getByKeyPath(o, idbstore.keyPath); + }); + var objectLookup = effectiveKeys && effectiveKeys.reduce(function (res, key, i) { + if (key != null) res[key] = objects[i]; + return res; + }, {}); // Generates map of {[key]: object} + + var promise = !effectiveKeys ? + + // Auto-incremented key-less objects only without any keys argument. + table.bulkAdd(objects) : + + // Keys provided. Either as inbound in provided objects, or as a keys argument. + // Begin with updating those that exists in DB: + table.where(':id').anyOf(effectiveKeys.filter(function (key) { + return key != null; + })).modify(function () { + this.value = objectLookup[this.primKey]; + objectLookup[this.primKey] = null; // Mark as "don't add this" + }).catch(ModifyError, function (e) { + errorList = e.failures; // No need to concat here. These are the first errors added. + }).then(function () { + // Now, let's examine which items didnt exist so we can add them: + var objsToAdd = [], + keysToAdd = keys && []; + // Iterate backwards. Why? Because if same key was used twice, just add the last one. + for (var i = effectiveKeys.length - 1; i >= 0; --i) { + var key = effectiveKeys[i]; + if (key == null || objectLookup[key]) { + objsToAdd.push(objects[i]); + keys && keysToAdd.push(key); + if (key != null) objectLookup[key] = null; // Mark as "dont add again" + } + } + // The items are in reverse order so reverse them before adding. + // Could be important in order to get auto-incremented keys the way the caller + // would expect. Could have used unshift instead of push()/reverse(), + // but: http://jsperf.com/unshift-vs-reverse + objsToAdd.reverse(); + keys && keysToAdd.reverse(); + return table.bulkAdd(objsToAdd, keysToAdd); + }).then(function (lastAddedKey) { + // Resolve with key of the last object in given arguments to bulkPut(): + var lastEffectiveKey = effectiveKeys[effectiveKeys.length - 1]; // Key was provided. + return lastEffectiveKey != null ? lastEffectiveKey : lastAddedKey; + }); + + promise.then(done).catch(BulkError, function (e) { + // Concat failure from ModifyError and reject using our 'done' method. + errorList = errorList.concat(e.failures); + done(); + }).catch(reject); + } + }, "locked"); // If called from transaction scope, lock transaction til all steps are done. + }, + bulkAdd: function (objects, keys) { + var self = this, + creatingHook = this.hook.creating.fire; + return this._idbstore(READWRITE, function (resolve, reject, idbstore, trans) { + if (!idbstore.keyPath && !self.schema.primKey.auto && !keys) throw new exceptions.InvalidArgument("bulkAdd() with non-inbound keys requires keys array in second argument"); + if (idbstore.keyPath && keys) throw new exceptions.InvalidArgument("bulkAdd(): keys argument invalid on tables with inbound keys"); + if (keys && keys.length !== objects.length) throw new exceptions.InvalidArgument("Arguments objects and keys must have the same length"); + if (objects.length === 0) return resolve(); // Caller provided empty list. + function done(result) { + if (errorList.length === 0) resolve(result);else reject(new BulkError(self.name + '.bulkAdd(): ' + errorList.length + ' of ' + numObjs + ' operations failed', errorList)); + } + var req, + errorList = [], + errorHandler, + successHandler, + numObjs = objects.length; + if (creatingHook !== nop) { + // + // There are subscribers to hook('creating') + // Must behave as documented. + // + var keyPath = idbstore.keyPath, + hookCtx = { onerror: null, onsuccess: null }; + errorHandler = BulkErrorHandlerCatchAll(errorList, null); + successHandler = BulkSuccessHandler(null, true); + + miniTryCatch(function () { + for (var i = 0, l = objects.length; i < l; ++i) { + var key = keys && keys[i]; + var obj = objects[i], + effectiveKey = keys ? key : keyPath ? getByKeyPath(obj, keyPath) : undefined, + keyToUse = creatingHook.call(hookCtx, effectiveKey, obj, trans); + if (effectiveKey == null && keyToUse != null) { + if (keyPath) { + obj = deepClone(obj); + setByKeyPath(obj, keyPath, keyToUse); + } else { + key = keyToUse; + } + } + req = key != null ? idbstore.add(obj, key) : idbstore.add(obj); + if (hookCtx.onerror) req._err = hookCtx.onerror; + if (hookCtx.onsuccess) req._suc = hookCtx.onsuccess; + if (i < l - 1) { + req.onerror = errorHandler; + if (hookCtx.onsuccess) req.onsuccess = successHandler; + // Reset event listeners for next iteration. + hookCtx.onerror = null; + hookCtx.onsuccess = null; + } + } + }, function (err) { + hookCtx.onerror && hookCtx.onerror(err); + throw err; + }); + + req.onerror = BulkErrorHandlerCatchAll(errorList, done); + req.onsuccess = BulkSuccessHandler(done, true); + } else { + // + // Standard Bulk (no 'creating' hook to care about) + // + errorHandler = BulkErrorHandlerCatchAll(errorList); + for (var i = 0, l = objects.length; i < l; ++i) { + req = keys ? idbstore.add(objects[i], keys[i]) : idbstore.add(objects[i]); + req.onerror = errorHandler; + } + // Only need to catch success or error on the last operation + // according to the IDB spec. + req.onerror = BulkErrorHandlerCatchAll(errorList, done); + req.onsuccess = BulkSuccessHandler(done); + } + }); + }, + add: function (obj, key) { + /// + /// Add an object to the database. In case an object with same primary key already exists, the object will not be added. + /// + /// A javascript object to insert + /// Primary key + var self = this, + creatingHook = this.hook.creating.fire; + return this._idbstore(READWRITE, function (resolve, reject, idbstore, trans) { + var thisCtx = { onsuccess: null, onerror: null }; + if (creatingHook !== nop) { + var effectiveKey = key != null ? key : idbstore.keyPath ? getByKeyPath(obj, idbstore.keyPath) : undefined; + var keyToUse = creatingHook.call(thisCtx, effectiveKey, obj, trans); // Allow subscribers to when("creating") to generate the key. + if (effectiveKey == null && keyToUse != null) { + // Using "==" and "!=" to check for either null or undefined! + if (idbstore.keyPath) setByKeyPath(obj, idbstore.keyPath, keyToUse);else key = keyToUse; + } + } + try { + var req = key != null ? idbstore.add(obj, key) : idbstore.add(obj), + psd = Promise.PSD; + req.onerror = eventRejectHandler(function (e) { + if (thisCtx.onerror) Promise.usePSD(psd, thisCtx.onerror.bind(thisCtx, e)); + return reject(e); + }, ["adding", obj, "into", self.name]); + req.onsuccess = function (ev) { + var keyPath = idbstore.keyPath; + if (keyPath) setByKeyPath(obj, keyPath, ev.target.result); + if (thisCtx.onsuccess) Promise.usePSD(psd, thisCtx.onsuccess.bind(thisCtx, ev.target.result)); + resolve(req.result); + }; + } catch (e) { + if (thisCtx.onerror) thisCtx.onerror(e); + throw e; + } + }); + }, + + put: function (obj, key) { + /// + /// Add an object to the database but in case an object with same primary key alread exists, the existing one will get updated. + /// + /// A javascript object to insert or update + /// Primary key + var self = this, + creatingHook = this.hook.creating.fire, + updatingHook = this.hook.updating.fire; + if (creatingHook !== nop || updatingHook !== nop) { + // + // People listens to when("creating") or when("updating") events! + // We must know whether the put operation results in an CREATE or UPDATE. + // + return this._trans(READWRITE, function (resolve, reject, trans) { + // Since key is optional, make sure we get it from obj if not provided + var effectiveKey = key !== undefined ? key : self.schema.primKey.keyPath && getByKeyPath(obj, self.schema.primKey.keyPath); + if (effectiveKey == null) { + // "== null" means checking for either null or undefined. + // No primary key. Must use add(). + trans.tables[self.name].add(obj).then(resolve, reject); + } else { + // Primary key exist. Lock transaction and try modifying existing. If nothing modified, call add(). + trans._lock(); // Needed because operation is splitted into modify() and add(). + // clone obj before this async call. If caller modifies obj the line after put(), the IDB spec requires that it should not affect operation. + obj = deepClone(obj); + trans.tables[self.name].where(":id").equals(effectiveKey).modify(function () { + // Replace extisting value with our object + // CRUD event firing handled in WriteableCollection.modify() + this.value = obj; + }).then(function (count) { + if (count === 0) { + // Object's key was not found. Add the object instead. + // CRUD event firing will be done in add() + return trans.tables[self.name].add(obj, key); // Resolving with another Promise. Returned Promise will then resolve with the new key. + } else { + return effectiveKey; // Resolve with the provided key. + } + }).finally(function () { + trans._unlock(); + }).then(resolve, reject); + } + }); + } else { + // Use the standard IDB put() method. + return this._idbstore(READWRITE, function (resolve, reject, idbstore) { + var req = key !== undefined ? idbstore.put(obj, key) : idbstore.put(obj); + req.onerror = eventRejectHandler(reject, ["putting", obj, "into", self.name]); + req.onsuccess = function (ev) { + var keyPath = idbstore.keyPath; + if (keyPath) setByKeyPath(obj, keyPath, ev.target.result); + resolve(req.result); + }; + }); + } + }, + + 'delete': function (key) { + /// Primary key of the object to delete + if (this.hook.deleting.subscribers.length) { + // People listens to when("deleting") event. Must implement delete using WriteableCollection.delete() that will + // call the CRUD event. Only WriteableCollection.delete() will know whether an object was actually deleted. + return this.where(":id").equals(key).delete(); + } else { + // No one listens. Use standard IDB delete() method. + return this._idbstore(READWRITE, function (resolve, reject, idbstore) { + var req = idbstore.delete(key); + req.onerror = eventRejectHandler(reject, ["deleting", key, "from", idbstore.name]); + req.onsuccess = function () { + resolve(req.result); + }; + }); + } + }, + + clear: function () { + if (this.hook.deleting.subscribers.length) { + // People listens to when("deleting") event. Must implement delete using WriteableCollection.delete() that will + // call the CRUD event. Only WriteableCollection.delete() will knows which objects that are actually deleted. + return this.toCollection().delete(); + } else { + return this._idbstore(READWRITE, function (resolve, reject, idbstore) { + var req = idbstore.clear(); + req.onerror = eventRejectHandler(reject, ["clearing", idbstore.name]); + req.onsuccess = function () { + resolve(req.result); + }; + }); + } + }, + + update: function (keyOrObject, modifications) { + if (typeof modifications !== 'object' || isArray(modifications)) throw new exceptions.InvalidArgument("db.update(keyOrObject, modifications). modifications must be an object."); + if (typeof keyOrObject === 'object' && !isArray(keyOrObject)) { + // object to modify. Also modify given object with the modifications: + keys(modifications).forEach(function (keyPath) { + setByKeyPath(keyOrObject, keyPath, modifications[keyPath]); + }); + var key = getByKeyPath(keyOrObject, this.schema.primKey.keyPath); + if (key === undefined) Promise.reject(new exceptions.InvalidArgument("Given object does not contain its primary key")); + return this.where(":id").equals(key).modify(modifications); + } else { + // key to modify + return this.where(":id").equals(keyOrObject).modify(modifications); + } + } + }; + }); + + // + // + // + // Transaction Class + // + // + // + function Transaction(mode, storeNames, dbschema, parent) { + /// + /// Transaction class. Represents a database transaction. All operations on db goes through a Transaction. + /// + /// Any of "readwrite" or "readonly" + /// Array of table names to operate on + var self = this; + this.db = db; + this.mode = mode; + this.storeNames = storeNames; + this.idbtrans = null; + this.on = Events(this, ["complete", "error"], "abort"); + this._reculock = 0; + this._blockedFuncs = []; + this._psd = null; + this.active = true; + this._dbschema = dbschema; + if (parent) this.parent = parent; + this._tpf = transactionPromiseFactory; + this.tables = Object.create(notInTransFallbackTables); // ...so that all non-included tables exists as instances (possible to call table.name for example) but will fail as soon as trying to execute a query on it. + + function transactionPromiseFactory(mode, storeNames, fn, writeLocked) { + // Creates a Promise instance and calls fn (resolve, reject, trans) where trans is the instance of this transaction object. + // Support for write-locking the transaction during the promise life time from creation to success/failure. + // This is actually not needed when just using single operations on IDB, since IDB implements this internally. + // However, when implementing a write operation as a series of operations on top of IDB(collection.delete() and collection.modify() for example), + // lock is indeed needed if Dexie APIshould behave in a consistent manner for the API user. + // Another example of this is if we want to support create/update/delete events, + // we need to implement put() using a series of other IDB operations but still need to lock the transaction all the way. + return self._promise(mode, fn, writeLocked); + } + + for (var i = storeNames.length - 1; i !== -1; --i) { + var name = storeNames[i]; + var table = db._tableFactory(mode, dbschema[name], transactionPromiseFactory); + this.tables[name] = table; + if (!this[name]) this[name] = table; + } + } + + extendProto(Transaction.prototype, { + // + // Transaction Protected Methods (not required by API users, but needed internally and eventually by dexie extensions) + // + + _lock: function () { + // Temporary set all requests into a pending queue if they are called before database is ready. + ++this._reculock; // Recursive read/write lock pattern using PSD (Promise Specific Data) instead of TLS (Thread Local Storage) + if (this._reculock === 1 && Promise.PSD) Promise.PSD.lockOwnerFor = this; + return this; + }, + _unlock: function () { + if (--this._reculock === 0) { + if (Promise.PSD) Promise.PSD.lockOwnerFor = null; + while (this._blockedFuncs.length > 0 && !this._locked()) { + var fn = this._blockedFuncs.shift(); + try { + fn(); + } catch (e) {} + } + } + return this; + }, + _locked: function () { + // Checks if any write-lock is applied on this transaction. + // To simplify the Dexie API for extension implementations, we support recursive locks. + // This is accomplished by using "Promise Specific Data" (PSD). + // PSD data is bound to a Promise and any child Promise emitted through then() or resolve( new Promise() ). + // Promise.PSD is local to code executing on top of the call stacks of any of any code executed by Promise(): + // * callback given to the Promise() constructor (function (resolve, reject){...}) + // * callbacks given to then()/catch()/finally() methods (function (value){...}) + // 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. + // Derivation is done so that the inner PSD __proto__ points to the outer PSD. + // Promise.PSD.lockOwnerFor will point to current transaction object if the currently executing PSD scope owns the lock. + return this._reculock && (!Promise.PSD || Promise.PSD.lockOwnerFor !== this); + }, + _nop: function (cb) { + // An asyncronic no-operation that may call given callback when done doing nothing. An alternative to asap() if we must not lose the transaction. + this.tables[this.storeNames[0]].get(0).then(cb); + }, + _promise: function (mode, fn, bWriteLock) { + var self = this; + return Promise.newPSD(function () { + var p; + // Read lock always + if (!self._locked()) { + p = self.active ? new Promise(function (resolve, reject) { + if (!self.idbtrans && mode) { + if (!idbdb) throw !dbOpenError || ["DatabaseClosedError", "MissingAPIError"].indexOf(dbOpenError.name) >= 0 ? dbOpenError : // Errors where it is no difference whether it was caused by the user operation or an earlier call to db.open() + new exceptions.OpenFailed(dbOpenError); // Make it clear that the user operation was not what caused the error - the error had occurred earlier on db.open()! + + var idbtrans = self.idbtrans = idbdb.transaction(safariMultiStoreFix(self.storeNames), self.mode); + idbtrans.onerror = function (e) { + self.on("error").fire(e && e.target.error); + e.preventDefault(); // Prohibit default bubbling to window.error + self.abort(); // Make sure transaction is aborted since we preventDefault. + }; + idbtrans.onabort = function (e) { + // Workaround for issue #78 - low disk space on chrome. + // onabort is called but never onerror. Call onerror explicitely. + // Do this in a future tick so we allow default onerror to execute before doing the fallback. + asap(function () { + self.on('error').fire(new exceptions.Abort("Transaction aborted for unknown reason")); + }); + + self.active = false; + self.on("abort").fire(e); + }; + idbtrans.oncomplete = function (e) { + self.active = false; + self.on("complete").fire(e); + }; + } + if (bWriteLock) self._lock(); // Write lock if write operation is requested + try { + fn(resolve, reject, self); + } catch (e) { + // Direct exception happened when doing operation. + // We must immediately fire the error and abort the transaction. + // When this happens we are still constructing the Promise so we don't yet know + // whether the caller is about to catch() the error or not. Have to make + // transaction fail. Catching such an error wont stop transaction from failing. + // This is a limitation we have to live with. + var e2 = stack(mapError(e)); + Dexie.ignoreTransaction(function () { + self.on('error').fire(e2); + }); + self.abort(); + reject(e2); + } + }) : Promise.reject(stack(new exceptions.TransactionInactive("Transaction is inactive. Original Scope Function Source: " + self.scopeFunc.toString()))); + if (self.active && bWriteLock) p.finally(function () { + self._unlock(); + }); + } else { + // Transaction is write-locked. Wait for mutex. + p = new Promise(function (resolve, reject) { + self._blockedFuncs.push(function () { + self._promise(mode, fn, bWriteLock).then(resolve, reject); + }); + }); + } + p.onuncatched = function (e) { + // Bubble to transaction. Even though IDB does this internally, it would just do it for error events and not for caught exceptions. + Dexie.ignoreTransaction(function () { + self.on("error").fire(e); + }); + self.abort(); + }; + return p; + }); + }, + + // + // Transaction Public Methods + // + + complete: function (cb) { + return this.on("complete", cb); + }, + error: function (cb) { + return this.on("error", cb); + }, + abort: function () { + if (this.idbtrans && this.active) try { + // TODO: if !this.idbtrans, enqueue an abort() operation. + this.active = false; + this.idbtrans.abort(); + this.on.error.fire(new exceptions.Abort("Transaction Aborted")); + } catch (e) {} + }, + table: function (name) { + if (!this.tables.hasOwnProperty(name)) { + throw new exceptions.InvalidTable("Table " + name + " not in transaction"); + } + return this.tables[name]; + } + }); + + // + // + // + // WhereClause + // + // + // + function WhereClause(table, index, orCollection) { + /// + /// + /// + this._ctx = { + table: table, + index: index === ":id" ? null : index, + collClass: table._collClass, + or: orCollection + }; + } + + extendProto(WhereClause.prototype, function () { + + // WhereClause private methods + + function fail(c, err, T) { + var collection = c instanceof WhereClause ? new c._ctx.collClass(c) : c; + try { + throw T ? new T(err) : new TypeError(err); + } catch (e) { + collection._ctx.error = e; + } + return collection; + } + + function emptyCollection(whereClause) { + return new whereClause._ctx.collClass(whereClause, function () { + return IDBKeyRange.only(""); + }).limit(0); + } + + function getSetArgs(args) { + return slice(args.length === 1 && isArray(args[0]) ? args[0] : args); + } + + function upperFactory(dir) { + return dir === "next" ? function (s) { + return s.toUpperCase(); + } : function (s) { + return s.toLowerCase(); + }; + } + function lowerFactory(dir) { + return dir === "next" ? function (s) { + return s.toLowerCase(); + } : function (s) { + return s.toUpperCase(); + }; + } + function nextCasing(key, lowerKey, upperNeedle, lowerNeedle, cmp, dir) { + var length = Math.min(key.length, lowerNeedle.length); + var llp = -1; + for (var i = 0; i < length; ++i) { + var lwrKeyChar = lowerKey[i]; + if (lwrKeyChar !== lowerNeedle[i]) { + if (cmp(key[i], upperNeedle[i]) < 0) return key.substr(0, i) + upperNeedle[i] + upperNeedle.substr(i + 1); + if (cmp(key[i], lowerNeedle[i]) < 0) return key.substr(0, i) + lowerNeedle[i] + upperNeedle.substr(i + 1); + if (llp >= 0) return key.substr(0, llp) + lowerKey[llp] + upperNeedle.substr(llp + 1); + return null; + } + if (cmp(key[i], lwrKeyChar) < 0) llp = i; + } + if (length < lowerNeedle.length && dir === "next") return key + upperNeedle.substr(key.length); + if (length < key.length && dir === "prev") return key.substr(0, upperNeedle.length); + return llp < 0 ? null : key.substr(0, llp) + lowerNeedle[llp] + upperNeedle.substr(llp + 1); + } + + function addIgnoreCaseAlgorithm(whereClause, match, needles, suffix) { + /// + var upper, + lower, + compare, + upperNeedles, + lowerNeedles, + direction, + nextKeySuffix, + needlesLen = needles.length; + function initDirection(dir) { + upper = upperFactory(dir); + lower = lowerFactory(dir); + compare = dir === "next" ? simpleCompare : simpleCompareReverse; + var needleBounds = needles.map(function (needle) { + return { lower: lower(needle), upper: upper(needle) }; + }).sort(function (a, b) { + return compare(a.lower, b.lower); + }); + upperNeedles = needleBounds.map(function (nb) { + return nb.upper; + }); + lowerNeedles = needleBounds.map(function (nb) { + return nb.lower; + }); + direction = dir; + nextKeySuffix = dir === "next" ? "" : suffix; + } + initDirection("next"); + + var c = new whereClause._ctx.collClass(whereClause, function () { + return IDBKeyRange.bound(upperNeedles[0], lowerNeedles[needlesLen - 1] + suffix); + }); + + c._ondirectionchange = function (direction) { + // This event onlys occur before filter is called the first time. + initDirection(direction); + }; + + var firstPossibleNeedle = 0; + + c._addAlgorithm(function (cursor, advance, resolve) { + /// + /// + /// + var key = cursor.key; + if (typeof key !== 'string') return false; + var lowerKey = lower(key); + if (match(lowerKey, lowerNeedles, firstPossibleNeedle)) { + return true; + } else { + var lowestPossibleCasing = null; + for (var i = firstPossibleNeedle; i < needlesLen; ++i) { + var casing = nextCasing(key, lowerKey, upperNeedles[i], lowerNeedles[i], compare, direction); + if (casing === null && lowestPossibleCasing === null) firstPossibleNeedle = i + 1;else if (lowestPossibleCasing === null || compare(lowestPossibleCasing, casing) > 0) { + lowestPossibleCasing = casing; + } + } + if (lowestPossibleCasing !== null) { + advance(function () { + cursor.continue(lowestPossibleCasing + nextKeySuffix); + }); + } else { + advance(resolve); + } + return false; + } + }); + return c; + } + + // + // WhereClause public methods + // + return { + between: function (lower, upper, includeLower, includeUpper) { + /// + /// Filter out records whose where-field lays between given lower and upper values. Applies to Strings, Numbers and Dates. + /// + /// + /// + /// Whether items that equals lower should be included. Default true. + /// Whether items that equals upper should be included. Default false. + /// + includeLower = includeLower !== false; // Default to true + includeUpper = includeUpper === true; // Default to false + try { + 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. + return new this._ctx.collClass(this, function () { + return IDBKeyRange.bound(lower, upper, !includeLower, !includeUpper); + }); + } catch (e) { + return fail(this, INVALID_KEY_ARGUMENT); + } + }, + equals: function (value) { + return new this._ctx.collClass(this, function () { + return IDBKeyRange.only(value); + }); + }, + above: function (value) { + return new this._ctx.collClass(this, function () { + return IDBKeyRange.lowerBound(value, true); + }); + }, + aboveOrEqual: function (value) { + return new this._ctx.collClass(this, function () { + return IDBKeyRange.lowerBound(value); + }); + }, + below: function (value) { + return new this._ctx.collClass(this, function () { + return IDBKeyRange.upperBound(value, true); + }); + }, + belowOrEqual: function (value) { + return new this._ctx.collClass(this, function () { + return IDBKeyRange.upperBound(value); + }); + }, + startsWith: function (str) { + /// + if (typeof str !== 'string') return fail(this, STRING_EXPECTED); + return this.between(str, str + maxString, true, true); + }, + startsWithIgnoreCase: function (str) { + /// + if (typeof str !== 'string') return fail(this, STRING_EXPECTED); + if (str === "") return this.startsWith(str); + return addIgnoreCaseAlgorithm(this, function (x, a) { + return x.indexOf(a[0]) === 0; + }, [str], maxString); + }, + equalsIgnoreCase: function (str) { + /// + if (typeof str !== 'string') return fail(this, STRING_EXPECTED); + return addIgnoreCaseAlgorithm(this, function (x, a) { + return x === a[0]; + }, [str], ""); + }, + anyOfIgnoreCase: function () { + var set = getSetArgs(arguments); + if (set.length === 0) return emptyCollection(this); + if (!set.every(function (s) { + return typeof s === 'string'; + })) { + return fail(this, "anyOfIgnoreCase() only works with strings"); + } + return addIgnoreCaseAlgorithm(this, function (x, a) { + return a.indexOf(x) !== -1; + }, set, ""); + }, + startsWithAnyOfIgnoreCase: function () { + var set = getSetArgs(arguments); + if (set.length === 0) return emptyCollection(this); + if (!set.every(function (s) { + return typeof s === 'string'; + })) { + return fail(this, "startsWithAnyOfIgnoreCase() only works with strings"); + } + return addIgnoreCaseAlgorithm(this, function (x, a) { + return a.some(function (n) { + return x.indexOf(n) === 0; + }); + }, set, maxString); + }, + anyOf: function () { + var set = getSetArgs(arguments); + var compare = ascending; + try { + set.sort(compare); + } catch (e) { + return fail(this, INVALID_KEY_ARGUMENT); + } + if (set.length === 0) return emptyCollection(this); + var c = new this._ctx.collClass(this, function () { + return IDBKeyRange.bound(set[0], set[set.length - 1]); + }); + + c._ondirectionchange = function (direction) { + compare = direction === "next" ? ascending : descending; + set.sort(compare); + }; + var i = 0; + c._addAlgorithm(function (cursor, advance, resolve) { + var key = cursor.key; + while (compare(key, set[i]) > 0) { + // The cursor has passed beyond this key. Check next. + ++i; + if (i === set.length) { + // There is no next. Stop searching. + advance(resolve); + return false; + } + } + if (compare(key, set[i]) === 0) { + // 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. + return true; + } else { + // cursor.key not yet at set[i]. Forward cursor to the next key to hunt for. + advance(function () { + cursor.continue(set[i]); + }); + return false; + } + }); + return c; + }, + + notEqual: function (value) { + return this.inAnyRange([[-Infinity, value], [value, maxKey]], { includeLowers: false, includeUppers: false }); + }, + + noneOf: function () { + var set = getSetArgs(arguments); + if (set.length === 0) return new this._ctx.collClass(this); // Return entire collection. + try { + set.sort(ascending); + } catch (e) { + return fail(this, INVALID_KEY_ARGUMENT); + } + // Transform ["a","b","c"] to a set of ranges for between/above/below: [[-Infinity,"a"], ["a","b"], ["b","c"], ["c",maxKey]] + var ranges = set.reduce(function (res, val) { + return res ? res.concat([[res[res.length - 1][1], val]]) : [[-Infinity, val]]; + }, null); + ranges.push([set[set.length - 1], maxKey]); + return this.inAnyRange(ranges, { includeLowers: false, includeUppers: false }); + }, + + /** Filter out values withing given set of ranges. + * Example, give children and elders a rebate of 50%: + * + * db.friends.where('age').inAnyRange([[0,18],[65,Infinity]]).modify({Rebate: 1/2}); + * + * @param {(string|number|Date|Array)[][]} ranges + * @param {{includeLowers: boolean, includeUppers: boolean}} options + */ + inAnyRange: function (ranges, options) { + var ctx = this._ctx; + if (ranges.length === 0) return emptyCollection(this); + if (!ranges.every(function (range) { + return range[0] !== undefined && range[1] !== undefined && ascending(range[0], range[1]) <= 0; + })) { + 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); + } + var includeLowers = !options || options.includeLowers !== false; // Default to true + var includeUppers = options && options.includeUppers === true; // Default to false + + function addRange(ranges, newRange) { + for (var i = 0, l = ranges.length; i < l; ++i) { + var range = ranges[i]; + if (cmp(newRange[0], range[1]) < 0 && cmp(newRange[1], range[0]) > 0) { + range[0] = min(range[0], newRange[0]); + range[1] = max(range[1], newRange[1]); + break; + } + } + if (i === l) ranges.push(newRange); + return ranges; + } + + var sortDirection = ascending; + function rangeSorter(a, b) { + return sortDirection(a[0], b[0]); + } + + // Join overlapping ranges + var set; + try { + set = ranges.reduce(addRange, []); + set.sort(rangeSorter); + } catch (ex) { + return fail(this, INVALID_KEY_ARGUMENT); + } + + var i = 0; + var keyIsBeyondCurrentEntry = includeUppers ? function (key) { + return ascending(key, set[i][1]) > 0; + } : function (key) { + return ascending(key, set[i][1]) >= 0; + }; + + var keyIsBeforeCurrentEntry = includeLowers ? function (key) { + return descending(key, set[i][0]) > 0; + } : function (key) { + return descending(key, set[i][0]) >= 0; + }; + + function keyWithinCurrentRange(key) { + return !keyIsBeyondCurrentEntry(key) && !keyIsBeforeCurrentEntry(key); + } + + var checkKey = keyIsBeyondCurrentEntry; + + var c = new ctx.collClass(this, function () { + return IDBKeyRange.bound(set[0][0], set[set.length - 1][1], !includeLowers, !includeUppers); + }); + + c._ondirectionchange = function (direction) { + if (direction === "next") { + checkKey = keyIsBeyondCurrentEntry; + sortDirection = ascending; + } else { + checkKey = keyIsBeforeCurrentEntry; + sortDirection = descending; + } + set.sort(rangeSorter); + }; + + c._addAlgorithm(function (cursor, advance, resolve) { + var key = cursor.key; + while (checkKey(key)) { + // The cursor has passed beyond this key. Check next. + ++i; + if (i === set.length) { + // There is no next. Stop searching. + advance(resolve); + return false; + } + } + if (keyWithinCurrentRange(key)) { + // 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. + return true; + } else if (cmp(key, set[i][1]) === 0 || cmp(key, set[i][0]) === 0) { + // includeUpper or includeLower is false so keyWithinCurrentRange() returns false even though we are at range border. + // Continue to next key but don't include this one. + return false; + } else { + // cursor.key not yet at set[i]. Forward cursor to the next key to hunt for. + advance(function () { + if (sortDirection === ascending) cursor.continue(set[i][0]);else cursor.continue(set[i][1]); + }); + return false; + } + }); + return c; + }, + startsWithAnyOf: function () { + var set = getSetArgs(arguments); + + if (!set.every(function (s) { + return typeof s === 'string'; + })) { + return fail(this, "startsWithAnyOf() only works with strings"); + } + if (set.length === 0) return emptyCollection(this); + + return this.inAnyRange(set.map(function (str) { + return [str, str + maxString]; + })); + } + }; + }); + + // + // + // + // Collection Class + // + // + // + function Collection(whereClause, keyRangeGenerator) { + /// + /// + /// + /// Where clause instance + /// + var keyRange = null, + error = null; + if (keyRangeGenerator) try { + keyRange = keyRangeGenerator(); + } catch (ex) { + error = stack(mapError(ex)); + } + + var whereCtx = whereClause._ctx, + table = whereCtx.table; + this._ctx = { + table: table, + index: whereCtx.index, + isPrimKey: !whereCtx.index || table.schema.primKey.keyPath && whereCtx.index === table.schema.primKey.name, + range: keyRange, + keysOnly: false, + dir: "next", + unique: "", + algorithm: null, + filter: null, + replayFilter: null, + isMatch: null, + offset: 0, + limit: Infinity, + error: error, // If set, any promise must be rejected with this error + or: whereCtx.or, + valueFilter: table.hook.reading.fire + }; + } + + extendProto(Collection.prototype, function () { + + // + // Collection Private Functions + // + + function addFilter(ctx, fn) { + ctx.filter = combine(ctx.filter, fn); + } + + function addReplayFilter(ctx, factory) { + var curr = ctx.replayFilter; + ctx.replayFilter = curr ? function () { + return combine(curr(), factory()); + } : factory; + } + + function addMatchFilter(ctx, fn) { + ctx.isMatch = combine(ctx.isMatch, fn); + } + + function getIndexOrStore(ctx, store) { + if (ctx.isPrimKey) return store; + var indexSpec = ctx.table.schema.idxByName[ctx.index]; + if (!indexSpec) throw new exceptions.Schema("KeyPath " + ctx.index + " on object store " + store.name + " is not indexed"); + return store.index(indexSpec.name); + } + + function openCursor(ctx, store) { + var idxOrStore = getIndexOrStore(ctx, store); + return ctx.keysOnly && 'openKeyCursor' in idxOrStore ? idxOrStore.openKeyCursor(ctx.range || null, ctx.dir + ctx.unique) : idxOrStore.openCursor(ctx.range || null, ctx.dir + ctx.unique); + } + + function iter(ctx, fn, resolve, reject, idbstore) { + var filter = ctx.replayFilter ? combine(ctx.filter, ctx.replayFilter()) : ctx.filter; + if (!ctx.or) { + iterate(openCursor(ctx, idbstore), combine(ctx.algorithm, filter), fn, resolve, reject, !ctx.keysOnly && ctx.valueFilter); + } else { + (function () { + var set = {}; + var resolved = 0; + + function resolveboth() { + if (++resolved === 2) resolve(); // Seems like we just support or btwn max 2 expressions, but there are no limit because we do recursion. + } + + function union(item, cursor, advance) { + if (!filter || filter(cursor, advance, resolveboth, reject)) { + var key = cursor.primaryKey.toString(); // Converts any Date to String, String to String, Number to String and Array to comma-separated string + if (!set.hasOwnProperty(key)) { + set[key] = true; + fn(item, cursor, advance); + } + } + } + + ctx.or._iterate(union, resolveboth, reject, idbstore); + iterate(openCursor(ctx, idbstore), ctx.algorithm, union, resolveboth, reject, !ctx.keysOnly && ctx.valueFilter); + })(); + } + } + function getInstanceTemplate(ctx) { + return ctx.table.schema.instanceTemplate; + } + + return { + + // + // Collection Protected Functions + // + + _read: function (fn, cb) { + var ctx = this._ctx; + if (ctx.error) return ctx.table._trans(null, function rejector(resolve, reject) { + reject(ctx.error); + });else return ctx.table._idbstore(READONLY, fn).then(cb); + }, + _write: function (fn) { + var ctx = this._ctx; + if (ctx.error) return ctx.table._trans(null, function rejector(resolve, reject) { + reject(ctx.error); + });else return ctx.table._idbstore(READWRITE, fn, "locked"); // When doing write operations on collections, always lock the operation so that upcoming operations gets queued. + }, + _addAlgorithm: function (fn) { + var ctx = this._ctx; + ctx.algorithm = combine(ctx.algorithm, fn); + }, + + _iterate: function (fn, resolve, reject, idbstore) { + return iter(this._ctx, fn, resolve, reject, idbstore); + }, + + clone: function (props) { + var rv = Object.create(this.constructor.prototype), + ctx = Object.create(this._ctx); + if (props) extend(ctx, props); + rv._ctx = ctx; + return rv; + }, + + raw: function () { + this._ctx.valueFilter = null; + return this; + }, + + // + // Collection Public methods + // + + each: function (fn) { + var ctx = this._ctx; + + fake && fn(getInstanceTemplate(ctx)); + + return this._read(function (resolve, reject, idbstore) { + iter(ctx, fn, resolve, reject, idbstore); + }); + }, + + count: function (cb) { + if (fake) return Promise.resolve(0).then(cb); + var self = this, + ctx = this._ctx; + + if (ctx.filter || ctx.algorithm || ctx.or || ctx.replayFilter) { + // When filters are applied or 'ored' collections are used, we must count manually + var count = 0; + return this._read(function (resolve, reject, idbstore) { + iter(ctx, function () { + ++count;return false; + }, function () { + resolve(count); + }, reject, idbstore); + }, cb); + } else { + // Otherwise, we can use the count() method if the index. + return this._read(function (resolve, reject, idbstore) { + var idx = getIndexOrStore(ctx, idbstore); + var req = ctx.range ? idx.count(ctx.range) : idx.count(); + req.onerror = eventRejectHandler(reject, ["calling", "count()", "on", self.name]); + req.onsuccess = function (e) { + resolve(e.target.result); + }; + }, cb); + } + }, + + sortBy: function (keyPath, cb) { + /// + var parts = keyPath.split('.').reverse(), + lastPart = parts[0], + lastIndex = parts.length - 1; + function getval(obj, i) { + if (i) return getval(obj[parts[i]], i - 1); + return obj[lastPart]; + } + var order = this._ctx.dir === "next" ? 1 : -1; + + function sorter(a, b) { + var aVal = getval(a, lastIndex), + bVal = getval(b, lastIndex); + return aVal < bVal ? -order : aVal > bVal ? order : 0; + } + return this.toArray(function (a) { + return a.sort(sorter); + }).then(cb); + }, + + toArray: function (cb) { + var ctx = this._ctx; + return this._read(function (resolve, reject, idbstore) { + fake && resolve([getInstanceTemplate(ctx)]); + var a = []; + iter(ctx, function (item) { + a.push(item); + }, function arrayComplete() { + resolve(a); + }, reject, idbstore); + }, cb); + }, + + offset: function (offset) { + var ctx = this._ctx; + if (offset <= 0) return this; + ctx.offset += offset; // For count() + if (!ctx.or && !ctx.algorithm && !ctx.filter && !ctx.replayFilter) { + addReplayFilter(ctx, function () { + var offsetLeft = offset; + return function (cursor, advance) { + if (offsetLeft === 0) return true; + if (offsetLeft === 1) { + --offsetLeft;return false; + } + advance(function () { + cursor.advance(offsetLeft); + offsetLeft = 0; + }); + return false; + }; + }); + } else { + addReplayFilter(ctx, function () { + var offsetLeft = offset; + return function () { + return --offsetLeft < 0; + }; + }); + } + return this; + }, + + limit: function (numRows) { + this._ctx.limit = Math.min(this._ctx.limit, numRows); // For count() + addReplayFilter(this._ctx, function () { + var rowsLeft = numRows; + return function (cursor, advance, resolve) { + if (--rowsLeft <= 0) advance(resolve); // Stop after this item has been included + return rowsLeft >= 0; // If numRows is already below 0, return false because then 0 was passed to numRows initially. Otherwise we wouldnt come here. + }; + }); + return this; + }, + + until: function (filterFunction, bIncludeStopEntry) { + var ctx = this._ctx; + fake && filterFunction(getInstanceTemplate(ctx)); + addFilter(this._ctx, function (cursor, advance, resolve) { + if (filterFunction(cursor.value)) { + advance(resolve); + return bIncludeStopEntry; + } else { + return true; + } + }); + return this; + }, + + first: function (cb) { + return this.limit(1).toArray(function (a) { + return a[0]; + }).then(cb); + }, + + last: function (cb) { + return this.reverse().first(cb); + }, + + filter: function (filterFunction) { + /// function(val){return true/false} + fake && filterFunction(getInstanceTemplate(this._ctx)); + addFilter(this._ctx, function (cursor) { + return filterFunction(cursor.value); + }); + addMatchFilter(this._ctx, filterFunction); // match filters not used in Dexie.js but can be used by 3rd part libraries to test a collection for a match without querying DB. Used by Dexie.Observable. + return this; + }, + + and: function (filterFunction) { + return this.filter(filterFunction); + }, + + or: function (indexName) { + return new WhereClause(this._ctx.table, indexName, this); + }, + + reverse: function () { + this._ctx.dir = this._ctx.dir === "prev" ? "next" : "prev"; + if (this._ondirectionchange) this._ondirectionchange(this._ctx.dir); + return this; + }, + + desc: function () { + return this.reverse(); + }, + + eachKey: function (cb) { + var ctx = this._ctx; + fake && cb(getByKeyPath(getInstanceTemplate(this._ctx), this._ctx.index ? this._ctx.table.schema.idxByName[this._ctx.index].keyPath : this._ctx.table.schema.primKey.keyPath)); + ctx.keysOnly = !ctx.isMatch; + return this.each(function (val, cursor) { + cb(cursor.key, cursor); + }); + }, + + eachUniqueKey: function (cb) { + this._ctx.unique = "unique"; + return this.eachKey(cb); + }, + + keys: function (cb) { + var ctx = this._ctx; + ctx.keysOnly = !ctx.isMatch; + var a = []; + if (fake) return new Promise(this.eachKey.bind(this)).then(function (x) { + return [x]; + }).then(cb); + return this.each(function (item, cursor) { + a.push(cursor.key); + }).then(function () { + return a; + }).then(cb); + }, + + uniqueKeys: function (cb) { + this._ctx.unique = "unique"; + return this.keys(cb); + }, + + firstKey: function (cb) { + return this.limit(1).keys(function (a) { + return a[0]; + }).then(cb); + }, + + lastKey: function (cb) { + return this.reverse().firstKey(cb); + }, + + distinct: function () { + var ctx = this._ctx, + idx = ctx.index && ctx.table.schema.idxByName[ctx.index]; + if (!idx || !idx.multi) return this; // distinct() only makes differencies on multiEntry indexes. + var set = {}; + addFilter(this._ctx, function (cursor) { + var strKey = cursor.primaryKey.toString(); // Converts any Date to String, String to String, Number to String and Array to comma-separated string + var found = set.hasOwnProperty(strKey); + set[strKey] = true; + return !found; + }); + return this; + } + }; + }); + + // + // + // WriteableCollection Class + // + // + function WriteableCollection() { + Collection.apply(this, arguments); + } + + derive(WriteableCollection).from(Collection).extend({ + + // + // WriteableCollection Public Methods + // + + modify: function (changes) { + var self = this, + ctx = this._ctx, + hook = ctx.table.hook, + updatingHook = hook.updating.fire, + deletingHook = hook.deleting.fire; + + fake && typeof changes === 'function' && changes.call({ value: ctx.table.schema.instanceTemplate }, ctx.table.schema.instanceTemplate); + + return this._write(function (resolve, reject, idbstore, trans) { + var modifyer; + if (typeof changes === 'function') { + // Changes is a function that may update, add or delete propterties or even require a deletion the object itself (delete this.item) + if (updatingHook === nop && deletingHook === nop) { + // Noone cares about what is being changed. Just let the modifier function be the given argument as is. + modifyer = changes; + } else { + // People want to know exactly what is being modified or deleted. + // Let modifyer be a proxy function that finds out what changes the caller is actually doing + // and call the hooks accordingly! + modifyer = function (item) { + var origItem = deepClone(item); // Clone the item first so we can compare laters. + 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) + if (!this.hasOwnProperty("value")) { + // The real modifyer function requests a deletion of the object. Inform the deletingHook that a deletion is taking place. + deletingHook.call(this, this.primKey, item, trans); + } else { + // No deletion. Check what was changed + var objectDiff = getObjectDiff(origItem, this.value); + var additionalChanges = updatingHook.call(this, objectDiff, this.primKey, origItem, trans); + if (additionalChanges) { + // Hook want to apply additional modifications. Make sure to fullfill the will of the hook. + item = this.value; + keys(additionalChanges).forEach(function (keyPath) { + setByKeyPath(item, keyPath, additionalChanges[keyPath]); // Adding {keyPath: undefined} means that the keyPath should be deleted. Handled by setByKeyPath + }); + } + } + }; + } + } else if (updatingHook === nop) { + // changes is a set of {keyPath: value} and no one is listening to the updating hook. + var keyPaths = keys(changes); + var numKeys = keyPaths.length; + modifyer = function (item) { + var anythingModified = false; + for (var i = 0; i < numKeys; ++i) { + var keyPath = keyPaths[i], + val = changes[keyPath]; + if (getByKeyPath(item, keyPath) !== val) { + setByKeyPath(item, keyPath, val); // Adding {keyPath: undefined} means that the keyPath should be deleted. Handled by setByKeyPath + anythingModified = true; + } + } + return anythingModified; + }; + } else { + // changes is a set of {keyPath: value} and people are listening to the updating hook so we need to call it and + // allow it to add additional modifications to make. + var origChanges = changes; + 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. + modifyer = function (item) { + var anythingModified = false; + var additionalChanges = updatingHook.call(this, changes, this.primKey, deepClone(item), trans); + if (additionalChanges) extend(changes, additionalChanges); + keys(changes).forEach(function (keyPath) { + var val = changes[keyPath]; + if (getByKeyPath(item, keyPath) !== val) { + setByKeyPath(item, keyPath, val); + anythingModified = true; + } + }); + if (additionalChanges) changes = shallowClone(origChanges); // Restore original changes for next iteration + return anythingModified; + }; + } + + var count = 0; + var successCount = 0; + var iterationComplete = false; + var failures = []; + var failKeys = []; + var currentKey = null; + + function modifyItem(item, cursor) { + currentKey = cursor.primaryKey; + var thisContext = { + primKey: cursor.primaryKey, + value: item, + onsuccess: null, + onerror: null + }; + + function onerror(e) { + failures.push(e); + failKeys.push(thisContext.primKey); + if (thisContext.onerror) Promise.newPSD(function () { + Promise.PSD.trans = trans; + thisContext.onerror(e); + }); + checkFinished(); + return true; // Catch these errors and let a final rejection decide whether or not to abort entire transaction + } + + if (modifyer.call(thisContext, item, thisContext) !== false) { + // If a callback explicitely returns false, do not perform the update! + var bDelete = !thisContext.hasOwnProperty("value"); + ++count; + miniTryCatch(function () { + var req = bDelete ? cursor.delete() : cursor.update(thisContext.value); + req.onerror = eventRejectHandler(onerror, bDelete ? ["deleting", item, "from", ctx.table.name] : ["modifying", item, "on", ctx.table.name]); + req.onsuccess = function () { + if (thisContext.onsuccess) Promise.newPSD(function () { + Promise.PSD.trans = trans; + thisContext.onsuccess(thisContext.value); + }); + ++successCount; + checkFinished(); + }; + }, onerror); + } else if (thisContext.onsuccess) { + // Hook will expect either onerror or onsuccess to always be called! + thisContext.onsuccess(thisContext.value); + } + } + + function doReject(e) { + if (e) { + failures.push(e); + failKeys.push(currentKey); + } + return reject(new ModifyError("Error modifying one or more objects", failures, successCount, failKeys)); + } + + function checkFinished() { + if (iterationComplete && successCount + failures.length === count) { + if (failures.length > 0) doReject();else resolve(successCount); + } + } + self.clone().raw()._iterate(modifyItem, function () { + iterationComplete = true; + checkFinished(); + }, doReject, idbstore); + }); + }, + + 'delete': function () { + var _this2 = this; + + var ctx = this._ctx, + range = ctx.range, + deletingHook = ctx.table.hook.deleting.fire, + hasDeleteHook = deletingHook !== nop; + if (!hasDeleteHook && !ctx.or && !ctx.algorithm && !ctx.filter && !ctx.replayFilter && (ctx.isPrimKey && !hangsOnDeleteLargeKeyRange || !range)) // if no range, we'll use clear(). + { + // May use IDBObjectStore.delete(IDBKeyRange) in this case (Issue #208) + // For chromium, this is the way most optimized version. + // For IE/Edge, this could hang the indexedDB engine and make operating system instable + // (https://gist.github.com/dfahlander/5a39328f029de18222cf2125d56c38f7) + return this._write(function (resolve, reject, idbstore) { + // Our API contract is to return a count of deleted items, so we have to count() before delete(). + var onerror = eventRejectHandler(reject, ["deleting range from", ctx.table.name]), + countReq = range ? idbstore.count(range) : idbstore.count(); + countReq.onerror = onerror; + countReq.onsuccess = function () { + var count = countReq.result; + miniTryCatch(function () { + var delReq = range ? idbstore.delete(range) : idbstore.clear(); + delReq.onerror = onerror; + delReq.onsuccess = function () { + return resolve(count); + }; + }, function (err) { + return reject(mapError(err)); + }); + }; + }); + } + + // Default version to use when collection is not a vanilla IDBKeyRange on the primary key. + // Divide into chunks to not starve RAM. + // If has delete hook, we will have to collect not just keys but also objects, so it will use + // more memory and need lower chunk size. + var CHUNKSIZE = hasDeleteHook ? 2000 : 10000; + + return this._write(function (resolve, reject, idbstore, trans) { + var totalCount = 0; + // Clone table and change the way transaction promises are generated. + // This is to be able to call other Collection methods within the same + // transaction even if the caller calls us without a transaction. + var table = Object.create(ctx.table); + table._tpf = trans._tpf; // Enable us to keep same transaction even if called without transaction. + // Clone collection and change its table and set a limit of CHUNKSIZE on the cloned Collection instance. + var collection = _this2.clone({ + table: table, // Execute in same transaction + keysOnly: !ctx.isMatch && !hasDeleteHook }) // load just keys (unless filter() or and() or deleteHook has subscribers) + .distinct() // In case multiEntry is used, never delete same key twice because resulting count + // would become larger than actual delete count. + .limit(CHUNKSIZE).raw(); // Don't filter through reading-hooks (like mapped classes etc) + + var keysOrTuples = []; + + // We're gonna do things on as many chunks that are needed. + // Use recursion of nextChunk function: + var nextChunk = function () { + return collection.each(hasDeleteHook ? function (val, cursor) { + // Somebody subscribes to hook('deleting'). Collect all primary keys and their values, + // so that the hook can be called with its values in bulkDelete(). + keysOrTuples.push([cursor.primaryKey, cursor.value]); + } : function (val, cursor) { + // No one subscribes to hook('deleting'). Collect only primary keys: + keysOrTuples.push(cursor.primaryKey); + }).then(function () { + // Chromium deletes faster when doing it in sort order. + hasDeleteHook ? keysOrTuples.sort(function (a, b) { + return ascending(a[0], b[0]); + }) : keysOrTuples.sort(ascending); + return bulkDelete(idbstore, trans, keysOrTuples, hasDeleteHook, deletingHook); + }).then(function () { + var count = keysOrTuples.length; + totalCount += count; + keysOrTuples = []; + return count < CHUNKSIZE ? totalCount : nextChunk(); + }); + }; + + resolve(nextChunk()); + }); + } + }); + + // + // + // + // ------------------------- Help functions --------------------------- + // + // + // + + function lowerVersionFirst(a, b) { + return a._cfg.version - b._cfg.version; + } + + function setApiOnPlace(objs, transactionPromiseFactory, tableNames, mode, dbschema, enableProhibitedDB) { + tableNames.forEach(function (tableName) { + var tableInstance = db._tableFactory(mode, dbschema[tableName], transactionPromiseFactory); + objs.forEach(function (obj) { + if (!obj[tableName]) { + if (enableProhibitedDB) { + setProp(obj, tableName, { + get: function () { + var currentTrans = Promise.PSD && Promise.PSD.trans; + if (currentTrans && currentTrans.db === db) { + return currentTrans.tables[tableName]; + } + return tableInstance; + } + }, { enumerable: true }); + } else { + obj[tableName] = tableInstance; + } + } + }); + }); + } + + function removeTablesApi(objs) { + objs.forEach(function (obj) { + for (var key in obj) { + if (obj[key] instanceof Table) delete obj[key]; + } + }); + } + + function iterate(req, filter, fn, resolve, reject, valueFilter) { + valueFilter = valueFilter || mirror; + if (!req.onerror) req.onerror = eventRejectHandler(reject); + if (filter) { + req.onsuccess = trycatch(function filter_record() { + var cursor = req.result; + if (cursor) { + var c = function () { + cursor.continue(); + }; + if (filter(cursor, function (advancer) { + c = advancer; + }, resolve, reject)) fn(valueFilter(cursor.value), cursor, function (advancer) { + c = advancer; + }); + c(); + } else { + resolve(); + } + }, reject); + } else { + req.onsuccess = trycatch(function filter_record() { + var cursor = req.result; + if (cursor) { + var c = function () { + cursor.continue(); + }; + fn(valueFilter(cursor.value), cursor, function (advancer) { + c = advancer; + }); + c(); + } else { + resolve(); + } + }, reject); + } + } + + function parseIndexSyntax(indexes) { + /// + /// + var rv = []; + indexes.split(',').forEach(function (index) { + index = index.trim(); + var name = index.replace("&", "").replace("++", "").replace("*", ""); + var keyPath = name.indexOf('[') !== 0 ? name : index.substring(index.indexOf('[') + 1, index.indexOf(']')).split('+'); + + rv.push(new IndexSpec(name, keyPath || null, index.indexOf('&') !== -1, index.indexOf('*') !== -1, index.indexOf("++") !== -1, isArray(keyPath), keyPath.indexOf('.') !== -1)); + }); + return rv; + } + + function cmp(key1, key2) { + return indexedDB.cmp(key1, key2); + } + + function min(a, b) { + return cmp(a, b) < 0 ? a : b; + } + + function max(a, b) { + return cmp(a, b) > 0 ? a : b; + } + + function ascending(a, b) { + return indexedDB.cmp(a, b); + } + + function descending(a, b) { + return indexedDB.cmp(b, a); + } + + function simpleCompare(a, b) { + return a < b ? -1 : a === b ? 0 : 1; + } + + function simpleCompareReverse(a, b) { + return a > b ? -1 : a === b ? 0 : 1; + } + + function combine(filter1, filter2) { + return filter1 ? filter2 ? function () { + return filter1.apply(this, arguments) && filter2.apply(this, arguments); + } : filter1 : filter2; + } + + function readGlobalSchema() { + db.verno = idbdb.version / 10; + db._dbSchema = globalSchema = {}; + dbStoreNames = slice(idbdb.objectStoreNames, 0); + if (dbStoreNames.length === 0) return; // Database contains no stores. + var trans = idbdb.transaction(safariMultiStoreFix(dbStoreNames), 'readonly'); + dbStoreNames.forEach(function (storeName) { + var store = trans.objectStore(storeName), + keyPath = store.keyPath, + dotted = keyPath && typeof keyPath === 'string' && keyPath.indexOf('.') !== -1; + var primKey = new IndexSpec(keyPath, keyPath || "", false, false, !!store.autoIncrement, keyPath && typeof keyPath !== 'string', dotted); + var indexes = []; + for (var j = 0; j < store.indexNames.length; ++j) { + var idbindex = store.index(store.indexNames[j]); + keyPath = idbindex.keyPath; + dotted = keyPath && typeof keyPath === 'string' && keyPath.indexOf('.') !== -1; + var index = new IndexSpec(idbindex.name, keyPath, !!idbindex.unique, !!idbindex.multiEntry, false, keyPath && typeof keyPath !== 'string', dotted); + indexes.push(index); + } + globalSchema[storeName] = new TableSchema(storeName, primKey, indexes, {}); + }); + setApiOnPlace([allTables], db._transPromiseFactory, keys(globalSchema), READWRITE, globalSchema); + } + + function adjustToExistingIndexNames(schema, idbtrans) { + /// + /// Issue #30 Problem with existing db - adjust to existing index names when migrating from non-dexie db + /// + /// Map between name and TableSchema + /// + var storeNames = idbtrans.db.objectStoreNames; + for (var i = 0; i < storeNames.length; ++i) { + var storeName = storeNames[i]; + var store = idbtrans.objectStore(storeName); + for (var j = 0; j < store.indexNames.length; ++j) { + var indexName = store.indexNames[j]; + var keyPath = store.index(indexName).keyPath; + var dexieName = typeof keyPath === 'string' ? keyPath : "[" + slice(keyPath).join('+') + "]"; + if (schema[storeName]) { + var indexSpec = schema[storeName].idxByName[dexieName]; + if (indexSpec) indexSpec.name = indexName; + } + } + } + } + + function fireOnBlocked(ev) { + db.on("blocked").fire(ev); + // Workaround (not fully*) for missing "versionchange" event in IE,Edge and Safari: + connections.filter(function (c) { + return c.name === db.name && c !== db && !c._vcFired; + }).map(function (c) { + return c.on("versionchange").fire(ev); + }); + } + + extend(this, { + Collection: Collection, + Table: Table, + Transaction: Transaction, + Version: Version, + WhereClause: WhereClause, + WriteableCollection: WriteableCollection, + WriteableTable: WriteableTable + }); + + init(); + + addons.forEach(function (fn) { + fn(db); + }); + } + + var fakeAutoComplete = function () {}; // Will never be changed. We just fake for the IDE that we change it (see doFakeAutoComplete()) + var fake = false; // Will never be changed. We just fake for the IDE that we change it (see doFakeAutoComplete()) + + function trycatch(fn, reject) { + var psd = Promise.PSD; + return function () { + var outerPSD = Promise.PSD; // Support Promise-specific data (PSD) in callback calls + Promise.PSD = psd; + try { + fn.apply(this, arguments); + } catch (e) { + reject(e); + } finally { + Promise.PSD = outerPSD; + } + }; + } + + function parseType(type) { + if (typeof type === 'function') { + return new type(); + } else if (isArray(type)) { + return [parseType(type[0])]; + } else if (type && typeof type === 'object') { + var rv = {}; + applyStructure(rv, type); + return rv; + } else { + return type; + } + } + + function applyStructure(obj, structure) { + keys(structure).forEach(function (member) { + var value = parseType(structure[member]); + obj[member] = value; + }); + return obj; + } + + function eventRejectHandler(reject, sentance) { + return function (event) { + var errObj = event && event.target.error || new Error(""); + if (sentance) { + var occurredWhen = " occurred when " + sentance.map(function (word) { + switch (typeof word) { + case 'function': + return word(); + case 'string': + return word; + default: + return JSON.stringify(word); + } + }).join(" "); + if (errObj.message && errObj.message != errObj.name) occurredWhen += ". " + errObj.message; + if (errObj.name) { + errObj = mapError(errObj, errObj.name + occurredWhen); + } else { + // Non-standard exceptions from IndexedDBPolyfill + errObj = errObj + occurredWhen; + } + } + reject(errObj); + + if (event) { + // Old versions of IndexedDBShim doesnt provide an error event + // Stop error from propagating to IDBTransaction. Let us handle that manually instead. + if (event.stopPropagation) // IndexedDBShim doesnt support this + event.stopPropagation(); + if (event.preventDefault) // IndexedDBShim doesnt support this + event.preventDefault(); + } + + return false; + }; + } + + function preventDefault(e) { + e.preventDefault(); + } + + function globalDatabaseList(cb) { + var val, + localStorage = Dexie.dependencies.localStorage; + if (!localStorage) return cb([]); // Envs without localStorage support + try { + val = JSON.parse(localStorage.getItem('Dexie.DatabaseNames') || "[]"); + } catch (e) { + val = []; + } + if (cb(val)) { + localStorage.setItem('Dexie.DatabaseNames', JSON.stringify(val)); + } + } + + function awaitIterable(iterable) { + var callNext = function (result) { + return iterable.next(result); + }, + doThrow = function (error) { + return iterable.throw(error); + }, + onSuccess = step(callNext), + onError = step(doThrow); + + function step(getNext) { + return function (val) { + var next = getNext(val), + value = next.value; + + return next.done ? value : !value || typeof value.then !== 'function' ? Array.isArray(value) ? awaitAll(value, 0) : onSuccess(value) : value.then(onSuccess, onError); + }; + } + + function awaitAll(values, i) { + if (i === values.length) return onSuccess(values); + var value = values[i]; + return value.constructor && typeof value.constructor.all == 'function' ? value.constructor.all(values).then(onSuccess, onError) : awaitAll(values, i + 1); + } + + return step(callNext)(); + } + + // + // IndexSpec struct + // + function IndexSpec(name, keyPath, unique, multi, auto, compound, dotted) { + /// + /// + /// + /// + /// + /// + /// + this.name = name; + this.keyPath = keyPath; + this.unique = unique; + this.multi = multi; + this.auto = auto; + this.compound = compound; + this.dotted = dotted; + var keyPathSrc = typeof keyPath === 'string' ? keyPath : keyPath && '[' + [].join.call(keyPath, '+') + ']'; + this.src = (unique ? '&' : '') + (multi ? '*' : '') + (auto ? "++" : "") + keyPathSrc; + } + + // + // TableSchema struct + // + function TableSchema(name, primKey, indexes, instanceTemplate) { + /// + /// + /// + /// + this.name = name; + this.primKey = primKey || new IndexSpec(); + this.indexes = indexes || [new IndexSpec()]; + this.instanceTemplate = instanceTemplate; + this.mappedClass = null; + this.idxByName = indexes.reduce(function (hashSet, index) { + hashSet[index.name] = index; + return hashSet; + }, {}); + } + + // + // Static delete() method. + // + Dexie.delete = function (databaseName) { + var db = new Dexie(databaseName), + promise = db.delete(); + promise.onblocked = function (fn) { + db.on("blocked", fn); + return this; + }; + return promise; + }; + + // + // Static exists() method. + // + Dexie.exists = function (name) { + return new Dexie(name).open().then(function (db) { + db.close(); + return true; + }).catch(Dexie.NoSuchDatabaseError, function () { + return false; + }); + }; + + // + // Static method for retrieving a list of all existing databases at current host. + // + Dexie.getDatabaseNames = function (cb) { + return new Promise(function (resolve, reject) { + var getDatabaseNames = getNativeGetDatabaseNamesFn(indexedDB); + if (getDatabaseNames) { + // In case getDatabaseNames() becomes standard, let's prepare to support it: + var req = getDatabaseNames(); + req.onsuccess = function (event) { + resolve(slice(event.target.result, 0)); // Converst DOMStringList to Array + }; + req.onerror = eventRejectHandler(reject); + } else { + globalDatabaseList(function (val) { + resolve(val); + return false; + }); + } + }).then(cb); + }; + + Dexie.defineClass = function (structure) { + /// + /// Create a javascript constructor based on given template for which properties to expect in the class. + /// Any property that is a constructor function will act as a type. So {name: String} will be equal to {name: new String()}. + /// + /// Helps IDE code completion by knowing the members that objects contain and not just the indexes. Also + /// know what type each member has. Example: {name: String, emailAddresses: [String], properties: {shoeSize: Number}} + + // Default constructor able to copy given properties into this object. + function Class(properties) { + /// Properties to initialize object with. + /// + properties ? extend(this, properties) : fake && applyStructure(this, structure); + } + return Class; + }; + + Dexie.applyStructure = applyStructure; + + Dexie.ignoreTransaction = function (scopeFunc) { + // In case caller is within a transaction but needs to create a separate transaction. + // Example of usage: + // + // Let's say we have a logger function in our app. Other application-logic should be unaware of the + // logger function and not need to include the 'logentries' table in all transaction it performs. + // The logging should always be done in a separate transaction and not be dependant on the current + // running transaction context. Then you could use Dexie.ignoreTransaction() to run code that starts a new transaction. + // + // Dexie.ignoreTransaction(function() { + // db.logentries.add(newLogEntry); + // }); + // + // Unless using Dexie.ignoreTransaction(), the above example would try to reuse the current transaction + // in current Promise-scope. + // + // An alternative to Dexie.ignoreTransaction() would be setImmediate() or setTimeout(). The reason we still provide an + // API for this because + // 1) The intention of writing the statement could be unclear if using setImmediate() or setTimeout(). + // 2) setTimeout() would wait unnescessary until firing. This is however not the case with setImmediate(). + // 3) setImmediate() is not supported in the ES standard. + return Promise.newPSD(function () { + Promise.PSD.trans = null; + return scopeFunc(); + }); + }; + + Dexie.vip = function (fn) { + // To be used by subscribers to the on('ready') event. + // This will let caller through to access DB even when it is blocked while the db.ready() subscribers are firing. + // This would have worked automatically if we were certain that the Provider was using Dexie.Promise for all asyncronic operations. The promise PSD + // from the provider.connect() call would then be derived all the way to when provider would call localDatabase.applyChanges(). But since + // the provider more likely is using non-promise async APIs or other thenable implementations, we cannot assume that. + // Note that this method is only useful for on('ready') subscribers that is returning a Promise from the event. If not using vip() + // the database could deadlock since it wont open until the returned Promise is resolved, and any non-VIPed operation started by + // the caller will not resolve until database is opened. + return Promise.newPSD(function () { + Promise.PSD.letThrough = true; // Make sure we are let through if still blocking db due to onready is firing. + return fn(); + }); + }; + + Dexie.async = function (generatorFn) { + return function () { + try { + var rv = awaitIterable(generatorFn.apply(this, arguments)); + if (!rv || typeof rv.then !== 'function') return Dexie.Promise.resolve(rv); + return rv; + } catch (e) { + return Dexie.Promise.reject(e); + } + }; + }; + + Dexie.spawn = function (generatorFn, args, thiz) { + try { + var rv = awaitIterable(generatorFn.apply(thiz, args || [])); + if (!rv || typeof rv.then !== 'function') return Dexie.Promise.resolve(rv); + return rv; + } catch (e) { + return Dexie.Promise.reject(e); + } + }; + + // Dexie.currentTransaction property. Only applicable for transactions entered using the new "transact()" method. + setProp(Dexie, "currentTransaction", { + get: function () { + /// + return Promise.PSD && Promise.PSD.trans || null; + } + }); + + function safariMultiStoreFix(storeNames) { + return storeNames.length === 1 ? storeNames[0] : storeNames; + } + + // Export our Promise implementation since it can be handy as a standalone Promise implementation + Dexie.Promise = Promise; + // Export our derive/extend/override methodology + Dexie.derive = derive; + Dexie.extend = extend; + Dexie.extendProto = extendProto; + Dexie.override = override; + // Export our Events() function - can be handy as a toolkit + Dexie.Events = Dexie.events = Events; // Backward compatible lowercase version. + // Utilities + Dexie.getByKeyPath = getByKeyPath; + Dexie.setByKeyPath = setByKeyPath; + Dexie.delByKeyPath = delByKeyPath; + Dexie.shallowClone = shallowClone; + Dexie.deepClone = deepClone; + Dexie.addons = []; + Dexie.fakeAutoComplete = fakeAutoComplete; + Dexie.asap = asap; + Dexie.maxKey = maxKey; + Dexie.connections = connections; + Dexie.dump = messageAndStack; + + // Export Error classes + extend(Dexie, fullNameExceptions); // Dexie.XXXError = class XXXError {...}; + Dexie.MultiModifyError = Dexie.ModifyError; // Backward compatibility 0.9.8 + Dexie.errnames = errnames; + + // Export other static classes + Dexie.IndexSpec = IndexSpec; + Dexie.TableSchema = TableSchema; + + // + // Dependencies + // + // These will automatically work in browsers with indexedDB support, or where an indexedDB polyfill has been included. + // + // In node.js, however, these properties must be set "manually" before instansiating a new Dexie(). For node.js, you need to require indexeddb-js or similar and then set these deps. + // + var idbshim = _global.idbModules && _global.idbModules.shimIndexedDB ? _global.idbModules : {}; + Dexie.dependencies = { + // Required: + indexedDB: idbshim.shimIndexedDB || _global.indexedDB || _global.mozIndexedDB || _global.webkitIndexedDB || _global.msIndexedDB, + IDBKeyRange: idbshim.IDBKeyRange || _global.IDBKeyRange || _global.webkitIDBKeyRange + }; + miniTryCatch(function () { + // Optional dependencies + // localStorage + Dexie.dependencies.localStorage = (typeof chrome !== "undefined" && chrome !== null ? chrome.storage : void 0) != null ? null : _global.localStorage; + }); + + // 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. + Dexie.semVer = "1.3.6-rc.1"; + Dexie.version = Dexie.semVer.split('.').map(function (n) { + return parseInt(n); + }).reduce(function (p, c, i) { + return p + c / Math.pow(10, i * 2); + }); + + function getNativeGetDatabaseNamesFn(indexedDB) { + var fn = indexedDB && (indexedDB.getDatabaseNames || indexedDB.webkitGetDatabaseNames); + return fn && fn.bind(indexedDB); + } + + // Fool IDE to improve autocomplete. Tested with Visual Studio 2013 and 2015. + doFakeAutoComplete(function () { + Dexie.fakeAutoComplete = fakeAutoComplete = doFakeAutoComplete; + Dexie.fake = fake = true; + }); + + // https://github.com/dfahlander/Dexie.js/issues/186 + // typescript compiler tsc in mode ts-->es5 & commonJS, will expect require() to return + // x.default. Workaround: Set Dexie.default = Dexie. + Dexie.default = Dexie; + + return Dexie; + +})); +//# sourceMappingURL=dexie.js.map \ No newline at end of file diff --git a/dist/dexie.js.map b/dist/dexie.js.map new file mode 100644 index 000000000..c5e8411b3 --- /dev/null +++ b/dist/dexie.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dexie.js","sources":["../C:/repos/dexie-release/tools/tmp/src/chaining-functions.js","../C:/repos/dexie-release/tools/tmp/src/utils.js","../C:/repos/dexie-release/tools/tmp/src/errors.js","../C:/repos/dexie-release/tools/tmp/src/Events.js","../C:/repos/dexie-release/tools/tmp/src/Promise.js","../C:/repos/dexie-release/tools/tmp/src/Dexie.js"],"sourcesContent":["import { extend } from './utils';\n\nexport function nop() {}\nexport function mirror(val) {\n return val;\n}\nexport function pureFunctionChain(f1, f2) {\n // Enables chained events that takes ONE argument and returns it to the next function in chain.\n // This pattern is used in the hook(\"reading\") event.\n if (f1 == null || f1 === mirror) return f2;\n return function (val) {\n return f2(f1(val));\n };\n}\n\nexport function callBoth(on1, on2) {\n return function () {\n on1.apply(this, arguments);\n on2.apply(this, arguments);\n };\n}\n\nexport function hookCreatingChain(f1, f2) {\n // Enables chained events that takes several arguments and may modify first argument by making a modification and then returning the same instance.\n // This pattern is used in the hook(\"creating\") event.\n if (f1 === nop) return f2;\n return function () {\n var res = f1.apply(this, arguments);\n if (res !== undefined) arguments[0] = res;\n var onsuccess = this.onsuccess,\n // In case event listener has set this.onsuccess\n onerror = this.onerror; // In case event listener has set this.onerror\n this.onsuccess = null;\n this.onerror = null;\n var res2 = f2.apply(this, arguments);\n if (onsuccess) this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;\n if (onerror) this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;\n return res2 !== undefined ? res2 : res;\n };\n}\n\nexport function hookDeletingChain(f1, f2) {\n if (f1 === nop) return f2;\n return function () {\n f1.apply(this, arguments);\n var onsuccess = this.onsuccess,\n // In case event listener has set this.onsuccess\n onerror = this.onerror; // In case event listener has set this.onerror\n this.onsuccess = this.onerror = null;\n f2.apply(this, arguments);\n if (onsuccess) this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;\n if (onerror) this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;\n };\n}\n\nexport function hookUpdatingChain(f1, f2) {\n if (f1 === nop) return f2;\n return function () {\n var res = f1.apply(this, arguments);\n extend(arguments[0], res); // If f1 returns new modifications, extend caller's modifications with the result before calling next in chain.\n var onsuccess = this.onsuccess,\n // In case event listener has set this.onsuccess\n onerror = this.onerror; // In case event listener has set this.onerror\n this.onsuccess = null;\n this.onerror = null;\n var res2 = f2.apply(this, arguments);\n if (onsuccess) this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;\n if (onerror) this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;\n return res === undefined ? res2 === undefined ? undefined : res2 : extend(res, res2);\n };\n}\n\nexport function stoppableEventChain(f1, f2) {\n // Enables chained events that may return false to stop the event chain.\n if (f1 === nop) return f2;\n return function () {\n if (f1.apply(this, arguments) === false) return false;\n return f2.apply(this, arguments);\n };\n}\n\nexport function reverseStoppableEventChain(f1, f2) {\n if (f1 === nop) return f2;\n return function () {\n if (f2.apply(this, arguments) === false) return false;\n return f1.apply(this, arguments);\n };\n}\n\nexport function nonStoppableEventChain(f1, f2) {\n if (f1 === nop) return f2;\n return function () {\n f1.apply(this, arguments);\n f2.apply(this, arguments);\n };\n}\n\nexport function promisableChain(f1, f2) {\n if (f1 === nop) return f2;\n return function () {\n var res = f1.apply(this, arguments);\n if (res && typeof res.then === 'function') {\n var thiz = this,\n args = arguments;\n return res.then(function () {\n return f2.apply(thiz, args);\n });\n }\n return f2.apply(this, arguments);\n };\n}","/*\r\n* Dexie.js - a minimalistic wrapper for IndexedDB\r\n* ===============================================\r\n*\r\n* By David Fahlander, david.fahlander@gmail.com\r\n*\r\n* Version {version}, {date}\r\n* www.dexie.com\r\n* Apache License Version 2.0, January 2004, http://www.apache.org/licenses/\r\n*/\nimport Promise from './Promise';\nimport { exceptions } from './errors';\n\nexport var keys = Object.keys;\nexport var isArray = Array.isArray;\nexport var _global = typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : global;\n\nexport function extend(obj, extension) {\n if (typeof extension !== 'object') return obj;\n keys(extension).forEach(function (key) {\n obj[key] = extension[key];\n });\n return obj;\n}\n\nexport function extendProto(proto, extension) {\n if (typeof extension === 'function') extension = extension(Object.getPrototypeOf(proto));\n keys(extension).forEach(function (key) {\n setProp(proto, key, extension[key]);\n });\n}\n\nexport function setProp(obj, prop, functionOrGetSet, options) {\n Object.defineProperty(obj, prop, extend(typeof functionOrGetSet.get === 'function' ? { get: functionOrGetSet.get, set: functionOrGetSet.set, configurable: true } : { value: functionOrGetSet, configurable: true, writable: true }, options));\n}\n\nexport function derive(Child) {\n return {\n from: function (Parent) {\n Child.prototype = Object.create(Parent.prototype);\n setProp(Child.prototype, \"constructor\", Child);\n return {\n extend: extendProto.bind(null, Child.prototype)\n };\n }\n };\n}\n\nvar _slice = [].slice;\nexport function slice(args, start, end) {\n return _slice.call(args, start, end);\n}\n\nexport function override(origFunc, overridedFactory) {\n return overridedFactory(origFunc);\n}\n\nexport function doFakeAutoComplete(fn) {\n var to = setTimeout(fn, 1000);\n clearTimeout(to);\n}\n\nexport function assert(b) {\n if (!b) throw new exceptions.Internal(\"Assertion failed\");\n}\n\nexport function asap(fn) {\n if (_global.setImmediate) setImmediate(fn);else setTimeout(fn, 0);\n}\n\nexport function miniTryCatch(fn, onerror) {\n try {\n fn();\n } catch (ex) {\n onerror && onerror(ex);\n }\n}\n\nexport function messageAndStack(e) {\n var stack = e && e.stack;\n return stack ? stack.indexOf(e + '') > 0 ? stack : e + \". \" + stack : e;\n}\n\nexport function stack(error) {\n if (error.stack) return error; // Provided error already has a stack\n try {\n var err = new Error(error.message || error); // In Chrome, stack is generated here.\n if (err.stack) {\n error.stack = err.stack;return error;\n } // If stack was generated, set it.\n // No stack. Other browsers only put the stack if we throw the error:\n throw err;\n } catch (e) {\n error.stack = e.stack;\n }\n return error;\n}\n\nexport function fail(err) {\n // Get the call stack and return a rejected promise.\n return Promise.reject(stack(err));\n}\n\nexport function getByKeyPath(obj, keyPath) {\n // http://www.w3.org/TR/IndexedDB/#steps-for-extracting-a-key-from-a-value-using-a-key-path\n if (obj.hasOwnProperty(keyPath)) return obj[keyPath]; // This line is moved from last to first for optimization purpose.\n if (!keyPath) return obj;\n if (typeof keyPath !== 'string') {\n var rv = [];\n for (var i = 0, l = keyPath.length; i < l; ++i) {\n var val = getByKeyPath(obj, keyPath[i]);\n rv.push(val);\n }\n return rv;\n }\n var period = keyPath.indexOf('.');\n if (period !== -1) {\n var innerObj = obj[keyPath.substr(0, period)];\n return innerObj === undefined ? undefined : getByKeyPath(innerObj, keyPath.substr(period + 1));\n }\n return undefined;\n}\n\nexport function setByKeyPath(obj, keyPath, value) {\n if (!obj || keyPath === undefined) return;\n if ('isFrozen' in Object && Object.isFrozen(obj)) return;\n if (typeof keyPath !== 'string' && 'length' in keyPath) {\n assert(typeof value !== 'string' && 'length' in value);\n for (var i = 0, l = keyPath.length; i < l; ++i) {\n setByKeyPath(obj, keyPath[i], value[i]);\n }\n } else {\n var period = keyPath.indexOf('.');\n if (period !== -1) {\n var currentKeyPath = keyPath.substr(0, period);\n var remainingKeyPath = keyPath.substr(period + 1);\n if (remainingKeyPath === \"\") {\n if (value === undefined) delete obj[currentKeyPath];else obj[currentKeyPath] = value;\n } else {\n var innerObj = obj[currentKeyPath];\n if (!innerObj) innerObj = obj[currentKeyPath] = {};\n setByKeyPath(innerObj, remainingKeyPath, value);\n }\n } else {\n if (value === undefined) delete obj[keyPath];else obj[keyPath] = value;\n }\n }\n}\n\nexport function delByKeyPath(obj, keyPath) {\n if (typeof keyPath === 'string') setByKeyPath(obj, keyPath, undefined);else if ('length' in keyPath) [].map.call(keyPath, function (kp) {\n setByKeyPath(obj, kp, undefined);\n });\n}\n\nexport function shallowClone(obj) {\n var rv = {};\n for (var m in obj) {\n if (obj.hasOwnProperty(m)) rv[m] = obj[m];\n }\n return rv;\n}\n\nexport function deepClone(any) {\n if (!any || typeof any !== 'object') return any;\n var rv;\n if (isArray(any)) {\n rv = [];\n for (var i = 0, l = any.length; i < l; ++i) {\n rv.push(deepClone(any[i]));\n }\n } else if (any instanceof Date) {\n rv = new Date();\n rv.setTime(any.getTime());\n } else {\n rv = any.constructor ? Object.create(any.constructor.prototype) : {};\n for (var prop in any) {\n if (any.hasOwnProperty(prop)) {\n rv[prop] = deepClone(any[prop]);\n }\n }\n }\n return rv;\n}\n\nexport function getObjectDiff(a, b, rv, prfx) {\n // Compares objects a and b and produces a diff object.\n rv = rv || {};\n prfx = prfx || '';\n for (var prop in a) {\n if (a.hasOwnProperty(prop)) {\n if (!b.hasOwnProperty(prop)) rv[prfx + prop] = undefined; // Property removed\n else {\n var ap = a[prop],\n bp = b[prop];\n if (typeof ap === 'object' && typeof bp === 'object') getObjectDiff(ap, bp, rv, prfx + prop + \".\");else if (ap !== bp) rv[prfx + prop] = b[prop]; // Primitive value changed\n }\n }\n }for (prop in b) {\n if (b.hasOwnProperty(prop) && !a.hasOwnProperty(prop)) {\n rv[prfx + prop] = b[prop]; // Property added\n }\n }return rv;\n}\n\nexport function idbp(idbOperation) {\n return new Promise(function (resolve, reject) {\n var req = idbOperation();\n req.onerror = reject;\n req.onsuccess = resolve;\n });\n}","import { derive, messageAndStack } from './utils';\n\nvar dexieErrorNames = ['Modify', 'Bulk', 'OpenFailed', 'VersionChange', 'Schema', 'Upgrade', 'InvalidTable', 'MissingAPI', 'NoSuchDatabase', 'InvalidArgument', 'SubTransaction', 'Unsupported', 'Internal', 'DatabaseClosed', 'IncompatiblePromise'];\n\nvar idbDomErrorNames = ['Unknown', 'Constraint', 'Data', 'TransactionInactive', 'ReadOnly', 'Version', 'NotFound', 'InvalidState', 'InvalidAccess', 'Abort', 'Timeout', 'QuotaExceeded', 'Syntax', 'DataClone'];\n\nvar errorList = dexieErrorNames.concat(idbDomErrorNames);\n\nvar defaultTexts = {\n VersionChanged: \"Database version changed by other database connection\",\n DatabaseClosed: \"Database has been closed\",\n IncompatiblePromise: \"Incompatible Promise used in transaction scope. See http://tinyurl.com/znyqjqc\"\n};\n\n//\n// DexieError - base class of all out exceptions.\n//\nexport function DexieError(name, msg) {\n // Reason we don't use ES6 classes is because:\n // 1. It bloats transpiled code and increases size of minified code.\n // 2. It doesn't give us much in this case.\n // 3. It would require sub classes to call super(), which\n // is not needed when deriving from Error.\n this.name = name;\n this.message = msg;\n}\nderive(DexieError).from(Error).extend({\n dump: function () {\n return messageAndStack(this);\n }\n});\n\nfunction getMultiErrorMessage(msg, failures) {\n return msg + \". Errors: \" + failures.map(function (f) {\n return f.toString();\n }).filter(function (v, i, s) {\n return s.indexOf(v) === i;\n }) // Only unique error strings\n .join('\\n');\n}\n//\n// ModifyError - thrown in WriteableCollection.modify()\n// Specific constructor because it contains members failures and failedKeys.\n//\nexport function ModifyError(msg, failures, successCount, failedKeys) {\n this.name = \"ModifyError\";\n this.failures = failures;\n this.failedKeys = failedKeys;\n this.successCount = successCount;\n this.message = getMultiErrorMessage(msg, failures);\n}\nderive(ModifyError).from(DexieError);\n\nexport function BulkError(msg, failures) {\n this.name = \"BulkError\";\n this.failures = failures;\n this.message = getMultiErrorMessage(msg, failures);\n}\nderive(BulkError).from(DexieError);\n\n//\n//\n// Dynamically generate error names and exception classes based\n// on the names in errorList.\n//\n//\n\n// Map of {ErrorName -> ErrorName + \"Error\"}\nexport var errnames = errorList.reduce(function (obj, name) {\n return obj[name] = name + \"Error\", obj;\n}, {});\n\n// Need an alias for DexieError because we're gonna create subclasses with the same name.\nvar BaseException = DexieError;\n// Map of {ErrorName -> exception constructor}\nexport var exceptions = errorList.reduce(function (obj, name) {\n // Let the name be \"DexieError\" because this name may\n // be shown in call stack and when debugging. DexieError is\n // the most true name because it derives from DexieError,\n // and we cannot change Function.name programatically without\n // dynamically create a Function object, which would be considered\n // 'eval-evil'.\n var fullName = name + \"Error\";\n function DexieError(msgOrInner, inner) {\n this.name = fullName;\n if (typeof msgOrInner === 'string') {\n this.message = msgOrInner;\n this.inner = inner || null;\n } else if (typeof msgOrInner === 'object') {\n this.message = msgOrInner.name + ' ' + msgOrInner.message;\n this.inner = msgOrInner;\n } else {\n this.message = defaultTexts[name];\n this.inner = null;\n }\n }\n derive(DexieError).from(BaseException);\n obj[name] = DexieError;\n return obj;\n}, {});\n\n// Use ECMASCRIPT standard exceptions where applicable:\nexceptions.Syntax = SyntaxError;\nexceptions.Type = TypeError;\nexceptions.Range = RangeError;\n\nexport var exceptionMap = idbDomErrorNames.reduce(function (obj, name) {\n obj[name + \"Error\"] = exceptions[name];\n return obj;\n}, {});\n\nexport function mapError(domError, message) {\n var rv = domError;\n if (!(domError instanceof DexieError) && domError.name && exceptionMap[domError.name]) {\n rv = new exceptionMap[domError.name](message || domError.message, domError);\n if (domError.stack) rv.stack = domError.stack;\n }\n return rv;\n}\n\nexport var fullNameExceptions = errorList.reduce(function (obj, name) {\n if ([\"Syntax\", \"Type\", \"Range\"].indexOf(name) === -1) obj[name + \"Error\"] = exceptions[name];\n return obj;\n}, {});\n\nfullNameExceptions.ModifyError = ModifyError;\nfullNameExceptions.DexieError = DexieError;\nfullNameExceptions.BulkError = BulkError;","import { slice, keys, isArray, asap, _global } from './utils';\nimport { nop, stoppableEventChain } from './chaining-functions';\nimport { exceptions } from './errors';\n\nexport default function Events(ctx) {\n var args = arguments;\n var evs = {};\n var rv = function (eventName, subscriber) {\n if (subscriber) {\n // Subscribe\n var args = slice(arguments, 1);\n var ev = evs[eventName];\n ev.subscribe.apply(ev, args);\n return ctx;\n } else if (typeof eventName === 'string') {\n // Return interface allowing to fire or unsubscribe from event\n return evs[eventName];\n }\n };\n rv.addEventType = add;\n\n function add(eventName, chainFunction, defaultFunction) {\n if (isArray(eventName)) return addEventGroup(eventName);\n if (typeof eventName === 'object') return addConfiguredEvents(eventName);\n if (!chainFunction) chainFunction = stoppableEventChain;\n if (!defaultFunction) defaultFunction = nop;\n\n var context = {\n subscribers: [],\n fire: defaultFunction,\n subscribe: function (cb) {\n context.subscribers.push(cb);\n context.fire = chainFunction(context.fire, cb);\n },\n unsubscribe: function (cb) {\n context.subscribers = context.subscribers.filter(function (fn) {\n return fn !== cb;\n });\n context.fire = context.subscribers.reduce(chainFunction, defaultFunction);\n }\n };\n evs[eventName] = rv[eventName] = context;\n return context;\n }\n\n function addConfiguredEvents(cfg) {\n // events(this, {reading: [functionChain, nop]});\n keys(cfg).forEach(function (eventName) {\n var args = cfg[eventName];\n if (isArray(args)) {\n add(eventName, cfg[eventName][0], cfg[eventName][1]);\n } else if (args === 'asap') {\n // 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\n // enabling that any exception that occur wont disturb the initiator and also not nescessary be catched and forgotten.\n var context = add(eventName, null, function fire() {\n var args = arguments;\n context.subscribers.forEach(function (fn) {\n asap(function fireEvent() {\n fn.apply(_global, args);\n });\n });\n });\n context.subscribe = function (fn) {\n // Change how subscribe works to not replace the fire function but to just add the subscriber to subscribers\n if (context.subscribers.indexOf(fn) === -1) context.subscribers.push(fn);\n };\n context.unsubscribe = function (fn) {\n // Change how unsubscribe works for the same reason as above.\n var idxOfFn = context.subscribers.indexOf(fn);\n if (idxOfFn !== -1) context.subscribers.splice(idxOfFn, 1);\n };\n } else throw new exceptions.InvalidArgument(\"Invalid event config\");\n });\n }\n\n function addEventGroup(eventGroup) {\n // promise-based event group (i.e. we promise to call one and only one of the events in the pair, and to only call it once.\n var done = false;\n eventGroup.forEach(function (name) {\n add(name).subscribe(checkDone);\n });\n function checkDone() {\n if (done) return false;\n done = true;\n }\n }\n\n for (var i = 1, l = args.length; i < l; ++i) {\n add(args[i]);\n }\n\n return rv;\n}","import { _global, slice, isArray, doFakeAutoComplete, messageAndStack } from './utils';\nimport { nop } from './chaining-functions';\nimport Events from './Events';\n\n//\n// Promise Class\n//\n// A variant of promise-light (https://github.com/taylorhakes/promise-light) by https://github.com/taylorhakes - an A+ and ECMASCRIPT 6 compliant Promise implementation.\n//\n// Modified by David Fahlander to be indexedDB compliant (See discussion: https://github.com/promises-aplus/promises-spec/issues/45) .\n// This implementation will not use setTimeout or setImmediate when it's not needed. The behavior is 100% Promise/A+ compliant since\n// the caller of new Promise() can be certain that the promise wont be triggered the lines after constructing the promise. We fix this by using the member variable constructing to check\n// whether the object is being constructed when reject or resolve is called. If so, the use setTimeout/setImmediate to fulfill the promise, otherwise, we know that it's not needed.\n//\n// This topic was also discussed in the following thread: https://github.com/promises-aplus/promises-spec/issues/45 and this implementation solves that issue.\n//\n// Another feature with this Promise implementation is that reject will return false in case no one catched the reject call. This is used\n// to stopPropagation() on the IDBRequest error event in case it was catched but not otherwise.\n//\n// Also, the event new Promise().onuncatched is called in case no one catches a reject call. This is used for us to manually bubble any request\n// errors to the transaction. We must not rely on IndexedDB implementation to do this, because it only does so when the source of the rejection\n// is an error event on a request, not in case an ordinary exception is thrown.\n\nvar _asap = _global.setImmediate || function (fn) {\n var args = slice(arguments, 1);\n\n // If not FF13 and earlier failed, we could use this call here instead: setTimeout.call(this, [fn, 0].concat(arguments));\n setTimeout(function () {\n fn.apply(_global, args);\n }, 0);\n};\n\ndoFakeAutoComplete(function () {\n // Simplify the job for VS Intellisense. This piece of code is one of the keys to the new marvellous intellisense support in Dexie.\n _asap = asap = enqueueImmediate = function (fn) {\n var args = arguments;setTimeout(function () {\n fn.apply(_global, slice(args, 1));\n }, 0);\n };\n});\n\nvar asap = _asap,\n isRootExecution = true;\n\nvar operationsQueue = [];\nvar tickFinalizers = [];\nvar enqueueImmediate = function (fn) {\n operationsQueue.push([fn, slice(arguments, 1)]);\n};\n\nfunction executeOperationsQueue() {\n var queue = operationsQueue;\n operationsQueue = [];\n for (var i = 0, l = queue.length; i < l; ++i) {\n var item = queue[i];\n item[0].apply(_global, item[1]);\n }\n}\n\nexport default function Promise(fn) {\n if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');\n if (typeof fn !== 'function') throw new TypeError('not a function');\n this._state = null; // null (=pending), false (=rejected) or true (=resolved)\n this._value = null; // error or result\n this._deferreds = [];\n this._catched = false; // for onuncatched\n //this._id = ++PromiseID;\n var self = this;\n var constructing = true;\n this._PSD = Promise.PSD;\n\n try {\n doResolve(this, fn, function (data) {\n if (constructing) asap(resolve, self, data);else resolve(self, data);\n }, function (reason) {\n if (constructing) {\n asap(reject, self, reason);\n return false;\n } else {\n return reject(self, reason);\n }\n });\n } finally {\n constructing = false;\n }\n}\n\nfunction handle(self, deferred) {\n if (self._state === null) {\n self._deferreds.push(deferred);\n return;\n }\n\n var cb = self._state ? deferred.onFulfilled : deferred.onRejected;\n if (cb === null) {\n // This Deferred 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()\n return (self._state ? deferred.resolve : deferred.reject)(self._value);\n }\n var ret,\n isRootExec = isRootExecution;\n isRootExecution = false;\n asap = enqueueImmediate;\n try {\n var outerPSD = Promise.PSD;\n Promise.PSD = self._PSD;\n ret = cb(self._value);\n if (!self._state && (!ret || typeof ret.then !== 'function' || ret._state !== false)) setCatched(self); // Caller did 'return Promise.reject(err);' - don't regard it as catched!\n deferred.resolve(ret);\n } catch (e) {\n deferred.reject(e);\n } finally {\n Promise.PSD = outerPSD;\n if (isRootExec) {\n do {\n while (operationsQueue.length > 0) {\n executeOperationsQueue();\n }var finalizer = tickFinalizers.pop();\n if (finalizer) try {\n finalizer();\n } catch (e) {}\n } while (tickFinalizers.length > 0 || operationsQueue.length > 0);\n asap = _asap;\n isRootExecution = true;\n }\n }\n}\n\nfunction _rootExec(fn) {\n var isRootExec = isRootExecution;\n isRootExecution = false;\n asap = enqueueImmediate;\n try {\n return fn();\n } finally {\n if (isRootExec) {\n do {\n while (operationsQueue.length > 0) {\n executeOperationsQueue();\n }var finalizer = tickFinalizers.pop();\n if (finalizer) try {\n finalizer();\n } catch (e) {}\n } while (tickFinalizers.length > 0 || operationsQueue.length > 0);\n asap = _asap;\n isRootExecution = true;\n }\n }\n}\n\nfunction setCatched(promise) {\n promise._catched = true;\n if (promise._parent && !promise._parent._catched) setCatched(promise._parent);\n}\n\nfunction resolve(promise, newValue) {\n var outerPSD = Promise.PSD;\n Promise.PSD = promise._PSD;\n try {\n //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure\n if (newValue === promise) throw new TypeError('A promise cannot be resolved with itself.');\n if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {\n if (typeof newValue.then === 'function') {\n if (newValue instanceof Promise && newValue._state !== null) {\n promise._state = newValue._state;\n promise._value = newValue._value;\n finale.call(promise);\n return;\n }\n doResolve(promise, function (resolve, reject) {\n //newValue instanceof Promise ? newValue._then(resolve, reject) : newValue.then(resolve, reject);\n newValue.then(resolve, reject);\n }, function (data) {\n resolve(promise, data);\n }, function (reason) {\n reject(promise, reason);\n });\n return;\n }\n }\n promise._state = true;\n promise._value = newValue;\n finale.call(promise);\n } catch (e) {\n reject(e);\n } finally {\n Promise.PSD = outerPSD;\n }\n}\n\nfunction reject(promise, newValue) {\n var outerPSD = Promise.PSD;\n Promise.PSD = promise._PSD;\n promise._state = false;\n promise._value = newValue;\n\n finale.call(promise);\n if (!promise._catched) {\n try {\n if (promise.onuncatched) promise.onuncatched(promise._value);else Promise.on.error.fire(promise._value);\n } catch (e) {}\n }\n Promise.PSD = outerPSD;\n return promise._catched;\n}\n\nfunction finale() {\n for (var i = 0, len = this._deferreds.length; i < len; i++) {\n handle(this, this._deferreds[i]);\n }\n this._deferreds = [];\n}\n\nfunction Deferred(onFulfilled, onRejected, resolve, reject) {\n this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;\n this.onRejected = typeof onRejected === 'function' ? onRejected : null;\n this.resolve = resolve;\n this.reject = reject;\n}\n\n/**\r\n * Take a potentially misbehaving resolver function and make sure\r\n * onFulfilled and onRejected are only called once.\r\n *\r\n * Makes no guarantees about asynchrony.\r\n */\nfunction doResolve(promise, fn, onFulfilled, onRejected) {\n var done = false;\n try {\n fn(function Promise_resolve(value) {\n if (done) return;\n done = true;\n onFulfilled(value);\n }, function Promise_reject(reason) {\n if (done) return promise._catched;\n done = true;\n return onRejected(reason);\n });\n } catch (ex) {\n if (done) return;\n return onRejected(ex);\n }\n}\n\nPromise.all = function () {\n var args = slice(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments);\n\n return new Promise(function (resolve, reject) {\n if (args.length === 0) return resolve([]);\n var remaining = args.length;\n function res(i, val) {\n try {\n if (val && (typeof val === 'object' || typeof val === 'function')) {\n var then = val.then;\n if (typeof then === 'function') {\n then.call(val, function (val) {\n res(i, val);\n }, reject);\n return;\n }\n }\n args[i] = val;\n if (--remaining === 0) {\n resolve(args);\n }\n } catch (ex) {\n reject(ex);\n }\n }\n for (var i = 0; i < args.length; i++) {\n res(i, args[i]);\n }\n });\n};\n\n/* Prototype Methods */\nPromise.prototype.then = function (onFulfilled, onRejected) {\n var self = this;\n var p = new Promise(function (resolve, reject) {\n if (self._state === null) handle(self, new Deferred(onFulfilled, onRejected, resolve, reject));else asap(handle, self, new Deferred(onFulfilled, onRejected, resolve, reject));\n });\n p._PSD = this._PSD;\n p.onuncatched = this.onuncatched; // Needed when exception occurs in a then() clause of a successful parent promise. Want onuncatched to be called even in callbacks of callbacks of the original promise.\n p._parent = this; // Used for recursively calling onuncatched event on self and all parents.\n return p;\n};\n\nPromise.prototype._then = function (onFulfilled, onRejected) {\n handle(this, new Deferred(onFulfilled, onRejected, nop, nop));\n};\n\nPromise.prototype['catch'] = function (onRejected) {\n if (arguments.length === 1) return this.then(null, onRejected);\n // First argument is the Error type to catch\n var type = arguments[0],\n callback = arguments[1];\n if (typeof type === 'function') return this.then(null, function (e) {\n // Catching errors by its constructor type (similar to java / c++ / c#)\n // Sample: promise.catch(TypeError, function (e) { ... });\n if (e instanceof type) return callback(e);else return Promise.reject(e);\n });else return this.then(null, function (e) {\n // Catching errors by the error.name property. Makes sense for indexedDB where error type\n // is always DOMError but where e.name tells the actual error type.\n // Sample: promise.catch('ConstraintError', function (e) { ... });\n if (e && e.name === type) return callback(e);else return Promise.reject(e);\n });\n};\n\nPromise.prototype['finally'] = function (onFinally) {\n return this.then(function (value) {\n onFinally();\n return value;\n }, function (err) {\n onFinally();\n return Promise.reject(err);\n });\n};\n\nPromise.prototype.onuncatched = null; // Optional event triggered if promise is rejected but no one listened.\n\nPromise.resolve = function (value) {\n if (value && typeof value.then === 'function') return value;\n var p = new Promise(function () {});\n p._state = true;\n p._value = value;\n return p;\n};\n\nPromise.reject = function (value) {\n var p = new Promise(function () {});\n p._state = false;\n p._value = value;\n return p;\n};\n\nPromise.race = function (values) {\n return new Promise(function (resolve, reject) {\n values.map(function (value) {\n value.then(resolve, reject);\n });\n });\n};\n\nPromise.PSD = null; // Promise Specific Data - a TLS Pattern (Thread Local Storage) for Promises. TODO: Rename Promise.PSD to Promise.data\n\nPromise.newPSD = function (fn) {\n // Create new PSD scope (Promise Specific Data)\n var outerScope = Promise.PSD;\n Promise.PSD = outerScope ? Object.create(outerScope) : {};\n try {\n return fn();\n } finally {\n Promise.PSD = outerScope;\n }\n};\n\nPromise.usePSD = function (psd, fn) {\n var outerScope = Promise.PSD;\n Promise.PSD = psd;\n try {\n return fn();\n } finally {\n Promise.PSD = outerScope;\n }\n};\n\nPromise._rootExec = _rootExec;\nPromise._tickFinalize = function (callback) {\n if (isRootExecution) throw new Error(\"Not in a virtual tick\");\n tickFinalizers.push(callback);\n};\n\nPromise.on = Events(null, { \"error\": [function (f1, f2) {\n return f2;\n }, // Only use the most recent handler (only allow one handler at a time).\n defaultErrorHandler] // Default to defaultErrorHandler\n});\n\n// By default, log uncaught errors to the console\nfunction defaultErrorHandler(e) {\n console.warn('Uncaught Promise: ' + messageAndStack(e));\n}","/*\r\n * Dexie.js - a minimalistic wrapper for IndexedDB\r\n * ===============================================\r\n *\r\n * By David Fahlander, david.fahlander@gmail.com\r\n *\r\n * Version {version}, {date}\r\n *\r\n * www.dexie.com\r\n *\r\n * Apache License Version 2.0, January 2004, http://www.apache.org/licenses/\r\n */\n\nimport { keys, setProp, isArray, extend, extendProto, derive, slice, override, _global, doFakeAutoComplete, asap, miniTryCatch, stack, fail, getByKeyPath, setByKeyPath, delByKeyPath, shallowClone, deepClone, getObjectDiff, messageAndStack } from './utils';\nimport { ModifyError, BulkError, errnames, exceptions, fullNameExceptions, mapError } from './errors';\nimport Promise from './Promise';\nimport Events from './Events';\nimport { nop, mirror, pureFunctionChain, hookCreatingChain, hookUpdatingChain, hookDeletingChain, promisableChain, reverseStoppableEventChain } from './chaining-functions';\n\nvar maxString = String.fromCharCode(65535),\n\n// maxKey is an Array if indexedDB implementations supports array keys (not supported by IE,Edge or Safari at the moment)\n// Otherwise maxKey is maxString. This is handy when needing an open upper border without limit.\nmaxKey = function () {\n try {\n IDBKeyRange.only([[]]);return [[]];\n } catch (e) {\n return maxString;\n }\n}(),\n INVALID_KEY_ARGUMENT = \"Invalid key provided. Keys must be of type string, number, Date or Array.\",\n STRING_EXPECTED = \"String expected.\",\n connections = [],\n isIEOrEdge = typeof navigator !== 'undefined' && /(MSIE|Trident|Edge)/.test(navigator.userAgent),\n hasIEDeleteObjectStoreBug = isIEOrEdge,\n hangsOnDeleteLargeKeyRange = isIEOrEdge;\n\nexport default function Dexie(dbName, options) {\n /// Specify only if you wich to control which addons that should run on this instance\n var deps = Dexie.dependencies;\n var opts = extend({\n // Default Options\n addons: Dexie.addons, // Pick statically registered addons by default\n autoOpen: true, // Don't require db.open() explicitely.\n indexedDB: deps.indexedDB, // Backend IndexedDB api. Default to IDBShim or browser env.\n IDBKeyRange: deps.IDBKeyRange // Backend IDBKeyRange api. Default to IDBShim or browser env.\n }, options);\n var addons = opts.addons,\n autoOpen = opts.autoOpen,\n indexedDB = opts.indexedDB,\n IDBKeyRange = opts.IDBKeyRange;\n\n var globalSchema = this._dbSchema = {};\n var versions = [];\n var dbStoreNames = [];\n var allTables = {};\n var notInTransFallbackTables = {};\n ///\n var idbdb = null; // Instance of IDBDatabase\n var db_is_blocked = true;\n var dbOpenError = null;\n var isBeingOpened = false;\n var READONLY = \"readonly\",\n READWRITE = \"readwrite\";\n var db = this;\n var pausedResumeables = [];\n var autoSchema = true;\n var hasNativeGetDatabaseNames = !!getNativeGetDatabaseNamesFn(indexedDB);\n\n function init() {\n // Default subscribers to \"versionchange\" and \"blocked\".\n // Can be overridden by custom handlers. If custom handlers return false, these default\n // behaviours will be prevented.\n db.on(\"versionchange\", function (ev) {\n // Default behavior for versionchange event is to close database connection.\n // Caller can override this behavior by doing db.on(\"versionchange\", function(){ return false; });\n // Let's not block the other window from making it's delete() or open() call.\n // NOTE! This event is never fired in IE,Edge or Safari.\n 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.');\n db.close();\n // In many web applications, it would be recommended to force window.reload()\n // when this event occurs. To do that, subscribe to the versionchange event\n // and call window.location.reload(true) if ev.newVersion > 0 (not a deletion)\n // The reason for this is that your current web app obviously has old schema code that needs\n // to be updated. Another window got a newer version of the app and needs to upgrade DB but\n // your window is blocking it unless we close it here.\n });\n db.on(\"blocked\", function (ev) {\n 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);\n });\n }\n\n //\n //\n //\n // ------------------------- Versioning Framework---------------------------\n //\n //\n //\n\n this.version = function (versionNumber) {\n /// \n /// \n if (idbdb || isBeingOpened) throw new exceptions.Schema(\"Cannot add version when database is open\");\n this.verno = Math.max(this.verno, versionNumber);\n var versionInstance = versions.filter(function (v) {\n return v._cfg.version === versionNumber;\n })[0];\n if (versionInstance) return versionInstance;\n versionInstance = new Version(versionNumber);\n versions.push(versionInstance);\n versions.sort(lowerVersionFirst);\n return versionInstance;\n };\n\n function Version(versionNumber) {\n this._cfg = {\n version: versionNumber,\n storesSource: null,\n dbschema: {},\n tables: {},\n contentUpgrade: null\n };\n this.stores({}); // Derive earlier schemas by default.\n }\n\n extend(Version.prototype, {\n stores: function (stores) {\n /// \n /// Defines the schema for a particular version\n /// \n /// \n /// Example:
\n /// {users: \"id++,first,last,&username,*email\",
\n /// passwords: \"id++,&username\"}
\n ///
\n /// Syntax: {Table: \"[primaryKey][++],[&][*]index1,[&][*]index2,...\"}

\n /// Special characters:
\n /// \"&\" means unique key,
\n /// \"*\" means value is multiEntry,
\n /// \"++\" means auto-increment and only applicable for primary key
\n /// \n this._cfg.storesSource = this._cfg.storesSource ? extend(this._cfg.storesSource, stores) : stores;\n\n // Derive stores from earlier versions if they are not explicitely specified as null or a new syntax.\n var storesSpec = {};\n versions.forEach(function (version) {\n // 'versions' is always sorted by lowest version first.\n extend(storesSpec, version._cfg.storesSource);\n });\n\n var dbschema = this._cfg.dbschema = {};\n this._parseStoresSpec(storesSpec, dbschema);\n // Update the latest schema to this version\n // Update API\n globalSchema = db._dbSchema = dbschema;\n removeTablesApi([allTables, db, notInTransFallbackTables]);\n setApiOnPlace([notInTransFallbackTables], tableNotInTransaction, keys(dbschema), READWRITE, dbschema);\n setApiOnPlace([allTables, db, this._cfg.tables], db._transPromiseFactory, keys(dbschema), READWRITE, dbschema, true);\n dbStoreNames = keys(dbschema);\n return this;\n },\n upgrade: function (upgradeFunction) {\n /// Function that performs upgrading actions.\n var self = this;\n fakeAutoComplete(function () {\n upgradeFunction(db._createTransaction(READWRITE, keys(self._cfg.dbschema), self._cfg.dbschema)); // BUGBUG: No code completion for prev version's tables wont appear.\n });\n this._cfg.contentUpgrade = upgradeFunction;\n return this;\n },\n _parseStoresSpec: function (stores, outSchema) {\n keys(stores).forEach(function (tableName) {\n if (stores[tableName] !== null) {\n var instanceTemplate = {};\n var indexes = parseIndexSyntax(stores[tableName]);\n var primKey = indexes.shift();\n if (primKey.multi) throw new exceptions.Schema(\"Primary key cannot be multi-valued\");\n if (primKey.keyPath) setByKeyPath(instanceTemplate, primKey.keyPath, primKey.auto ? 0 : primKey.keyPath);\n indexes.forEach(function (idx) {\n if (idx.auto) throw new exceptions.Schema(\"Only primary key can be marked as autoIncrement (++)\");\n if (!idx.keyPath) throw new exceptions.Schema(\"Index must have a name and cannot be an empty string\");\n setByKeyPath(instanceTemplate, idx.keyPath, idx.compound ? idx.keyPath.map(function () {\n return \"\";\n }) : \"\");\n });\n outSchema[tableName] = new TableSchema(tableName, primKey, indexes, instanceTemplate);\n }\n });\n }\n });\n\n function runUpgraders(oldVersion, idbtrans, reject, openReq) {\n if (oldVersion === 0) {\n //globalSchema = versions[versions.length - 1]._cfg.dbschema;\n // Create tables:\n keys(globalSchema).forEach(function (tableName) {\n createTable(idbtrans, tableName, globalSchema[tableName].primKey, globalSchema[tableName].indexes);\n });\n // Populate data\n var t = db._createTransaction(READWRITE, dbStoreNames, globalSchema);\n t.idbtrans = idbtrans;\n t.idbtrans.onerror = eventRejectHandler(reject, [\"populating database\"]);\n t.on('error').subscribe(reject);\n Promise.newPSD(function () {\n Promise.PSD.trans = t;\n try {\n db.on(\"populate\").fire(t);\n } catch (err) {\n openReq.onerror = idbtrans.onerror = function (ev) {\n ev.preventDefault();\n }; // Prohibit AbortError fire on db.on(\"error\") in Firefox.\n try {\n idbtrans.abort();\n } catch (e) {}\n idbtrans.db.close();\n reject(err);\n }\n });\n } else {\n // Upgrade version to version, step-by-step from oldest to newest version.\n // Each transaction object will contain the table set that was current in that version (but also not-yet-deleted tables from its previous version)\n var queue = [];\n var oldVersionStruct = versions.filter(function (version) {\n return version._cfg.version === oldVersion;\n })[0];\n if (!oldVersionStruct) throw new exceptions.Upgrade(\"Dexie specification of currently installed DB version is missing\");\n globalSchema = db._dbSchema = oldVersionStruct._cfg.dbschema;\n var anyContentUpgraderHasRun = false;\n\n var versToRun = versions.filter(function (v) {\n return v._cfg.version > oldVersion;\n });\n versToRun.forEach(function (version) {\n /// \n var oldSchema = globalSchema;\n var newSchema = version._cfg.dbschema;\n adjustToExistingIndexNames(oldSchema, idbtrans);\n adjustToExistingIndexNames(newSchema, idbtrans);\n globalSchema = db._dbSchema = newSchema;\n {\n var diff = getSchemaDiff(oldSchema, newSchema);\n diff.add.forEach(function (tuple) {\n queue.push(function (idbtrans, cb) {\n createTable(idbtrans, tuple[0], tuple[1].primKey, tuple[1].indexes);\n cb();\n });\n });\n diff.change.forEach(function (change) {\n if (change.recreate) {\n throw new exceptions.Upgrade(\"Not yet support for changing primary key\");\n } else {\n queue.push(function (idbtrans, cb) {\n var store = idbtrans.objectStore(change.name);\n change.add.forEach(function (idx) {\n addIndex(store, idx);\n });\n change.change.forEach(function (idx) {\n store.deleteIndex(idx.name);\n addIndex(store, idx);\n });\n change.del.forEach(function (idxName) {\n store.deleteIndex(idxName);\n });\n cb();\n });\n }\n });\n if (version._cfg.contentUpgrade) {\n queue.push(function (idbtrans, cb) {\n anyContentUpgraderHasRun = true;\n var t = db._createTransaction(READWRITE, slice(idbtrans.db.objectStoreNames), newSchema);\n t.idbtrans = idbtrans;\n var uncompletedRequests = 0;\n t._promise = override(t._promise, function (orig_promise) {\n return function (mode, fn, writeLock) {\n ++uncompletedRequests;\n function proxy(fn) {\n return function () {\n fn.apply(this, arguments);\n if (--uncompletedRequests === 0) cb(); // A called db operation has completed without starting a new operation. The flow is finished, now run next upgrader.\n };\n }\n return orig_promise.call(this, mode, function (resolve, reject) {\n arguments[0] = proxy(resolve);\n arguments[1] = proxy(reject);\n fn.apply(this, arguments);\n }, writeLock);\n };\n });\n idbtrans.onerror = eventRejectHandler(reject, [\"running upgrader function for version\", version._cfg.version]);\n t.on('error').subscribe(reject);\n version._cfg.contentUpgrade(t);\n if (uncompletedRequests === 0) cb(); // contentUpgrade() didnt call any db operations at all.\n });\n }\n if (!anyContentUpgraderHasRun || hasIEDeleteObjectStoreBug) {\n // Dont delete old tables if ieBug is present and a content upgrader has run. Let tables be left in DB so far. This needs to be taken care of.\n queue.push(function (idbtrans, cb) {\n // Delete old tables\n deleteRemovedTables(newSchema, idbtrans);\n cb();\n });\n }\n }\n });\n\n // Now, create a queue execution engine\n var runNextQueuedFunction = function () {\n try {\n if (queue.length) queue.shift()(idbtrans, runNextQueuedFunction);else createMissingTables(globalSchema, idbtrans); // At last, make sure to create any missing tables. (Needed by addons that add stores to DB without specifying version)\n } catch (err) {\n openReq.onerror = idbtrans.onerror = function (ev) {\n ev.preventDefault();\n }; // Prohibit AbortError fire on db.on(\"error\") in Firefox.\n try {\n idbtrans.abort();\n } catch (e) {}\n idbtrans.db.close();\n reject(err);\n }\n };\n runNextQueuedFunction();\n }\n }\n\n function getSchemaDiff(oldSchema, newSchema) {\n var diff = {\n del: [], // Array of table names\n add: [], // Array of [tableName, newDefinition]\n change: [] // Array of {name: tableName, recreate: newDefinition, del: delIndexNames, add: newIndexDefs, change: changedIndexDefs}\n };\n for (var table in oldSchema) {\n if (!newSchema[table]) diff.del.push(table);\n }\n for (table in newSchema) {\n var oldDef = oldSchema[table],\n newDef = newSchema[table];\n if (!oldDef) diff.add.push([table, newDef]);else {\n var change = {\n name: table,\n def: newSchema[table],\n recreate: false,\n del: [],\n add: [],\n change: []\n };\n if (oldDef.primKey.src !== newDef.primKey.src) {\n // Primary key has changed. Remove and re-add table.\n change.recreate = true;\n diff.change.push(change);\n } else {\n var oldIndexes = oldDef.indexes.reduce(function (prev, current) {\n prev[current.name] = current;return prev;\n }, {});\n var newIndexes = newDef.indexes.reduce(function (prev, current) {\n prev[current.name] = current;return prev;\n }, {});\n for (var idxName in oldIndexes) {\n if (!newIndexes[idxName]) change.del.push(idxName);\n }\n for (idxName in newIndexes) {\n var oldIdx = oldIndexes[idxName],\n newIdx = newIndexes[idxName];\n if (!oldIdx) change.add.push(newIdx);else if (oldIdx.src !== newIdx.src) change.change.push(newIdx);\n }\n if (change.recreate || change.del.length > 0 || change.add.length > 0 || change.change.length > 0) {\n diff.change.push(change);\n }\n }\n }\n }\n return diff;\n }\n\n function createTable(idbtrans, tableName, primKey, indexes) {\n /// \n var store = idbtrans.db.createObjectStore(tableName, primKey.keyPath ? { keyPath: primKey.keyPath, autoIncrement: primKey.auto } : { autoIncrement: primKey.auto });\n indexes.forEach(function (idx) {\n addIndex(store, idx);\n });\n return store;\n }\n\n function createMissingTables(newSchema, idbtrans) {\n keys(newSchema).forEach(function (tableName) {\n if (!idbtrans.db.objectStoreNames.contains(tableName)) {\n createTable(idbtrans, tableName, newSchema[tableName].primKey, newSchema[tableName].indexes);\n }\n });\n }\n\n function deleteRemovedTables(newSchema, idbtrans) {\n for (var i = 0; i < idbtrans.db.objectStoreNames.length; ++i) {\n var storeName = idbtrans.db.objectStoreNames[i];\n if (newSchema[storeName] === null || newSchema[storeName] === undefined) {\n idbtrans.db.deleteObjectStore(storeName);\n }\n }\n }\n\n function addIndex(store, idx) {\n store.createIndex(idx.name, idx.keyPath, { unique: idx.unique, multiEntry: idx.multi });\n }\n\n function executePausedResumeables() {\n pausedResumeables.forEach(function (resumable) {\n // Resume all stalled operations. They will fail once they wake up.\n resumable.resume();\n });\n }\n\n //\n //\n // Dexie Protected API\n //\n //\n\n this._allTables = allTables;\n\n this._tableFactory = function createTable(mode, tableSchema, transactionPromiseFactory) {\n /// \n if (mode === READONLY) return new Table(tableSchema.name, transactionPromiseFactory, tableSchema, Collection);else return new WriteableTable(tableSchema.name, transactionPromiseFactory, tableSchema);\n };\n\n this._createTransaction = function (mode, storeNames, dbschema, parentTransaction) {\n return new Transaction(mode, storeNames, dbschema, parentTransaction);\n };\n\n function tableNotInTransaction(mode, storeNames) {\n throw new exceptions.InvalidTable(\"Table \" + storeNames[0] + \" not part of transaction. Original Scope Function Source: \" + Dexie.Promise.PSD.trans.scopeFunc.toString());\n }\n\n this._transPromiseFactory = function transactionPromiseFactory(mode, storeNames, fn) {\n // Last argument is \"writeLocked\". But this doesnt apply to oneshot direct db operations, so we ignore it.\n if (db_is_blocked && (!Promise.PSD || !Promise.PSD.letThrough)) {\n // Database is paused. Wait til resumed.\n if (!isBeingOpened && !autoOpen) {\n return fail(new exceptions.DatabaseClosed());\n }\n var blockedPromise = new Promise(function (resolve, reject) {\n pausedResumeables.push({\n resume: function () {\n var p = db._transPromiseFactory(mode, storeNames, fn);\n blockedPromise.onuncatched = p.onuncatched;\n p.then(resolve, reject);\n }\n });\n });\n if (autoOpen && !isBeingOpened) {\n db.open().catch(nop); // catching to get rid of error logging of uncaught Promise. dbOpenError will be returned again as a rejected Promise.\n }\n return blockedPromise;\n } else {\n var trans = db._createTransaction(mode, storeNames, globalSchema);\n return trans._promise(mode, function (resolve, reject) {\n // An uncatched operation will bubble to this anonymous transaction. Make sure\n // to continue bubbling it up to db.on('error'):\n trans.error(function (err) {\n db.on('error').fire(err);\n });\n Promise.newPSD(function () {\n Promise.PSD.trans = trans;\n fn(function (value) {\n // Instead of resolving value directly, wait with resolving it until transaction has completed.\n // Otherwise the data would not be in the DB if requesting it in the then() operation.\n // Specifically, to ensure that the following expression will work:\n //\n // db.friends.put({name: \"Arne\"}).then(function () {\n // db.friends.where(\"name\").equals(\"Arne\").count(function(count) {\n // assert (count === 1);\n // });\n // });\n //\n trans.complete(function () {\n resolve(value);\n });\n }, reject, trans);\n });\n });\n }\n };\n\n this._whenReady = function (fn) {\n if (!fake && db_is_blocked && (!Promise.PSD || !Promise.PSD.letThrough)) {\n if (!isBeingOpened) {\n if (autoOpen) {\n db.open().catch(nop); // catching to get rid of error logging of uncaught Promise. dbOpenError will be returned again as a rejected Promise.\n } else {\n return fail(new exceptions.DatabaseClosed());\n }\n }\n return new Promise(function (resolve, reject) {\n pausedResumeables.push({\n resume: function () {\n fn(resolve, reject);\n }\n });\n });\n }\n return new Promise(fn);\n };\n\n //\n //\n //\n //\n // Dexie API\n //\n //\n //\n\n this.verno = 0;\n\n this.open = function () {\n if (idbdb) return Promise.resolve(db);\n if (isBeingOpened) return new Promise(function (resolve, reject) {\n return db._whenReady(function () {\n resolve(db);\n }, function (e) {\n reject(e);\n });\n });\n dbOpenError = null;\n isBeingOpened = true;\n db_is_blocked = true;\n return new Promise(function (resolve, reject) {\n if (fake) resolve();\n var req;\n function openError(err) {\n try {\n req.transaction.abort();\n } catch (e) {}\n if (idbdb) try {\n idbdb.close();\n } catch (e) {}\n idbdb = null;\n isBeingOpened = false;\n dbOpenError = mapError(err);\n db_is_blocked = false;\n reject(dbOpenError);\n executePausedResumeables();\n }\n try {\n // Make sure caller has specified at least one version\n if (versions.length > 0) autoSchema = false;\n\n // Multiply db.verno with 10 will be needed to workaround upgrading bug in IE:\n // IE fails when deleting objectStore after reading from it.\n // A future version of Dexie.js will stopover an intermediate version to workaround this.\n // 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.\n if (!indexedDB) throw new exceptions.MissingAPI(\"indexedDB API not found. If using IE10+, make sure to run your code on a server URL \" + \"(not locally). If using Safari, make sure to include indexedDB polyfill.\");\n req = autoSchema ? indexedDB.open(dbName) : indexedDB.open(dbName, Math.round(db.verno * 10));\n 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\n req.onerror = eventRejectHandler(openError, [\"opening database\", dbName]);\n req.onblocked = fireOnBlocked;\n req.onupgradeneeded = trycatch(function (e) {\n if (autoSchema && !db._allowEmptyDB) {\n // Unless an addon has specified db._allowEmptyDB, lets make the call fail.\n // Caller did not specify a version or schema. Doing that is only acceptable for opening alread existing databases.\n // If onupgradeneeded is called it means database did not exist. Reject the open() promise and make sure that we\n // do not create a new database by accident here.\n req.onerror = function (event) {\n event.preventDefault();\n }; // Prohibit onabort error from firing before we're done!\n req.transaction.abort(); // Abort transaction (would hope that this would make DB disappear but it doesnt.)\n // Close database and delete it.\n req.result.close();\n 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!\n delreq.onsuccess = delreq.onerror = function () {\n openError(new exceptions.NoSuchDatabase('Database ' + dbName + ' doesnt exist'));\n };\n } else {\n req.transaction.onerror = eventRejectHandler(openError);\n var oldVer = e.oldVersion > Math.pow(2, 62) ? 0 : e.oldVersion; // Safari 8 fix.\n runUpgraders(oldVer / 10, req.transaction, openError, req);\n }\n }, openError);\n req.onsuccess = trycatch(function () {\n isBeingOpened = false;\n idbdb = req.result;\n if (autoSchema) readGlobalSchema();else if (idbdb.objectStoreNames.length > 0) {\n try {\n adjustToExistingIndexNames(globalSchema, idbdb.transaction(safariMultiStoreFix(idbdb.objectStoreNames), READONLY));\n } catch (e) {\n // Safari may bail out if > 1 store names. However, this shouldnt be a showstopper. Issue #120.\n }\n }\n\n idbdb.onversionchange = function (ev) {\n db._vcFired = true; // detect implementations that not support versionchange (IE/Edge/Safari)\n db.on(\"versionchange\").fire(ev);\n };\n if (!hasNativeGetDatabaseNames) {\n // Update localStorage with list of database names\n globalDatabaseList(function (databaseNames) {\n if (databaseNames.indexOf(dbName) === -1) return databaseNames.push(dbName);\n });\n }\n // Now, let any subscribers to the on(\"ready\") fire BEFORE any other db operations resume!\n // If an the on(\"ready\") subscriber returns a Promise, we will wait til promise completes or rejects before\n Promise.newPSD(function () {\n Promise.PSD.letThrough = true; // Set a Promise-Specific Data property informing that onready is firing. This will make db._whenReady() let the subscribers use the DB but block all others (!). Quite cool ha?\n try {\n var res = db.on.ready.fire();\n if (res && typeof res.then === 'function') {\n // If on('ready') returns a promise, wait for it to complete and then resume any pending operations.\n res.then(resume, function (err) {\n idbdb.close();\n idbdb = null;\n openError(err);\n });\n } else {\n asap(resume); // Cannot call resume directly because then the pauseResumables would inherit from our PSD scope.\n }\n } catch (e) {\n openError(e);\n }\n\n function resume() {\n db_is_blocked = false;\n executePausedResumeables();\n resolve();\n }\n });\n }, openError);\n } catch (err) {\n openError(err);\n }\n }).then(function () {\n connections.push(db);\n return db;\n });\n };\n\n this.close = function () {\n var idx = connections.indexOf(db);\n if (idx >= 0) connections.splice(idx, 1);\n if (idbdb) {\n idbdb.close();\n idbdb = null;\n autoOpen = false;\n if (db_is_blocked) {\n executePausedResumeables();\n }\n db_is_blocked = false;\n dbOpenError = new exceptions.DatabaseClosed();\n } else if (isBeingOpened) {\n db.on('ready', function () {\n return Promise.reject(new exceptions.DatabaseClosed());\n });\n }\n };\n\n this.delete = function () {\n var args = arguments;\n return new Promise(function (resolve, reject) {\n if (args.length > 0) throw new exceptions.InvalidArgument(\"Arguments not allowed in db.delete()\");\n function doDelete() {\n db.close();\n var req = indexedDB.deleteDatabase(dbName);\n req.onsuccess = function () {\n if (!hasNativeGetDatabaseNames) {\n globalDatabaseList(function (databaseNames) {\n var pos = databaseNames.indexOf(dbName);\n if (pos >= 0) return databaseNames.splice(pos, 1);\n });\n }\n resolve();\n };\n req.onerror = eventRejectHandler(reject, [\"deleting\", dbName]);\n req.onblocked = fireOnBlocked;\n }\n if (isBeingOpened) {\n pausedResumeables.push({ resume: doDelete });\n } else {\n doDelete();\n }\n });\n };\n\n this.backendDB = function () {\n return idbdb;\n };\n\n this.isOpen = function () {\n return idbdb !== null;\n };\n this.hasFailed = function () {\n return dbOpenError !== null;\n };\n this.dynamicallyOpened = function () {\n return autoSchema;\n };\n\n //\n // Properties\n //\n this.name = dbName;\n\n // db.tables - an array of all Table instances.\n setProp(this, \"tables\", {\n get: function () {\n /// \n return keys(allTables).map(function (name) {\n return allTables[name];\n });\n }\n });\n\n //\n // Events\n //\n this.on = Events(this, \"error\", \"populate\", { blocked: [reverseStoppableEventChain, nop], \"ready\": [promisableChain, nop], \"versionchange\": [reverseStoppableEventChain, nop] });\n\n // Handle on('ready') specifically: If DB is already open, trigger the event immediately. Also, default to unsubscribe immediately after being triggered.\n this.on.ready.subscribe = override(this.on.ready.subscribe, function (origSubscribe) {\n return function (subscriber, bSticky) {\n function proxy() {\n if (!bSticky) db.on.ready.unsubscribe(proxy);\n return subscriber.apply(this, arguments);\n }\n origSubscribe.call(this, proxy);\n if (db.isOpen()) {\n if (db_is_blocked) {\n pausedResumeables.push({ resume: proxy });\n } else {\n proxy();\n }\n }\n };\n });\n\n fakeAutoComplete(function () {\n db.on(\"populate\").fire(db._createTransaction(READWRITE, dbStoreNames, globalSchema));\n db.on(\"error\").fire(new Error());\n });\n\n this.transaction = function (mode, tableInstances, scopeFunc) {\n /// \n ///\n /// \n /// \"r\" for readonly, or \"rw\" for readwrite\n /// Table instance, Array of Table instances, String or String Array of object stores to include in the transaction\n /// Function to execute with transaction\n\n // Let table arguments be all arguments between mode and last argument.\n tableInstances = slice(arguments, 1, arguments.length - 1);\n // Let scopeFunc be the last argument\n scopeFunc = arguments[arguments.length - 1];\n var parentTransaction = Promise.PSD && Promise.PSD.trans;\n // Check if parent transactions is bound to this db instance, and if caller wants to reuse it\n if (!parentTransaction || parentTransaction.db !== db || mode.indexOf('!') !== -1) parentTransaction = null;\n var onlyIfCompatible = mode.indexOf('?') !== -1;\n mode = mode.replace('!', '').replace('?', '');\n //\n // Get storeNames from arguments. Either through given table instances, or through given table names.\n //\n var tables = isArray(tableInstances[0]) ? tableInstances.reduce(function (a, b) {\n return a.concat(b);\n }) : tableInstances;\n var error = null;\n var storeNames = tables.map(function (tableInstance) {\n if (typeof tableInstance === \"string\") {\n return tableInstance;\n } else {\n if (!(tableInstance instanceof Table)) error = error || new TypeError(\"Invalid type. Arguments following mode must be instances of Table or String\");\n return tableInstance.name;\n }\n });\n\n //\n // Resolve mode. Allow shortcuts \"r\" and \"rw\".\n //\n if (mode == \"r\" || mode == READONLY) mode = READONLY;else if (mode == \"rw\" || mode == READWRITE) mode = READWRITE;else error = new exceptions.InvalidArgument(\"Invalid transaction mode: \" + mode);\n\n if (parentTransaction) {\n // Basic checks\n if (!error) {\n if (parentTransaction && parentTransaction.mode === READONLY && mode === READWRITE) {\n if (onlyIfCompatible) parentTransaction = null; // Spawn new transaction instead.\n else error = error || new exceptions.SubTransaction(\"Cannot enter a sub-transaction with READWRITE mode when parent transaction is READONLY\");\n }\n if (parentTransaction) {\n storeNames.forEach(function (storeName) {\n if (!parentTransaction.tables.hasOwnProperty(storeName)) {\n if (onlyIfCompatible) parentTransaction = null; // Spawn new transaction instead.\n else error = error || new exceptions.SubTransaction(\"Table \" + storeName + \" not included in parent transaction. Parent Transaction function: \" + parentTransaction.scopeFunc.toString());\n }\n });\n }\n }\n }\n if (parentTransaction) {\n // If this is a sub-transaction, lock the parent and then launch the sub-transaction.\n return parentTransaction._promise(mode, enterTransactionScope, \"lock\");\n } else {\n // If this is a root-level transaction, wait til database is ready and then launch the transaction.\n return db._whenReady(enterTransactionScope);\n }\n\n function enterTransactionScope(resolve, reject) {\n // Our transaction. To be set later.\n var trans = null;\n var isConstructing = true;\n\n try {\n // Throw any error if any of the above checks failed.\n // Real error defined some lines up. We throw it here from within a Promise to reject Promise\n // rather than make caller need to both use try..catch and promise catching. The reason we still\n // throw here rather than do Promise.reject(error) is that we like to have the stack attached to the\n // error. Also because there is a catch() clause bound to this try() that will bubble the error\n // to the parent transaction.\n if (error) throw error;\n\n //\n // Create Transaction instance\n //\n trans = db._createTransaction(mode, storeNames, globalSchema, parentTransaction);\n\n // Provide arguments to the scope function (for backward compatibility)\n var tableArgs = storeNames.map(function (name) {\n return trans.tables[name];\n });\n tableArgs.push(trans);\n\n // If transaction completes, resolve the Promise with the return value of scopeFunc.\n var returnValue;\n var uncompletedRequests = 0;\n\n // Create a new PSD frame to hold Promise.PSD.trans. Must not be bound to the current PSD frame since we want\n // it to pop before then() callback is called of our returned Promise.\n Promise.newPSD(function () {\n // Let the transaction instance be part of a Promise-specific data (PSD) value.\n Promise.PSD.trans = trans;\n trans.scopeFunc = scopeFunc; // For Error (\"Table \" + storeNames[0] + \" not part of transaction\") when it happens. This may help localizing the code that started a transaction used on another place.\n\n if (parentTransaction) {\n // Emulate transaction commit awareness for inner transaction (must 'commit' when the inner transaction has no more operations ongoing)\n trans.idbtrans = parentTransaction.idbtrans;\n trans._promise = override(trans._promise, function (orig) {\n return function (mode, fn, writeLock) {\n ++uncompletedRequests;\n function proxy(fn2) {\n return function (val) {\n var retval;\n // _rootExec needed so that we do not loose any IDBTransaction in a setTimeout() call.\n Promise._rootExec(function () {\n retval = fn2(val);\n // _tickFinalize makes sure to support lazy micro tasks executed in Promise._rootExec().\n // We certainly do not want to copy the bad pattern from IndexedDB but instead allow\n // execution of Promise.then() callbacks until the're all done.\n Promise._tickFinalize(function () {\n if (--uncompletedRequests === 0 && trans.active) {\n trans.active = false;\n trans.on.complete.fire(); // A called db operation has completed without starting a new operation. The flow is finished\n }\n });\n });\n return retval;\n };\n }\n return orig.call(this, mode, function (resolve2, reject2, trans) {\n return fn(proxy(resolve2), proxy(reject2), trans);\n }, writeLock);\n };\n });\n }\n trans.complete(function () {\n resolve(returnValue);\n });\n // If transaction fails, reject the Promise and bubble to db if noone catched this rejection.\n trans.error(function (e) {\n if (trans.idbtrans) trans.idbtrans.onerror = preventDefault; // Prohibit AbortError from firing.\n try {\n trans.abort();\n } catch (e2) {}\n if (parentTransaction) {\n parentTransaction.active = false;\n parentTransaction.on.error.fire(e); // Bubble to parent transaction\n }\n\n if (isConstructing) asap(doReject);else doReject();\n function doReject() {\n var catched = reject(e);\n if (!parentTransaction && !catched) {\n db.on.error.fire(e); // If not catched, bubble error to db.on(\"error\").\n }\n }\n });\n\n // Finally, call the scope function with our table and transaction arguments.\n Promise._rootExec(function () {\n returnValue = scopeFunc.apply(trans, tableArgs); // NOTE: returnValue is used in trans.on.complete() not as a returnValue to this func.\n if (returnValue) {\n if (typeof returnValue.next === 'function' && typeof returnValue.throw === 'function') {\n // scopeFunc returned an iterable. Handle yield as await.\n returnValue = awaitIterable(returnValue);\n } else if (typeof returnValue.then === 'function' && !returnValue.hasOwnProperty('_PSD')) {\n throw new exceptions.IncompatiblePromise();\n }\n }\n });\n });\n if (!trans.idbtrans || parentTransaction && uncompletedRequests === 0) {\n trans._nop(); // Make sure transaction is being used so that it will resolve.\n }\n } catch (e) {\n // If exception occur, abort the transaction and reject Promise.\n if (trans && trans.idbtrans) trans.idbtrans.onerror = preventDefault; // Prohibit AbortError from firing.\n if (trans) trans.abort();\n if (parentTransaction) parentTransaction.on.error.fire(e);\n asap(function () {\n // Need to use asap(=setImmediate/setTimeout) before calling reject because we are in the Promise constructor and reject() will always return false if so.\n if (!reject(e)) db.on(\"error\").fire(e); // If not catched, bubble exception to db.on(\"error\");\n });\n }\n isConstructing = false;\n }\n };\n\n this.table = function (tableName) {\n /// \n if (fake && autoSchema) return new WriteableTable(tableName);\n if (!allTables.hasOwnProperty(tableName)) {\n throw new exceptions.InvalidTable('Table ' + tableName + ' does not exist');\n }\n return allTables[tableName];\n };\n\n //\n //\n //\n // Table Class\n //\n //\n //\n function Table(name, transactionPromiseFactory, tableSchema, collClass) {\n /// \n this.name = name;\n this.schema = tableSchema;\n this.hook = allTables[name] ? allTables[name].hook : Events(null, {\n \"creating\": [hookCreatingChain, nop],\n \"reading\": [pureFunctionChain, mirror],\n \"updating\": [hookUpdatingChain, nop],\n \"deleting\": [hookDeletingChain, nop]\n });\n this._tpf = transactionPromiseFactory;\n this._collClass = collClass || Collection;\n }\n\n extendProto(Table.prototype, function () {\n function failReadonly() {\n // It's ok to throw here because this can only happen within a transaction,\n // and will always be caught by the transaction scope and returned as a\n // failed promise.\n throw new exceptions.ReadOnly(\"Current Transaction is READONLY\");\n }\n return {\n //\n // Table Protected Methods\n //\n\n _trans: function getTransaction(mode, fn, writeLocked) {\n return this._tpf(mode, [this.name], fn, writeLocked);\n },\n _idbstore: function getIDBObjectStore(mode, fn, writeLocked) {\n if (fake) return new Promise(fn); // Simplify the work for Intellisense/Code completion.\n var self = this;\n return this._tpf(mode, [this.name], function (resolve, reject, trans) {\n fn(resolve, reject, trans.idbtrans.objectStore(self.name), trans);\n }, writeLocked);\n },\n\n //\n // Table Public Methods\n //\n get: function (key, cb) {\n var self = this;\n return this._idbstore(READONLY, function (resolve, reject, idbstore) {\n fake && resolve(self.schema.instanceTemplate);\n var req = idbstore.get(key);\n req.onerror = eventRejectHandler(reject, [\"getting\", key, \"from\", self.name]);\n req.onsuccess = function () {\n resolve(self.hook.reading.fire(req.result));\n };\n }).then(cb);\n },\n where: function (indexName) {\n return new WhereClause(this, indexName);\n },\n count: function (cb) {\n return this.toCollection().count(cb);\n },\n offset: function (offset) {\n return this.toCollection().offset(offset);\n },\n limit: function (numRows) {\n return this.toCollection().limit(numRows);\n },\n reverse: function () {\n return this.toCollection().reverse();\n },\n filter: function (filterFunction) {\n return this.toCollection().and(filterFunction);\n },\n each: function (fn) {\n return this.toCollection().each(fn);\n },\n toArray: function (cb) {\n return this.toCollection().toArray(cb);\n },\n orderBy: function (index) {\n return new this._collClass(new WhereClause(this, index));\n },\n\n toCollection: function () {\n return new this._collClass(new WhereClause(this));\n },\n\n mapToClass: function (constructor, structure) {\n /// \n /// Map table to a javascript constructor function. Objects returned from the database will be instances of this class, making\n /// it possible to the instanceOf operator as well as extending the class using constructor.prototype.method = function(){...}.\n /// \n /// Constructor function representing the class.\n /// Helps IDE code completion by knowing the members that objects contain and not just the indexes. Also\n /// know what type each member has. Example: {name: String, emailAddresses: [String], password}\n this.schema.mappedClass = constructor;\n var instanceTemplate = Object.create(constructor.prototype);\n if (structure) {\n // structure and instanceTemplate is for IDE code competion only while constructor.prototype is for actual inheritance.\n applyStructure(instanceTemplate, structure);\n }\n this.schema.instanceTemplate = instanceTemplate;\n\n // Now, subscribe to the when(\"reading\") event to make all objects that come out from this table inherit from given class\n // no matter which method to use for reading (Table.get() or Table.where(...)... )\n var readHook = function (obj) {\n if (!obj) return obj; // No valid object. (Value is null). Return as is.\n // Create a new object that derives from constructor:\n var res = Object.create(constructor.prototype);\n // Clone members:\n for (var m in obj) {\n if (obj.hasOwnProperty(m)) res[m] = obj[m];\n }return res;\n };\n\n if (this.schema.readHook) {\n this.hook.reading.unsubscribe(this.schema.readHook);\n }\n this.schema.readHook = readHook;\n this.hook(\"reading\", readHook);\n return constructor;\n },\n defineClass: function (structure) {\n /// \n /// Define all members of the class that represents the table. This will help code completion of when objects are read from the database\n /// as well as making it possible to extend the prototype of the returned constructor function.\n /// \n /// Helps IDE code completion by knowing the members that objects contain and not just the indexes. Also\n /// know what type each member has. Example: {name: String, emailAddresses: [String], properties: {shoeSize: Number}}\n return this.mapToClass(Dexie.defineClass(structure), structure);\n },\n add: failReadonly,\n put: failReadonly,\n 'delete': failReadonly,\n clear: failReadonly,\n update: failReadonly\n };\n });\n\n //\n //\n //\n // WriteableTable Class (extends Table)\n //\n //\n //\n function WriteableTable(name, transactionPromiseFactory, tableSchema, collClass) {\n Table.call(this, name, transactionPromiseFactory, tableSchema, collClass || WriteableCollection);\n }\n\n function BulkErrorHandlerCatchAll(errorList, done) {\n var psd = Promise.PSD;\n return function (ev) {\n try {\n if (ev.stopPropagation) ev.stopPropagation();\n if (ev.preventDefault) ev.preventDefault();\n var err = ev.target.error;\n errorList.push(err);\n if (ev.target._err) {\n Promise.usePSD(psd, ev.target._err.bind(null, err));\n }\n } finally {\n if (done) done();\n }\n };\n }\n\n function BulkErrorHandler(done) {\n var psd = Promise.PSD;\n return function (ev) {\n var err;\n try {\n err = ev.target.error;\n if (ev.target._err) {\n Promise.usePSD(psd, ev.target._err.bind(null, err));\n }\n } finally {\n done(err);\n }\n };\n }\n\n function BulkSuccessHandler(done, hookListener) {\n var psd = Promise.PSD;\n return hookListener ? function (ev) {\n var res;\n try {\n res = ev.target.result;\n ev.target._suc && Promise.usePSD(psd, ev.target._suc.bind(null, res));\n } finally {\n if (done) done(res);\n }\n } : function (ev) {\n done(ev.target.result);\n };\n }\n\n function bulkDelete(idbstore, trans, keysOrTuples, hasDeleteHook, deletingHook) {\n // If hasDeleteHook, keysOrTuples must be an array of tuples: [[key1, value2],[key2,value2],...],\n // else keysOrTuples must be just an array of keys: [key1, key2, ...].\n return new Promise(function (resolve, reject) {\n var len = keysOrTuples.length,\n lastItem = len - 1;\n if (len === 0) return resolve();\n if (!hasDeleteHook) {\n for (var i = 0; i < len; ++i) {\n var req = idbstore.delete(keysOrTuples[i]);\n req.onerror = function (ev) {\n return reject(mapError(ev.target.error));\n };\n if (i === lastItem) req.onsuccess = function () {\n return resolve();\n };\n }\n } else {\n var hookCtx = { onsuccess: null, onerror: null },\n errorHandler = BulkErrorHandler(function (e) {\n return reject(mapError(e));\n }),\n successHandler = BulkSuccessHandler(null, true);\n miniTryCatch(function () {\n for (var i = 0; i < len; ++i) {\n var tuple = keysOrTuples[i];\n deletingHook.call(hookCtx, tuple[0], tuple[1], trans);\n var req = idbstore.delete(tuple[0]);\n if (hookCtx.onerror) req._err = hookCtx.onerror;\n if (hookCtx.onsuccess) req._suc = hookCtx.onsuccess;\n req.onerror = errorHandler;\n if (i === lastItem) req.onsuccess = BulkSuccessHandler(resolve, true);else req.onsuccess = successHandler;\n hookCtx.onsuccess = null;\n hookCtx.onerror = null;\n }\n }, function (err) {\n hookCtx.onerror && hookCtx.onerror(err);\n throw err;\n });\n }\n });\n }\n\n derive(WriteableTable).from(Table).extend(function () {\n\n return {\n bulkDelete: function (keys) {\n if (this.hook.deleting.fire === nop) {\n return this._idbstore(READWRITE, function (resolve, reject, idbstore, trans) {\n resolve(bulkDelete(idbstore, trans, keys, false, nop));\n });\n } else {\n return this.where(':id').anyOf(keys).delete().then(function () {}); // Resolve with undefined.\n }\n },\n bulkPut: function (objects, keys) {\n var _this = this;\n\n return this._idbstore(READWRITE, function (resolve, reject, idbstore, trans) {\n if (!idbstore.keyPath && !_this.schema.primKey.auto && !keys) throw new exceptions.InvalidArgument(\"bulkPut() with non-inbound keys requires keys array in second argument\");\n if (idbstore.keyPath && keys) throw new exceptions.InvalidArgument(\"bulkPut(): keys argument invalid on tables with inbound keys\");\n if (keys && keys.length !== objects.length) throw new exceptions.InvalidArgument(\"Arguments objects and keys must have the same length\");\n if (objects.length === 0) return resolve(); // Caller provided empty list.\n var done = function (result) {\n if (errorList.length === 0) resolve(result);else reject(new BulkError(_this.name + '.bulkPut(): ' + errorList.length + ' of ' + numObjs + ' operations failed', errorList));\n };\n var req,\n errorList = [],\n errorHandler,\n numObjs = objects.length,\n table = trans.tables[_this.name]; // Enable us to do stuff in several steps with same transaction.\n if (_this.hook.creating.fire === nop && _this.hook.updating.fire === nop) {\n //\n // Standard Bulk (no 'creating' or 'updating' hooks to care about)\n //\n errorHandler = BulkErrorHandlerCatchAll(errorList);\n for (var i = 0, l = objects.length; i < l; ++i) {\n req = keys ? idbstore.put(objects[i], keys[i]) : idbstore.put(objects[i]);\n req.onerror = errorHandler;\n }\n // Only need to catch success or error on the last operation\n // according to the IDB spec.\n req.onerror = BulkErrorHandlerCatchAll(errorList, done);\n req.onsuccess = BulkSuccessHandler(done);\n } else {\n var effectiveKeys = keys || idbstore.keyPath && objects.map(function (o) {\n return getByKeyPath(o, idbstore.keyPath);\n });\n var objectLookup = effectiveKeys && effectiveKeys.reduce(function (res, key, i) {\n if (key != null) res[key] = objects[i];\n return res;\n }, {}); // Generates map of {[key]: object}\n\n var promise = !effectiveKeys ?\n\n // Auto-incremented key-less objects only without any keys argument.\n table.bulkAdd(objects) :\n\n // Keys provided. Either as inbound in provided objects, or as a keys argument.\n // Begin with updating those that exists in DB:\n table.where(':id').anyOf(effectiveKeys.filter(function (key) {\n return key != null;\n })).modify(function () {\n this.value = objectLookup[this.primKey];\n objectLookup[this.primKey] = null; // Mark as \"don't add this\"\n }).catch(ModifyError, function (e) {\n errorList = e.failures; // No need to concat here. These are the first errors added.\n }).then(function () {\n // Now, let's examine which items didnt exist so we can add them:\n var objsToAdd = [],\n keysToAdd = keys && [];\n // Iterate backwards. Why? Because if same key was used twice, just add the last one.\n for (var i = effectiveKeys.length - 1; i >= 0; --i) {\n var key = effectiveKeys[i];\n if (key == null || objectLookup[key]) {\n objsToAdd.push(objects[i]);\n keys && keysToAdd.push(key);\n if (key != null) objectLookup[key] = null; // Mark as \"dont add again\"\n }\n }\n // The items are in reverse order so reverse them before adding.\n // Could be important in order to get auto-incremented keys the way the caller\n // would expect. Could have used unshift instead of push()/reverse(),\n // but: http://jsperf.com/unshift-vs-reverse\n objsToAdd.reverse();\n keys && keysToAdd.reverse();\n return table.bulkAdd(objsToAdd, keysToAdd);\n }).then(function (lastAddedKey) {\n // Resolve with key of the last object in given arguments to bulkPut():\n var lastEffectiveKey = effectiveKeys[effectiveKeys.length - 1]; // Key was provided.\n return lastEffectiveKey != null ? lastEffectiveKey : lastAddedKey;\n });\n\n promise.then(done).catch(BulkError, function (e) {\n // Concat failure from ModifyError and reject using our 'done' method.\n errorList = errorList.concat(e.failures);\n done();\n }).catch(reject);\n }\n }, \"locked\"); // If called from transaction scope, lock transaction til all steps are done.\n },\n bulkAdd: function (objects, keys) {\n var self = this,\n creatingHook = this.hook.creating.fire;\n return this._idbstore(READWRITE, function (resolve, reject, idbstore, trans) {\n if (!idbstore.keyPath && !self.schema.primKey.auto && !keys) throw new exceptions.InvalidArgument(\"bulkAdd() with non-inbound keys requires keys array in second argument\");\n if (idbstore.keyPath && keys) throw new exceptions.InvalidArgument(\"bulkAdd(): keys argument invalid on tables with inbound keys\");\n if (keys && keys.length !== objects.length) throw new exceptions.InvalidArgument(\"Arguments objects and keys must have the same length\");\n if (objects.length === 0) return resolve(); // Caller provided empty list.\n function done(result) {\n if (errorList.length === 0) resolve(result);else reject(new BulkError(self.name + '.bulkAdd(): ' + errorList.length + ' of ' + numObjs + ' operations failed', errorList));\n }\n var req,\n errorList = [],\n errorHandler,\n successHandler,\n numObjs = objects.length;\n if (creatingHook !== nop) {\n //\n // There are subscribers to hook('creating')\n // Must behave as documented.\n //\n var keyPath = idbstore.keyPath,\n hookCtx = { onerror: null, onsuccess: null };\n errorHandler = BulkErrorHandlerCatchAll(errorList, null);\n successHandler = BulkSuccessHandler(null, true);\n\n miniTryCatch(function () {\n for (var i = 0, l = objects.length; i < l; ++i) {\n var key = keys && keys[i];\n var obj = objects[i],\n effectiveKey = keys ? key : keyPath ? getByKeyPath(obj, keyPath) : undefined,\n keyToUse = creatingHook.call(hookCtx, effectiveKey, obj, trans);\n if (effectiveKey == null && keyToUse != null) {\n if (keyPath) {\n obj = deepClone(obj);\n setByKeyPath(obj, keyPath, keyToUse);\n } else {\n key = keyToUse;\n }\n }\n req = key != null ? idbstore.add(obj, key) : idbstore.add(obj);\n if (hookCtx.onerror) req._err = hookCtx.onerror;\n if (hookCtx.onsuccess) req._suc = hookCtx.onsuccess;\n if (i < l - 1) {\n req.onerror = errorHandler;\n if (hookCtx.onsuccess) req.onsuccess = successHandler;\n // Reset event listeners for next iteration.\n hookCtx.onerror = null;\n hookCtx.onsuccess = null;\n }\n }\n }, function (err) {\n hookCtx.onerror && hookCtx.onerror(err);\n throw err;\n });\n\n req.onerror = BulkErrorHandlerCatchAll(errorList, done);\n req.onsuccess = BulkSuccessHandler(done, true);\n } else {\n //\n // Standard Bulk (no 'creating' hook to care about)\n //\n errorHandler = BulkErrorHandlerCatchAll(errorList);\n for (var i = 0, l = objects.length; i < l; ++i) {\n req = keys ? idbstore.add(objects[i], keys[i]) : idbstore.add(objects[i]);\n req.onerror = errorHandler;\n }\n // Only need to catch success or error on the last operation\n // according to the IDB spec.\n req.onerror = BulkErrorHandlerCatchAll(errorList, done);\n req.onsuccess = BulkSuccessHandler(done);\n }\n });\n },\n add: function (obj, key) {\n /// \n /// Add an object to the database. In case an object with same primary key already exists, the object will not be added.\n /// \n /// A javascript object to insert\n /// Primary key\n var self = this,\n creatingHook = this.hook.creating.fire;\n return this._idbstore(READWRITE, function (resolve, reject, idbstore, trans) {\n var thisCtx = { onsuccess: null, onerror: null };\n if (creatingHook !== nop) {\n var effectiveKey = key != null ? key : idbstore.keyPath ? getByKeyPath(obj, idbstore.keyPath) : undefined;\n var keyToUse = creatingHook.call(thisCtx, effectiveKey, obj, trans); // Allow subscribers to when(\"creating\") to generate the key.\n if (effectiveKey == null && keyToUse != null) {\n // Using \"==\" and \"!=\" to check for either null or undefined!\n if (idbstore.keyPath) setByKeyPath(obj, idbstore.keyPath, keyToUse);else key = keyToUse;\n }\n }\n try {\n var req = key != null ? idbstore.add(obj, key) : idbstore.add(obj),\n psd = Promise.PSD;\n req.onerror = eventRejectHandler(function (e) {\n if (thisCtx.onerror) Promise.usePSD(psd, thisCtx.onerror.bind(thisCtx, e));\n return reject(e);\n }, [\"adding\", obj, \"into\", self.name]);\n req.onsuccess = function (ev) {\n var keyPath = idbstore.keyPath;\n if (keyPath) setByKeyPath(obj, keyPath, ev.target.result);\n if (thisCtx.onsuccess) Promise.usePSD(psd, thisCtx.onsuccess.bind(thisCtx, ev.target.result));\n resolve(req.result);\n };\n } catch (e) {\n if (thisCtx.onerror) thisCtx.onerror(e);\n throw e;\n }\n });\n },\n\n put: function (obj, key) {\n /// \n /// Add an object to the database but in case an object with same primary key alread exists, the existing one will get updated.\n /// \n /// A javascript object to insert or update\n /// Primary key\n var self = this,\n creatingHook = this.hook.creating.fire,\n updatingHook = this.hook.updating.fire;\n if (creatingHook !== nop || updatingHook !== nop) {\n //\n // People listens to when(\"creating\") or when(\"updating\") events!\n // We must know whether the put operation results in an CREATE or UPDATE.\n //\n return this._trans(READWRITE, function (resolve, reject, trans) {\n // Since key is optional, make sure we get it from obj if not provided\n var effectiveKey = key !== undefined ? key : self.schema.primKey.keyPath && getByKeyPath(obj, self.schema.primKey.keyPath);\n if (effectiveKey == null) {\n // \"== null\" means checking for either null or undefined.\n // No primary key. Must use add().\n trans.tables[self.name].add(obj).then(resolve, reject);\n } else {\n // Primary key exist. Lock transaction and try modifying existing. If nothing modified, call add().\n trans._lock(); // Needed because operation is splitted into modify() and add().\n // clone obj before this async call. If caller modifies obj the line after put(), the IDB spec requires that it should not affect operation.\n obj = deepClone(obj);\n trans.tables[self.name].where(\":id\").equals(effectiveKey).modify(function () {\n // Replace extisting value with our object\n // CRUD event firing handled in WriteableCollection.modify()\n this.value = obj;\n }).then(function (count) {\n if (count === 0) {\n // Object's key was not found. Add the object instead.\n // CRUD event firing will be done in add()\n return trans.tables[self.name].add(obj, key); // Resolving with another Promise. Returned Promise will then resolve with the new key.\n } else {\n return effectiveKey; // Resolve with the provided key.\n }\n }).finally(function () {\n trans._unlock();\n }).then(resolve, reject);\n }\n });\n } else {\n // Use the standard IDB put() method.\n return this._idbstore(READWRITE, function (resolve, reject, idbstore) {\n var req = key !== undefined ? idbstore.put(obj, key) : idbstore.put(obj);\n req.onerror = eventRejectHandler(reject, [\"putting\", obj, \"into\", self.name]);\n req.onsuccess = function (ev) {\n var keyPath = idbstore.keyPath;\n if (keyPath) setByKeyPath(obj, keyPath, ev.target.result);\n resolve(req.result);\n };\n });\n }\n },\n\n 'delete': function (key) {\n /// Primary key of the object to delete\n if (this.hook.deleting.subscribers.length) {\n // People listens to when(\"deleting\") event. Must implement delete using WriteableCollection.delete() that will\n // call the CRUD event. Only WriteableCollection.delete() will know whether an object was actually deleted.\n return this.where(\":id\").equals(key).delete();\n } else {\n // No one listens. Use standard IDB delete() method.\n return this._idbstore(READWRITE, function (resolve, reject, idbstore) {\n var req = idbstore.delete(key);\n req.onerror = eventRejectHandler(reject, [\"deleting\", key, \"from\", idbstore.name]);\n req.onsuccess = function () {\n resolve(req.result);\n };\n });\n }\n },\n\n clear: function () {\n if (this.hook.deleting.subscribers.length) {\n // People listens to when(\"deleting\") event. Must implement delete using WriteableCollection.delete() that will\n // call the CRUD event. Only WriteableCollection.delete() will knows which objects that are actually deleted.\n return this.toCollection().delete();\n } else {\n return this._idbstore(READWRITE, function (resolve, reject, idbstore) {\n var req = idbstore.clear();\n req.onerror = eventRejectHandler(reject, [\"clearing\", idbstore.name]);\n req.onsuccess = function () {\n resolve(req.result);\n };\n });\n }\n },\n\n update: function (keyOrObject, modifications) {\n if (typeof modifications !== 'object' || isArray(modifications)) throw new exceptions.InvalidArgument(\"db.update(keyOrObject, modifications). modifications must be an object.\");\n if (typeof keyOrObject === 'object' && !isArray(keyOrObject)) {\n // object to modify. Also modify given object with the modifications:\n keys(modifications).forEach(function (keyPath) {\n setByKeyPath(keyOrObject, keyPath, modifications[keyPath]);\n });\n var key = getByKeyPath(keyOrObject, this.schema.primKey.keyPath);\n if (key === undefined) Promise.reject(new exceptions.InvalidArgument(\"Given object does not contain its primary key\"));\n return this.where(\":id\").equals(key).modify(modifications);\n } else {\n // key to modify\n return this.where(\":id\").equals(keyOrObject).modify(modifications);\n }\n }\n };\n });\n\n //\n //\n //\n // Transaction Class\n //\n //\n //\n function Transaction(mode, storeNames, dbschema, parent) {\n /// \n /// Transaction class. Represents a database transaction. All operations on db goes through a Transaction.\n /// \n /// Any of \"readwrite\" or \"readonly\"\n /// Array of table names to operate on\n var self = this;\n this.db = db;\n this.mode = mode;\n this.storeNames = storeNames;\n this.idbtrans = null;\n this.on = Events(this, [\"complete\", \"error\"], \"abort\");\n this._reculock = 0;\n this._blockedFuncs = [];\n this._psd = null;\n this.active = true;\n this._dbschema = dbschema;\n if (parent) this.parent = parent;\n this._tpf = transactionPromiseFactory;\n this.tables = Object.create(notInTransFallbackTables); // ...so that all non-included tables exists as instances (possible to call table.name for example) but will fail as soon as trying to execute a query on it.\n\n function transactionPromiseFactory(mode, storeNames, fn, writeLocked) {\n // Creates a Promise instance and calls fn (resolve, reject, trans) where trans is the instance of this transaction object.\n // Support for write-locking the transaction during the promise life time from creation to success/failure.\n // This is actually not needed when just using single operations on IDB, since IDB implements this internally.\n // However, when implementing a write operation as a series of operations on top of IDB(collection.delete() and collection.modify() for example),\n // lock is indeed needed if Dexie APIshould behave in a consistent manner for the API user.\n // Another example of this is if we want to support create/update/delete events,\n // we need to implement put() using a series of other IDB operations but still need to lock the transaction all the way.\n return self._promise(mode, fn, writeLocked);\n }\n\n for (var i = storeNames.length - 1; i !== -1; --i) {\n var name = storeNames[i];\n var table = db._tableFactory(mode, dbschema[name], transactionPromiseFactory);\n this.tables[name] = table;\n if (!this[name]) this[name] = table;\n }\n }\n\n extendProto(Transaction.prototype, {\n //\n // Transaction Protected Methods (not required by API users, but needed internally and eventually by dexie extensions)\n //\n\n _lock: function () {\n // Temporary set all requests into a pending queue if they are called before database is ready.\n ++this._reculock; // Recursive read/write lock pattern using PSD (Promise Specific Data) instead of TLS (Thread Local Storage)\n if (this._reculock === 1 && Promise.PSD) Promise.PSD.lockOwnerFor = this;\n return this;\n },\n _unlock: function () {\n if (--this._reculock === 0) {\n if (Promise.PSD) Promise.PSD.lockOwnerFor = null;\n while (this._blockedFuncs.length > 0 && !this._locked()) {\n var fn = this._blockedFuncs.shift();\n try {\n fn();\n } catch (e) {}\n }\n }\n return this;\n },\n _locked: function () {\n // Checks if any write-lock is applied on this transaction.\n // To simplify the Dexie API for extension implementations, we support recursive locks.\n // This is accomplished by using \"Promise Specific Data\" (PSD).\n // PSD data is bound to a Promise and any child Promise emitted through then() or resolve( new Promise() ).\n // Promise.PSD is local to code executing on top of the call stacks of any of any code executed by Promise():\n // * callback given to the Promise() constructor (function (resolve, reject){...})\n // * callbacks given to then()/catch()/finally() methods (function (value){...})\n // 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.\n // Derivation is done so that the inner PSD __proto__ points to the outer PSD.\n // Promise.PSD.lockOwnerFor will point to current transaction object if the currently executing PSD scope owns the lock.\n return this._reculock && (!Promise.PSD || Promise.PSD.lockOwnerFor !== this);\n },\n _nop: function (cb) {\n // An asyncronic no-operation that may call given callback when done doing nothing. An alternative to asap() if we must not lose the transaction.\n this.tables[this.storeNames[0]].get(0).then(cb);\n },\n _promise: function (mode, fn, bWriteLock) {\n var self = this;\n return Promise.newPSD(function () {\n var p;\n // Read lock always\n if (!self._locked()) {\n p = self.active ? new Promise(function (resolve, reject) {\n if (!self.idbtrans && mode) {\n if (!idbdb) throw !dbOpenError || [\"DatabaseClosedError\", \"MissingAPIError\"].indexOf(dbOpenError.name) >= 0 ? dbOpenError : // Errors where it is no difference whether it was caused by the user operation or an earlier call to db.open()\n new exceptions.OpenFailed(dbOpenError); // Make it clear that the user operation was not what caused the error - the error had occurred earlier on db.open()!\n\n var idbtrans = self.idbtrans = idbdb.transaction(safariMultiStoreFix(self.storeNames), self.mode);\n idbtrans.onerror = function (e) {\n self.on(\"error\").fire(e && e.target.error);\n e.preventDefault(); // Prohibit default bubbling to window.error\n self.abort(); // Make sure transaction is aborted since we preventDefault.\n };\n idbtrans.onabort = function (e) {\n // Workaround for issue #78 - low disk space on chrome.\n // onabort is called but never onerror. Call onerror explicitely.\n // Do this in a future tick so we allow default onerror to execute before doing the fallback.\n asap(function () {\n self.on('error').fire(new exceptions.Abort(\"Transaction aborted for unknown reason\"));\n });\n\n self.active = false;\n self.on(\"abort\").fire(e);\n };\n idbtrans.oncomplete = function (e) {\n self.active = false;\n self.on(\"complete\").fire(e);\n };\n }\n if (bWriteLock) self._lock(); // Write lock if write operation is requested\n try {\n fn(resolve, reject, self);\n } catch (e) {\n // Direct exception happened when doing operation.\n // We must immediately fire the error and abort the transaction.\n // When this happens we are still constructing the Promise so we don't yet know\n // whether the caller is about to catch() the error or not. Have to make\n // transaction fail. Catching such an error wont stop transaction from failing.\n // This is a limitation we have to live with.\n var e2 = stack(mapError(e));\n Dexie.ignoreTransaction(function () {\n self.on('error').fire(e2);\n });\n self.abort();\n reject(e2);\n }\n }) : Promise.reject(stack(new exceptions.TransactionInactive(\"Transaction is inactive. Original Scope Function Source: \" + self.scopeFunc.toString())));\n if (self.active && bWriteLock) p.finally(function () {\n self._unlock();\n });\n } else {\n // Transaction is write-locked. Wait for mutex.\n p = new Promise(function (resolve, reject) {\n self._blockedFuncs.push(function () {\n self._promise(mode, fn, bWriteLock).then(resolve, reject);\n });\n });\n }\n p.onuncatched = function (e) {\n // Bubble to transaction. Even though IDB does this internally, it would just do it for error events and not for caught exceptions.\n Dexie.ignoreTransaction(function () {\n self.on(\"error\").fire(e);\n });\n self.abort();\n };\n return p;\n });\n },\n\n //\n // Transaction Public Methods\n //\n\n complete: function (cb) {\n return this.on(\"complete\", cb);\n },\n error: function (cb) {\n return this.on(\"error\", cb);\n },\n abort: function () {\n if (this.idbtrans && this.active) try {\n // TODO: if !this.idbtrans, enqueue an abort() operation.\n this.active = false;\n this.idbtrans.abort();\n this.on.error.fire(new exceptions.Abort(\"Transaction Aborted\"));\n } catch (e) {}\n },\n table: function (name) {\n if (!this.tables.hasOwnProperty(name)) {\n throw new exceptions.InvalidTable(\"Table \" + name + \" not in transaction\");\n }\n return this.tables[name];\n }\n });\n\n //\n //\n //\n // WhereClause\n //\n //\n //\n function WhereClause(table, index, orCollection) {\n /// \n /// \n /// \n this._ctx = {\n table: table,\n index: index === \":id\" ? null : index,\n collClass: table._collClass,\n or: orCollection\n };\n }\n\n extendProto(WhereClause.prototype, function () {\n\n // WhereClause private methods\n\n function fail(c, err, T) {\n var collection = c instanceof WhereClause ? new c._ctx.collClass(c) : c;\n try {\n throw T ? new T(err) : new TypeError(err);\n } catch (e) {\n collection._ctx.error = e;\n }\n return collection;\n }\n\n function emptyCollection(whereClause) {\n return new whereClause._ctx.collClass(whereClause, function () {\n return IDBKeyRange.only(\"\");\n }).limit(0);\n }\n\n function getSetArgs(args) {\n return slice(args.length === 1 && isArray(args[0]) ? args[0] : args);\n }\n\n function upperFactory(dir) {\n return dir === \"next\" ? function (s) {\n return s.toUpperCase();\n } : function (s) {\n return s.toLowerCase();\n };\n }\n function lowerFactory(dir) {\n return dir === \"next\" ? function (s) {\n return s.toLowerCase();\n } : function (s) {\n return s.toUpperCase();\n };\n }\n function nextCasing(key, lowerKey, upperNeedle, lowerNeedle, cmp, dir) {\n var length = Math.min(key.length, lowerNeedle.length);\n var llp = -1;\n for (var i = 0; i < length; ++i) {\n var lwrKeyChar = lowerKey[i];\n if (lwrKeyChar !== lowerNeedle[i]) {\n if (cmp(key[i], upperNeedle[i]) < 0) return key.substr(0, i) + upperNeedle[i] + upperNeedle.substr(i + 1);\n if (cmp(key[i], lowerNeedle[i]) < 0) return key.substr(0, i) + lowerNeedle[i] + upperNeedle.substr(i + 1);\n if (llp >= 0) return key.substr(0, llp) + lowerKey[llp] + upperNeedle.substr(llp + 1);\n return null;\n }\n if (cmp(key[i], lwrKeyChar) < 0) llp = i;\n }\n if (length < lowerNeedle.length && dir === \"next\") return key + upperNeedle.substr(key.length);\n if (length < key.length && dir === \"prev\") return key.substr(0, upperNeedle.length);\n return llp < 0 ? null : key.substr(0, llp) + lowerNeedle[llp] + upperNeedle.substr(llp + 1);\n }\n\n function addIgnoreCaseAlgorithm(whereClause, match, needles, suffix) {\n /// \n var upper,\n lower,\n compare,\n upperNeedles,\n lowerNeedles,\n direction,\n nextKeySuffix,\n needlesLen = needles.length;\n function initDirection(dir) {\n upper = upperFactory(dir);\n lower = lowerFactory(dir);\n compare = dir === \"next\" ? simpleCompare : simpleCompareReverse;\n var needleBounds = needles.map(function (needle) {\n return { lower: lower(needle), upper: upper(needle) };\n }).sort(function (a, b) {\n return compare(a.lower, b.lower);\n });\n upperNeedles = needleBounds.map(function (nb) {\n return nb.upper;\n });\n lowerNeedles = needleBounds.map(function (nb) {\n return nb.lower;\n });\n direction = dir;\n nextKeySuffix = dir === \"next\" ? \"\" : suffix;\n }\n initDirection(\"next\");\n\n var c = new whereClause._ctx.collClass(whereClause, function () {\n return IDBKeyRange.bound(upperNeedles[0], lowerNeedles[needlesLen - 1] + suffix);\n });\n\n c._ondirectionchange = function (direction) {\n // This event onlys occur before filter is called the first time.\n initDirection(direction);\n };\n\n var firstPossibleNeedle = 0;\n\n c._addAlgorithm(function (cursor, advance, resolve) {\n /// \n /// \n /// \n var key = cursor.key;\n if (typeof key !== 'string') return false;\n var lowerKey = lower(key);\n if (match(lowerKey, lowerNeedles, firstPossibleNeedle)) {\n return true;\n } else {\n var lowestPossibleCasing = null;\n for (var i = firstPossibleNeedle; i < needlesLen; ++i) {\n var casing = nextCasing(key, lowerKey, upperNeedles[i], lowerNeedles[i], compare, direction);\n if (casing === null && lowestPossibleCasing === null) firstPossibleNeedle = i + 1;else if (lowestPossibleCasing === null || compare(lowestPossibleCasing, casing) > 0) {\n lowestPossibleCasing = casing;\n }\n }\n if (lowestPossibleCasing !== null) {\n advance(function () {\n cursor.continue(lowestPossibleCasing + nextKeySuffix);\n });\n } else {\n advance(resolve);\n }\n return false;\n }\n });\n return c;\n }\n\n //\n // WhereClause public methods\n //\n return {\n between: function (lower, upper, includeLower, includeUpper) {\n /// \n /// Filter out records whose where-field lays between given lower and upper values. Applies to Strings, Numbers and Dates.\n /// \n /// \n /// \n /// Whether items that equals lower should be included. Default true.\n /// Whether items that equals upper should be included. Default false.\n /// \n includeLower = includeLower !== false; // Default to true\n includeUpper = includeUpper === true; // Default to false\n try {\n 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.\n return new this._ctx.collClass(this, function () {\n return IDBKeyRange.bound(lower, upper, !includeLower, !includeUpper);\n });\n } catch (e) {\n return fail(this, INVALID_KEY_ARGUMENT);\n }\n },\n equals: function (value) {\n return new this._ctx.collClass(this, function () {\n return IDBKeyRange.only(value);\n });\n },\n above: function (value) {\n return new this._ctx.collClass(this, function () {\n return IDBKeyRange.lowerBound(value, true);\n });\n },\n aboveOrEqual: function (value) {\n return new this._ctx.collClass(this, function () {\n return IDBKeyRange.lowerBound(value);\n });\n },\n below: function (value) {\n return new this._ctx.collClass(this, function () {\n return IDBKeyRange.upperBound(value, true);\n });\n },\n belowOrEqual: function (value) {\n return new this._ctx.collClass(this, function () {\n return IDBKeyRange.upperBound(value);\n });\n },\n startsWith: function (str) {\n /// \n if (typeof str !== 'string') return fail(this, STRING_EXPECTED);\n return this.between(str, str + maxString, true, true);\n },\n startsWithIgnoreCase: function (str) {\n /// \n if (typeof str !== 'string') return fail(this, STRING_EXPECTED);\n if (str === \"\") return this.startsWith(str);\n return addIgnoreCaseAlgorithm(this, function (x, a) {\n return x.indexOf(a[0]) === 0;\n }, [str], maxString);\n },\n equalsIgnoreCase: function (str) {\n /// \n if (typeof str !== 'string') return fail(this, STRING_EXPECTED);\n return addIgnoreCaseAlgorithm(this, function (x, a) {\n return x === a[0];\n }, [str], \"\");\n },\n anyOfIgnoreCase: function () {\n var set = getSetArgs(arguments);\n if (set.length === 0) return emptyCollection(this);\n if (!set.every(function (s) {\n return typeof s === 'string';\n })) {\n return fail(this, \"anyOfIgnoreCase() only works with strings\");\n }\n return addIgnoreCaseAlgorithm(this, function (x, a) {\n return a.indexOf(x) !== -1;\n }, set, \"\");\n },\n startsWithAnyOfIgnoreCase: function () {\n var set = getSetArgs(arguments);\n if (set.length === 0) return emptyCollection(this);\n if (!set.every(function (s) {\n return typeof s === 'string';\n })) {\n return fail(this, \"startsWithAnyOfIgnoreCase() only works with strings\");\n }\n return addIgnoreCaseAlgorithm(this, function (x, a) {\n return a.some(function (n) {\n return x.indexOf(n) === 0;\n });\n }, set, maxString);\n },\n anyOf: function () {\n var set = getSetArgs(arguments);\n var compare = ascending;\n try {\n set.sort(compare);\n } catch (e) {\n return fail(this, INVALID_KEY_ARGUMENT);\n }\n if (set.length === 0) return emptyCollection(this);\n var c = new this._ctx.collClass(this, function () {\n return IDBKeyRange.bound(set[0], set[set.length - 1]);\n });\n\n c._ondirectionchange = function (direction) {\n compare = direction === \"next\" ? ascending : descending;\n set.sort(compare);\n };\n var i = 0;\n c._addAlgorithm(function (cursor, advance, resolve) {\n var key = cursor.key;\n while (compare(key, set[i]) > 0) {\n // The cursor has passed beyond this key. Check next.\n ++i;\n if (i === set.length) {\n // There is no next. Stop searching.\n advance(resolve);\n return false;\n }\n }\n if (compare(key, set[i]) === 0) {\n // 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.\n return true;\n } else {\n // cursor.key not yet at set[i]. Forward cursor to the next key to hunt for.\n advance(function () {\n cursor.continue(set[i]);\n });\n return false;\n }\n });\n return c;\n },\n\n notEqual: function (value) {\n return this.inAnyRange([[-Infinity, value], [value, maxKey]], { includeLowers: false, includeUppers: false });\n },\n\n noneOf: function () {\n var set = getSetArgs(arguments);\n if (set.length === 0) return new this._ctx.collClass(this); // Return entire collection.\n try {\n set.sort(ascending);\n } catch (e) {\n return fail(this, INVALID_KEY_ARGUMENT);\n }\n // Transform [\"a\",\"b\",\"c\"] to a set of ranges for between/above/below: [[-Infinity,\"a\"], [\"a\",\"b\"], [\"b\",\"c\"], [\"c\",maxKey]]\n var ranges = set.reduce(function (res, val) {\n return res ? res.concat([[res[res.length - 1][1], val]]) : [[-Infinity, val]];\n }, null);\n ranges.push([set[set.length - 1], maxKey]);\n return this.inAnyRange(ranges, { includeLowers: false, includeUppers: false });\n },\n\n /** Filter out values withing given set of ranges.\r\n * Example, give children and elders a rebate of 50%:\r\n *\r\n * db.friends.where('age').inAnyRange([[0,18],[65,Infinity]]).modify({Rebate: 1/2});\r\n *\r\n * @param {(string|number|Date|Array)[][]} ranges\r\n * @param {{includeLowers: boolean, includeUppers: boolean}} options\r\n */\n inAnyRange: function (ranges, options) {\n var ctx = this._ctx;\n if (ranges.length === 0) return emptyCollection(this);\n if (!ranges.every(function (range) {\n return range[0] !== undefined && range[1] !== undefined && ascending(range[0], range[1]) <= 0;\n })) {\n 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);\n }\n var includeLowers = !options || options.includeLowers !== false; // Default to true\n var includeUppers = options && options.includeUppers === true; // Default to false\n\n function addRange(ranges, newRange) {\n for (var i = 0, l = ranges.length; i < l; ++i) {\n var range = ranges[i];\n if (cmp(newRange[0], range[1]) < 0 && cmp(newRange[1], range[0]) > 0) {\n range[0] = min(range[0], newRange[0]);\n range[1] = max(range[1], newRange[1]);\n break;\n }\n }\n if (i === l) ranges.push(newRange);\n return ranges;\n }\n\n var sortDirection = ascending;\n function rangeSorter(a, b) {\n return sortDirection(a[0], b[0]);\n }\n\n // Join overlapping ranges\n var set;\n try {\n set = ranges.reduce(addRange, []);\n set.sort(rangeSorter);\n } catch (ex) {\n return fail(this, INVALID_KEY_ARGUMENT);\n }\n\n var i = 0;\n var keyIsBeyondCurrentEntry = includeUppers ? function (key) {\n return ascending(key, set[i][1]) > 0;\n } : function (key) {\n return ascending(key, set[i][1]) >= 0;\n };\n\n var keyIsBeforeCurrentEntry = includeLowers ? function (key) {\n return descending(key, set[i][0]) > 0;\n } : function (key) {\n return descending(key, set[i][0]) >= 0;\n };\n\n function keyWithinCurrentRange(key) {\n return !keyIsBeyondCurrentEntry(key) && !keyIsBeforeCurrentEntry(key);\n }\n\n var checkKey = keyIsBeyondCurrentEntry;\n\n var c = new ctx.collClass(this, function () {\n return IDBKeyRange.bound(set[0][0], set[set.length - 1][1], !includeLowers, !includeUppers);\n });\n\n c._ondirectionchange = function (direction) {\n if (direction === \"next\") {\n checkKey = keyIsBeyondCurrentEntry;\n sortDirection = ascending;\n } else {\n checkKey = keyIsBeforeCurrentEntry;\n sortDirection = descending;\n }\n set.sort(rangeSorter);\n };\n\n c._addAlgorithm(function (cursor, advance, resolve) {\n var key = cursor.key;\n while (checkKey(key)) {\n // The cursor has passed beyond this key. Check next.\n ++i;\n if (i === set.length) {\n // There is no next. Stop searching.\n advance(resolve);\n return false;\n }\n }\n if (keyWithinCurrentRange(key)) {\n // 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.\n return true;\n } else if (cmp(key, set[i][1]) === 0 || cmp(key, set[i][0]) === 0) {\n // includeUpper or includeLower is false so keyWithinCurrentRange() returns false even though we are at range border.\n // Continue to next key but don't include this one.\n return false;\n } else {\n // cursor.key not yet at set[i]. Forward cursor to the next key to hunt for.\n advance(function () {\n if (sortDirection === ascending) cursor.continue(set[i][0]);else cursor.continue(set[i][1]);\n });\n return false;\n }\n });\n return c;\n },\n startsWithAnyOf: function () {\n var set = getSetArgs(arguments);\n\n if (!set.every(function (s) {\n return typeof s === 'string';\n })) {\n return fail(this, \"startsWithAnyOf() only works with strings\");\n }\n if (set.length === 0) return emptyCollection(this);\n\n return this.inAnyRange(set.map(function (str) {\n return [str, str + maxString];\n }));\n }\n };\n });\n\n //\n //\n //\n // Collection Class\n //\n //\n //\n function Collection(whereClause, keyRangeGenerator) {\n /// \n ///\n /// \n /// Where clause instance\n /// \n var keyRange = null,\n error = null;\n if (keyRangeGenerator) try {\n keyRange = keyRangeGenerator();\n } catch (ex) {\n error = stack(mapError(ex));\n }\n\n var whereCtx = whereClause._ctx,\n table = whereCtx.table;\n this._ctx = {\n table: table,\n index: whereCtx.index,\n isPrimKey: !whereCtx.index || table.schema.primKey.keyPath && whereCtx.index === table.schema.primKey.name,\n range: keyRange,\n keysOnly: false,\n dir: \"next\",\n unique: \"\",\n algorithm: null,\n filter: null,\n replayFilter: null,\n isMatch: null,\n offset: 0,\n limit: Infinity,\n error: error, // If set, any promise must be rejected with this error\n or: whereCtx.or,\n valueFilter: table.hook.reading.fire\n };\n }\n\n extendProto(Collection.prototype, function () {\n\n //\n // Collection Private Functions\n //\n\n function addFilter(ctx, fn) {\n ctx.filter = combine(ctx.filter, fn);\n }\n\n function addReplayFilter(ctx, factory) {\n var curr = ctx.replayFilter;\n ctx.replayFilter = curr ? function () {\n return combine(curr(), factory());\n } : factory;\n }\n\n function addMatchFilter(ctx, fn) {\n ctx.isMatch = combine(ctx.isMatch, fn);\n }\n\n function getIndexOrStore(ctx, store) {\n if (ctx.isPrimKey) return store;\n var indexSpec = ctx.table.schema.idxByName[ctx.index];\n if (!indexSpec) throw new exceptions.Schema(\"KeyPath \" + ctx.index + \" on object store \" + store.name + \" is not indexed\");\n return store.index(indexSpec.name);\n }\n\n function openCursor(ctx, store) {\n var idxOrStore = getIndexOrStore(ctx, store);\n return ctx.keysOnly && 'openKeyCursor' in idxOrStore ? idxOrStore.openKeyCursor(ctx.range || null, ctx.dir + ctx.unique) : idxOrStore.openCursor(ctx.range || null, ctx.dir + ctx.unique);\n }\n\n function iter(ctx, fn, resolve, reject, idbstore) {\n var filter = ctx.replayFilter ? combine(ctx.filter, ctx.replayFilter()) : ctx.filter;\n if (!ctx.or) {\n iterate(openCursor(ctx, idbstore), combine(ctx.algorithm, filter), fn, resolve, reject, !ctx.keysOnly && ctx.valueFilter);\n } else {\n (function () {\n var set = {};\n var resolved = 0;\n\n function resolveboth() {\n if (++resolved === 2) resolve(); // Seems like we just support or btwn max 2 expressions, but there are no limit because we do recursion.\n }\n\n function union(item, cursor, advance) {\n if (!filter || filter(cursor, advance, resolveboth, reject)) {\n var key = cursor.primaryKey.toString(); // Converts any Date to String, String to String, Number to String and Array to comma-separated string\n if (!set.hasOwnProperty(key)) {\n set[key] = true;\n fn(item, cursor, advance);\n }\n }\n }\n\n ctx.or._iterate(union, resolveboth, reject, idbstore);\n iterate(openCursor(ctx, idbstore), ctx.algorithm, union, resolveboth, reject, !ctx.keysOnly && ctx.valueFilter);\n })();\n }\n }\n function getInstanceTemplate(ctx) {\n return ctx.table.schema.instanceTemplate;\n }\n\n return {\n\n //\n // Collection Protected Functions\n //\n\n _read: function (fn, cb) {\n var ctx = this._ctx;\n if (ctx.error) return ctx.table._trans(null, function rejector(resolve, reject) {\n reject(ctx.error);\n });else return ctx.table._idbstore(READONLY, fn).then(cb);\n },\n _write: function (fn) {\n var ctx = this._ctx;\n if (ctx.error) return ctx.table._trans(null, function rejector(resolve, reject) {\n reject(ctx.error);\n });else return ctx.table._idbstore(READWRITE, fn, \"locked\"); // When doing write operations on collections, always lock the operation so that upcoming operations gets queued.\n },\n _addAlgorithm: function (fn) {\n var ctx = this._ctx;\n ctx.algorithm = combine(ctx.algorithm, fn);\n },\n\n _iterate: function (fn, resolve, reject, idbstore) {\n return iter(this._ctx, fn, resolve, reject, idbstore);\n },\n\n clone: function (props) {\n var rv = Object.create(this.constructor.prototype),\n ctx = Object.create(this._ctx);\n if (props) extend(ctx, props);\n rv._ctx = ctx;\n return rv;\n },\n\n raw: function () {\n this._ctx.valueFilter = null;\n return this;\n },\n\n //\n // Collection Public methods\n //\n\n each: function (fn) {\n var ctx = this._ctx;\n\n fake && fn(getInstanceTemplate(ctx));\n\n return this._read(function (resolve, reject, idbstore) {\n iter(ctx, fn, resolve, reject, idbstore);\n });\n },\n\n count: function (cb) {\n if (fake) return Promise.resolve(0).then(cb);\n var self = this,\n ctx = this._ctx;\n\n if (ctx.filter || ctx.algorithm || ctx.or || ctx.replayFilter) {\n // When filters are applied or 'ored' collections are used, we must count manually\n var count = 0;\n return this._read(function (resolve, reject, idbstore) {\n iter(ctx, function () {\n ++count;return false;\n }, function () {\n resolve(count);\n }, reject, idbstore);\n }, cb);\n } else {\n // Otherwise, we can use the count() method if the index.\n return this._read(function (resolve, reject, idbstore) {\n var idx = getIndexOrStore(ctx, idbstore);\n var req = ctx.range ? idx.count(ctx.range) : idx.count();\n req.onerror = eventRejectHandler(reject, [\"calling\", \"count()\", \"on\", self.name]);\n req.onsuccess = function (e) {\n resolve(e.target.result);\n };\n }, cb);\n }\n },\n\n sortBy: function (keyPath, cb) {\n /// \n var parts = keyPath.split('.').reverse(),\n lastPart = parts[0],\n lastIndex = parts.length - 1;\n function getval(obj, i) {\n if (i) return getval(obj[parts[i]], i - 1);\n return obj[lastPart];\n }\n var order = this._ctx.dir === \"next\" ? 1 : -1;\n\n function sorter(a, b) {\n var aVal = getval(a, lastIndex),\n bVal = getval(b, lastIndex);\n return aVal < bVal ? -order : aVal > bVal ? order : 0;\n }\n return this.toArray(function (a) {\n return a.sort(sorter);\n }).then(cb);\n },\n\n toArray: function (cb) {\n var ctx = this._ctx;\n return this._read(function (resolve, reject, idbstore) {\n fake && resolve([getInstanceTemplate(ctx)]);\n var a = [];\n iter(ctx, function (item) {\n a.push(item);\n }, function arrayComplete() {\n resolve(a);\n }, reject, idbstore);\n }, cb);\n },\n\n offset: function (offset) {\n var ctx = this._ctx;\n if (offset <= 0) return this;\n ctx.offset += offset; // For count()\n if (!ctx.or && !ctx.algorithm && !ctx.filter && !ctx.replayFilter) {\n addReplayFilter(ctx, function () {\n var offsetLeft = offset;\n return function (cursor, advance) {\n if (offsetLeft === 0) return true;\n if (offsetLeft === 1) {\n --offsetLeft;return false;\n }\n advance(function () {\n cursor.advance(offsetLeft);\n offsetLeft = 0;\n });\n return false;\n };\n });\n } else {\n addReplayFilter(ctx, function () {\n var offsetLeft = offset;\n return function () {\n return --offsetLeft < 0;\n };\n });\n }\n return this;\n },\n\n limit: function (numRows) {\n this._ctx.limit = Math.min(this._ctx.limit, numRows); // For count()\n addReplayFilter(this._ctx, function () {\n var rowsLeft = numRows;\n return function (cursor, advance, resolve) {\n if (--rowsLeft <= 0) advance(resolve); // Stop after this item has been included\n return rowsLeft >= 0; // If numRows is already below 0, return false because then 0 was passed to numRows initially. Otherwise we wouldnt come here.\n };\n });\n return this;\n },\n\n until: function (filterFunction, bIncludeStopEntry) {\n var ctx = this._ctx;\n fake && filterFunction(getInstanceTemplate(ctx));\n addFilter(this._ctx, function (cursor, advance, resolve) {\n if (filterFunction(cursor.value)) {\n advance(resolve);\n return bIncludeStopEntry;\n } else {\n return true;\n }\n });\n return this;\n },\n\n first: function (cb) {\n return this.limit(1).toArray(function (a) {\n return a[0];\n }).then(cb);\n },\n\n last: function (cb) {\n return this.reverse().first(cb);\n },\n\n filter: function (filterFunction) {\n /// function(val){return true/false}\n fake && filterFunction(getInstanceTemplate(this._ctx));\n addFilter(this._ctx, function (cursor) {\n return filterFunction(cursor.value);\n });\n addMatchFilter(this._ctx, filterFunction); // match filters not used in Dexie.js but can be used by 3rd part libraries to test a collection for a match without querying DB. Used by Dexie.Observable.\n return this;\n },\n\n and: function (filterFunction) {\n return this.filter(filterFunction);\n },\n\n or: function (indexName) {\n return new WhereClause(this._ctx.table, indexName, this);\n },\n\n reverse: function () {\n this._ctx.dir = this._ctx.dir === \"prev\" ? \"next\" : \"prev\";\n if (this._ondirectionchange) this._ondirectionchange(this._ctx.dir);\n return this;\n },\n\n desc: function () {\n return this.reverse();\n },\n\n eachKey: function (cb) {\n var ctx = this._ctx;\n fake && cb(getByKeyPath(getInstanceTemplate(this._ctx), this._ctx.index ? this._ctx.table.schema.idxByName[this._ctx.index].keyPath : this._ctx.table.schema.primKey.keyPath));\n ctx.keysOnly = !ctx.isMatch;\n return this.each(function (val, cursor) {\n cb(cursor.key, cursor);\n });\n },\n\n eachUniqueKey: function (cb) {\n this._ctx.unique = \"unique\";\n return this.eachKey(cb);\n },\n\n keys: function (cb) {\n var ctx = this._ctx;\n ctx.keysOnly = !ctx.isMatch;\n var a = [];\n if (fake) return new Promise(this.eachKey.bind(this)).then(function (x) {\n return [x];\n }).then(cb);\n return this.each(function (item, cursor) {\n a.push(cursor.key);\n }).then(function () {\n return a;\n }).then(cb);\n },\n\n uniqueKeys: function (cb) {\n this._ctx.unique = \"unique\";\n return this.keys(cb);\n },\n\n firstKey: function (cb) {\n return this.limit(1).keys(function (a) {\n return a[0];\n }).then(cb);\n },\n\n lastKey: function (cb) {\n return this.reverse().firstKey(cb);\n },\n\n distinct: function () {\n var ctx = this._ctx,\n idx = ctx.index && ctx.table.schema.idxByName[ctx.index];\n if (!idx || !idx.multi) return this; // distinct() only makes differencies on multiEntry indexes.\n var set = {};\n addFilter(this._ctx, function (cursor) {\n var strKey = cursor.primaryKey.toString(); // Converts any Date to String, String to String, Number to String and Array to comma-separated string\n var found = set.hasOwnProperty(strKey);\n set[strKey] = true;\n return !found;\n });\n return this;\n }\n };\n });\n\n //\n //\n // WriteableCollection Class\n //\n //\n function WriteableCollection() {\n Collection.apply(this, arguments);\n }\n\n derive(WriteableCollection).from(Collection).extend({\n\n //\n // WriteableCollection Public Methods\n //\n\n modify: function (changes) {\n var self = this,\n ctx = this._ctx,\n hook = ctx.table.hook,\n updatingHook = hook.updating.fire,\n deletingHook = hook.deleting.fire;\n\n fake && typeof changes === 'function' && changes.call({ value: ctx.table.schema.instanceTemplate }, ctx.table.schema.instanceTemplate);\n\n return this._write(function (resolve, reject, idbstore, trans) {\n var modifyer;\n if (typeof changes === 'function') {\n // Changes is a function that may update, add or delete propterties or even require a deletion the object itself (delete this.item)\n if (updatingHook === nop && deletingHook === nop) {\n // Noone cares about what is being changed. Just let the modifier function be the given argument as is.\n modifyer = changes;\n } else {\n // People want to know exactly what is being modified or deleted.\n // Let modifyer be a proxy function that finds out what changes the caller is actually doing\n // and call the hooks accordingly!\n modifyer = function (item) {\n var origItem = deepClone(item); // Clone the item first so we can compare laters.\n 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)\n if (!this.hasOwnProperty(\"value\")) {\n // The real modifyer function requests a deletion of the object. Inform the deletingHook that a deletion is taking place.\n deletingHook.call(this, this.primKey, item, trans);\n } else {\n // No deletion. Check what was changed\n var objectDiff = getObjectDiff(origItem, this.value);\n var additionalChanges = updatingHook.call(this, objectDiff, this.primKey, origItem, trans);\n if (additionalChanges) {\n // Hook want to apply additional modifications. Make sure to fullfill the will of the hook.\n item = this.value;\n keys(additionalChanges).forEach(function (keyPath) {\n setByKeyPath(item, keyPath, additionalChanges[keyPath]); // Adding {keyPath: undefined} means that the keyPath should be deleted. Handled by setByKeyPath\n });\n }\n }\n };\n }\n } else if (updatingHook === nop) {\n // changes is a set of {keyPath: value} and no one is listening to the updating hook.\n var keyPaths = keys(changes);\n var numKeys = keyPaths.length;\n modifyer = function (item) {\n var anythingModified = false;\n for (var i = 0; i < numKeys; ++i) {\n var keyPath = keyPaths[i],\n val = changes[keyPath];\n if (getByKeyPath(item, keyPath) !== val) {\n setByKeyPath(item, keyPath, val); // Adding {keyPath: undefined} means that the keyPath should be deleted. Handled by setByKeyPath\n anythingModified = true;\n }\n }\n return anythingModified;\n };\n } else {\n // changes is a set of {keyPath: value} and people are listening to the updating hook so we need to call it and\n // allow it to add additional modifications to make.\n var origChanges = changes;\n 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.\n modifyer = function (item) {\n var anythingModified = false;\n var additionalChanges = updatingHook.call(this, changes, this.primKey, deepClone(item), trans);\n if (additionalChanges) extend(changes, additionalChanges);\n keys(changes).forEach(function (keyPath) {\n var val = changes[keyPath];\n if (getByKeyPath(item, keyPath) !== val) {\n setByKeyPath(item, keyPath, val);\n anythingModified = true;\n }\n });\n if (additionalChanges) changes = shallowClone(origChanges); // Restore original changes for next iteration\n return anythingModified;\n };\n }\n\n var count = 0;\n var successCount = 0;\n var iterationComplete = false;\n var failures = [];\n var failKeys = [];\n var currentKey = null;\n\n function modifyItem(item, cursor) {\n currentKey = cursor.primaryKey;\n var thisContext = {\n primKey: cursor.primaryKey,\n value: item,\n onsuccess: null,\n onerror: null\n };\n\n function onerror(e) {\n failures.push(e);\n failKeys.push(thisContext.primKey);\n if (thisContext.onerror) Promise.newPSD(function () {\n Promise.PSD.trans = trans;\n thisContext.onerror(e);\n });\n checkFinished();\n return true; // Catch these errors and let a final rejection decide whether or not to abort entire transaction\n }\n\n if (modifyer.call(thisContext, item, thisContext) !== false) {\n // If a callback explicitely returns false, do not perform the update!\n var bDelete = !thisContext.hasOwnProperty(\"value\");\n ++count;\n miniTryCatch(function () {\n var req = bDelete ? cursor.delete() : cursor.update(thisContext.value);\n req.onerror = eventRejectHandler(onerror, bDelete ? [\"deleting\", item, \"from\", ctx.table.name] : [\"modifying\", item, \"on\", ctx.table.name]);\n req.onsuccess = function () {\n if (thisContext.onsuccess) Promise.newPSD(function () {\n Promise.PSD.trans = trans;\n thisContext.onsuccess(thisContext.value);\n });\n ++successCount;\n checkFinished();\n };\n }, onerror);\n } else if (thisContext.onsuccess) {\n // Hook will expect either onerror or onsuccess to always be called!\n thisContext.onsuccess(thisContext.value);\n }\n }\n\n function doReject(e) {\n if (e) {\n failures.push(e);\n failKeys.push(currentKey);\n }\n return reject(new ModifyError(\"Error modifying one or more objects\", failures, successCount, failKeys));\n }\n\n function checkFinished() {\n if (iterationComplete && successCount + failures.length === count) {\n if (failures.length > 0) doReject();else resolve(successCount);\n }\n }\n self.clone().raw()._iterate(modifyItem, function () {\n iterationComplete = true;\n checkFinished();\n }, doReject, idbstore);\n });\n },\n\n 'delete': function () {\n var _this2 = this;\n\n var ctx = this._ctx,\n range = ctx.range,\n deletingHook = ctx.table.hook.deleting.fire,\n hasDeleteHook = deletingHook !== nop;\n if (!hasDeleteHook && !ctx.or && !ctx.algorithm && !ctx.filter && !ctx.replayFilter && (ctx.isPrimKey && !hangsOnDeleteLargeKeyRange || !range)) // if no range, we'll use clear().\n {\n // May use IDBObjectStore.delete(IDBKeyRange) in this case (Issue #208)\n // For chromium, this is the way most optimized version.\n // For IE/Edge, this could hang the indexedDB engine and make operating system instable\n // (https://gist.github.com/dfahlander/5a39328f029de18222cf2125d56c38f7)\n return this._write(function (resolve, reject, idbstore) {\n // Our API contract is to return a count of deleted items, so we have to count() before delete().\n var onerror = eventRejectHandler(reject, [\"deleting range from\", ctx.table.name]),\n countReq = range ? idbstore.count(range) : idbstore.count();\n countReq.onerror = onerror;\n countReq.onsuccess = function () {\n var count = countReq.result;\n miniTryCatch(function () {\n var delReq = range ? idbstore.delete(range) : idbstore.clear();\n delReq.onerror = onerror;\n delReq.onsuccess = function () {\n return resolve(count);\n };\n }, function (err) {\n return reject(mapError(err));\n });\n };\n });\n }\n\n // Default version to use when collection is not a vanilla IDBKeyRange on the primary key.\n // Divide into chunks to not starve RAM.\n // If has delete hook, we will have to collect not just keys but also objects, so it will use\n // more memory and need lower chunk size.\n var CHUNKSIZE = hasDeleteHook ? 2000 : 10000;\n\n return this._write(function (resolve, reject, idbstore, trans) {\n var totalCount = 0;\n // Clone table and change the way transaction promises are generated.\n // This is to be able to call other Collection methods within the same\n // transaction even if the caller calls us without a transaction.\n var table = Object.create(ctx.table);\n table._tpf = trans._tpf; // Enable us to keep same transaction even if called without transaction.\n // Clone collection and change its table and set a limit of CHUNKSIZE on the cloned Collection instance.\n var collection = _this2.clone({\n table: table, // Execute in same transaction\n keysOnly: !ctx.isMatch && !hasDeleteHook }) // load just keys (unless filter() or and() or deleteHook has subscribers)\n .distinct() // In case multiEntry is used, never delete same key twice because resulting count\n // would become larger than actual delete count.\n .limit(CHUNKSIZE).raw(); // Don't filter through reading-hooks (like mapped classes etc)\n\n var keysOrTuples = [];\n\n // We're gonna do things on as many chunks that are needed.\n // Use recursion of nextChunk function:\n var nextChunk = function () {\n return collection.each(hasDeleteHook ? function (val, cursor) {\n // Somebody subscribes to hook('deleting'). Collect all primary keys and their values,\n // so that the hook can be called with its values in bulkDelete().\n keysOrTuples.push([cursor.primaryKey, cursor.value]);\n } : function (val, cursor) {\n // No one subscribes to hook('deleting'). Collect only primary keys:\n keysOrTuples.push(cursor.primaryKey);\n }).then(function () {\n // Chromium deletes faster when doing it in sort order.\n hasDeleteHook ? keysOrTuples.sort(function (a, b) {\n return ascending(a[0], b[0]);\n }) : keysOrTuples.sort(ascending);\n return bulkDelete(idbstore, trans, keysOrTuples, hasDeleteHook, deletingHook);\n }).then(function () {\n var count = keysOrTuples.length;\n totalCount += count;\n keysOrTuples = [];\n return count < CHUNKSIZE ? totalCount : nextChunk();\n });\n };\n\n resolve(nextChunk());\n });\n }\n });\n\n //\n //\n //\n // ------------------------- Help functions ---------------------------\n //\n //\n //\n\n function lowerVersionFirst(a, b) {\n return a._cfg.version - b._cfg.version;\n }\n\n function setApiOnPlace(objs, transactionPromiseFactory, tableNames, mode, dbschema, enableProhibitedDB) {\n tableNames.forEach(function (tableName) {\n var tableInstance = db._tableFactory(mode, dbschema[tableName], transactionPromiseFactory);\n objs.forEach(function (obj) {\n if (!obj[tableName]) {\n if (enableProhibitedDB) {\n setProp(obj, tableName, {\n get: function () {\n var currentTrans = Promise.PSD && Promise.PSD.trans;\n if (currentTrans && currentTrans.db === db) {\n return currentTrans.tables[tableName];\n }\n return tableInstance;\n }\n }, { enumerable: true });\n } else {\n obj[tableName] = tableInstance;\n }\n }\n });\n });\n }\n\n function removeTablesApi(objs) {\n objs.forEach(function (obj) {\n for (var key in obj) {\n if (obj[key] instanceof Table) delete obj[key];\n }\n });\n }\n\n function iterate(req, filter, fn, resolve, reject, valueFilter) {\n valueFilter = valueFilter || mirror;\n if (!req.onerror) req.onerror = eventRejectHandler(reject);\n if (filter) {\n req.onsuccess = trycatch(function filter_record() {\n var cursor = req.result;\n if (cursor) {\n var c = function () {\n cursor.continue();\n };\n if (filter(cursor, function (advancer) {\n c = advancer;\n }, resolve, reject)) fn(valueFilter(cursor.value), cursor, function (advancer) {\n c = advancer;\n });\n c();\n } else {\n resolve();\n }\n }, reject);\n } else {\n req.onsuccess = trycatch(function filter_record() {\n var cursor = req.result;\n if (cursor) {\n var c = function () {\n cursor.continue();\n };\n fn(valueFilter(cursor.value), cursor, function (advancer) {\n c = advancer;\n });\n c();\n } else {\n resolve();\n }\n }, reject);\n }\n }\n\n function parseIndexSyntax(indexes) {\n /// \n /// \n var rv = [];\n indexes.split(',').forEach(function (index) {\n index = index.trim();\n var name = index.replace(\"&\", \"\").replace(\"++\", \"\").replace(\"*\", \"\");\n var keyPath = name.indexOf('[') !== 0 ? name : index.substring(index.indexOf('[') + 1, index.indexOf(']')).split('+');\n\n rv.push(new IndexSpec(name, keyPath || null, index.indexOf('&') !== -1, index.indexOf('*') !== -1, index.indexOf(\"++\") !== -1, isArray(keyPath), keyPath.indexOf('.') !== -1));\n });\n return rv;\n }\n\n function cmp(key1, key2) {\n return indexedDB.cmp(key1, key2);\n }\n\n function min(a, b) {\n return cmp(a, b) < 0 ? a : b;\n }\n\n function max(a, b) {\n return cmp(a, b) > 0 ? a : b;\n }\n\n function ascending(a, b) {\n return indexedDB.cmp(a, b);\n }\n\n function descending(a, b) {\n return indexedDB.cmp(b, a);\n }\n\n function simpleCompare(a, b) {\n return a < b ? -1 : a === b ? 0 : 1;\n }\n\n function simpleCompareReverse(a, b) {\n return a > b ? -1 : a === b ? 0 : 1;\n }\n\n function combine(filter1, filter2) {\n return filter1 ? filter2 ? function () {\n return filter1.apply(this, arguments) && filter2.apply(this, arguments);\n } : filter1 : filter2;\n }\n\n function readGlobalSchema() {\n db.verno = idbdb.version / 10;\n db._dbSchema = globalSchema = {};\n dbStoreNames = slice(idbdb.objectStoreNames, 0);\n if (dbStoreNames.length === 0) return; // Database contains no stores.\n var trans = idbdb.transaction(safariMultiStoreFix(dbStoreNames), 'readonly');\n dbStoreNames.forEach(function (storeName) {\n var store = trans.objectStore(storeName),\n keyPath = store.keyPath,\n dotted = keyPath && typeof keyPath === 'string' && keyPath.indexOf('.') !== -1;\n var primKey = new IndexSpec(keyPath, keyPath || \"\", false, false, !!store.autoIncrement, keyPath && typeof keyPath !== 'string', dotted);\n var indexes = [];\n for (var j = 0; j < store.indexNames.length; ++j) {\n var idbindex = store.index(store.indexNames[j]);\n keyPath = idbindex.keyPath;\n dotted = keyPath && typeof keyPath === 'string' && keyPath.indexOf('.') !== -1;\n var index = new IndexSpec(idbindex.name, keyPath, !!idbindex.unique, !!idbindex.multiEntry, false, keyPath && typeof keyPath !== 'string', dotted);\n indexes.push(index);\n }\n globalSchema[storeName] = new TableSchema(storeName, primKey, indexes, {});\n });\n setApiOnPlace([allTables], db._transPromiseFactory, keys(globalSchema), READWRITE, globalSchema);\n }\n\n function adjustToExistingIndexNames(schema, idbtrans) {\n /// \n /// Issue #30 Problem with existing db - adjust to existing index names when migrating from non-dexie db\n /// \n /// Map between name and TableSchema\n /// \n var storeNames = idbtrans.db.objectStoreNames;\n for (var i = 0; i < storeNames.length; ++i) {\n var storeName = storeNames[i];\n var store = idbtrans.objectStore(storeName);\n for (var j = 0; j < store.indexNames.length; ++j) {\n var indexName = store.indexNames[j];\n var keyPath = store.index(indexName).keyPath;\n var dexieName = typeof keyPath === 'string' ? keyPath : \"[\" + slice(keyPath).join('+') + \"]\";\n if (schema[storeName]) {\n var indexSpec = schema[storeName].idxByName[dexieName];\n if (indexSpec) indexSpec.name = indexName;\n }\n }\n }\n }\n\n function fireOnBlocked(ev) {\n db.on(\"blocked\").fire(ev);\n // Workaround (not fully*) for missing \"versionchange\" event in IE,Edge and Safari:\n connections.filter(function (c) {\n return c.name === db.name && c !== db && !c._vcFired;\n }).map(function (c) {\n return c.on(\"versionchange\").fire(ev);\n });\n }\n\n extend(this, {\n Collection: Collection,\n Table: Table,\n Transaction: Transaction,\n Version: Version,\n WhereClause: WhereClause,\n WriteableCollection: WriteableCollection,\n WriteableTable: WriteableTable\n });\n\n init();\n\n addons.forEach(function (fn) {\n fn(db);\n });\n}\n\nvar fakeAutoComplete = function () {}; // Will never be changed. We just fake for the IDE that we change it (see doFakeAutoComplete())\nvar fake = false; // Will never be changed. We just fake for the IDE that we change it (see doFakeAutoComplete())\n\nfunction trycatch(fn, reject) {\n var psd = Promise.PSD;\n return function () {\n var outerPSD = Promise.PSD; // Support Promise-specific data (PSD) in callback calls\n Promise.PSD = psd;\n try {\n fn.apply(this, arguments);\n } catch (e) {\n reject(e);\n } finally {\n Promise.PSD = outerPSD;\n }\n };\n}\n\nfunction parseType(type) {\n if (typeof type === 'function') {\n return new type();\n } else if (isArray(type)) {\n return [parseType(type[0])];\n } else if (type && typeof type === 'object') {\n var rv = {};\n applyStructure(rv, type);\n return rv;\n } else {\n return type;\n }\n}\n\nfunction applyStructure(obj, structure) {\n keys(structure).forEach(function (member) {\n var value = parseType(structure[member]);\n obj[member] = value;\n });\n return obj;\n}\n\nfunction eventRejectHandler(reject, sentance) {\n return function (event) {\n var errObj = event && event.target.error || new Error(\"\");\n if (sentance) {\n var occurredWhen = \" occurred when \" + sentance.map(function (word) {\n switch (typeof word) {\n case 'function':\n return word();\n case 'string':\n return word;\n default:\n return JSON.stringify(word);\n }\n }).join(\" \");\n if (errObj.message && errObj.message != errObj.name) occurredWhen += \". \" + errObj.message;\n if (errObj.name) {\n errObj = mapError(errObj, errObj.name + occurredWhen);\n } else {\n // Non-standard exceptions from IndexedDBPolyfill\n errObj = errObj + occurredWhen;\n }\n }\n reject(errObj);\n\n if (event) {\n // Old versions of IndexedDBShim doesnt provide an error event\n // Stop error from propagating to IDBTransaction. Let us handle that manually instead.\n if (event.stopPropagation) // IndexedDBShim doesnt support this\n event.stopPropagation();\n if (event.preventDefault) // IndexedDBShim doesnt support this\n event.preventDefault();\n }\n\n return false;\n };\n}\n\nfunction preventDefault(e) {\n e.preventDefault();\n}\n\nfunction globalDatabaseList(cb) {\n var val,\n localStorage = Dexie.dependencies.localStorage;\n if (!localStorage) return cb([]); // Envs without localStorage support\n try {\n val = JSON.parse(localStorage.getItem('Dexie.DatabaseNames') || \"[]\");\n } catch (e) {\n val = [];\n }\n if (cb(val)) {\n localStorage.setItem('Dexie.DatabaseNames', JSON.stringify(val));\n }\n}\n\nfunction awaitIterable(iterable) {\n var callNext = function (result) {\n return iterable.next(result);\n },\n doThrow = function (error) {\n return iterable.throw(error);\n },\n onSuccess = step(callNext),\n onError = step(doThrow);\n\n function step(getNext) {\n return function (val) {\n var next = getNext(val),\n value = next.value;\n\n return next.done ? value : !value || typeof value.then !== 'function' ? Array.isArray(value) ? awaitAll(value, 0) : onSuccess(value) : value.then(onSuccess, onError);\n };\n }\n\n function awaitAll(values, i) {\n if (i === values.length) return onSuccess(values);\n var value = values[i];\n return value.constructor && typeof value.constructor.all == 'function' ? value.constructor.all(values).then(onSuccess, onError) : awaitAll(values, i + 1);\n }\n\n return step(callNext)();\n}\n\n//\n// IndexSpec struct\n//\nfunction IndexSpec(name, keyPath, unique, multi, auto, compound, dotted) {\n /// \n /// \n /// \n /// \n /// \n /// \n /// \n this.name = name;\n this.keyPath = keyPath;\n this.unique = unique;\n this.multi = multi;\n this.auto = auto;\n this.compound = compound;\n this.dotted = dotted;\n var keyPathSrc = typeof keyPath === 'string' ? keyPath : keyPath && '[' + [].join.call(keyPath, '+') + ']';\n this.src = (unique ? '&' : '') + (multi ? '*' : '') + (auto ? \"++\" : \"\") + keyPathSrc;\n}\n\n//\n// TableSchema struct\n//\nfunction TableSchema(name, primKey, indexes, instanceTemplate) {\n /// \n /// \n /// \n /// \n this.name = name;\n this.primKey = primKey || new IndexSpec();\n this.indexes = indexes || [new IndexSpec()];\n this.instanceTemplate = instanceTemplate;\n this.mappedClass = null;\n this.idxByName = indexes.reduce(function (hashSet, index) {\n hashSet[index.name] = index;\n return hashSet;\n }, {});\n}\n\n//\n// Static delete() method.\n//\nDexie.delete = function (databaseName) {\n var db = new Dexie(databaseName),\n promise = db.delete();\n promise.onblocked = function (fn) {\n db.on(\"blocked\", fn);\n return this;\n };\n return promise;\n};\n\n//\n// Static exists() method.\n//\nDexie.exists = function (name) {\n return new Dexie(name).open().then(function (db) {\n db.close();\n return true;\n }).catch(Dexie.NoSuchDatabaseError, function () {\n return false;\n });\n};\n\n//\n// Static method for retrieving a list of all existing databases at current host.\n//\nDexie.getDatabaseNames = function (cb) {\n return new Promise(function (resolve, reject) {\n var getDatabaseNames = getNativeGetDatabaseNamesFn(indexedDB);\n if (getDatabaseNames) {\n // In case getDatabaseNames() becomes standard, let's prepare to support it:\n var req = getDatabaseNames();\n req.onsuccess = function (event) {\n resolve(slice(event.target.result, 0)); // Converst DOMStringList to Array\n };\n req.onerror = eventRejectHandler(reject);\n } else {\n globalDatabaseList(function (val) {\n resolve(val);\n return false;\n });\n }\n }).then(cb);\n};\n\nDexie.defineClass = function (structure) {\n /// \n /// Create a javascript constructor based on given template for which properties to expect in the class.\n /// Any property that is a constructor function will act as a type. So {name: String} will be equal to {name: new String()}.\n /// \n /// Helps IDE code completion by knowing the members that objects contain and not just the indexes. Also\n /// know what type each member has. Example: {name: String, emailAddresses: [String], properties: {shoeSize: Number}}\n\n // Default constructor able to copy given properties into this object.\n function Class(properties) {\n /// Properties to initialize object with.\n /// \n properties ? extend(this, properties) : fake && applyStructure(this, structure);\n }\n return Class;\n};\n\nDexie.applyStructure = applyStructure;\n\nDexie.ignoreTransaction = function (scopeFunc) {\n // In case caller is within a transaction but needs to create a separate transaction.\n // Example of usage:\n //\n // Let's say we have a logger function in our app. Other application-logic should be unaware of the\n // logger function and not need to include the 'logentries' table in all transaction it performs.\n // The logging should always be done in a separate transaction and not be dependant on the current\n // running transaction context. Then you could use Dexie.ignoreTransaction() to run code that starts a new transaction.\n //\n // Dexie.ignoreTransaction(function() {\n // db.logentries.add(newLogEntry);\n // });\n //\n // Unless using Dexie.ignoreTransaction(), the above example would try to reuse the current transaction\n // in current Promise-scope.\n //\n // An alternative to Dexie.ignoreTransaction() would be setImmediate() or setTimeout(). The reason we still provide an\n // API for this because\n // 1) The intention of writing the statement could be unclear if using setImmediate() or setTimeout().\n // 2) setTimeout() would wait unnescessary until firing. This is however not the case with setImmediate().\n // 3) setImmediate() is not supported in the ES standard.\n return Promise.newPSD(function () {\n Promise.PSD.trans = null;\n return scopeFunc();\n });\n};\n\nDexie.vip = function (fn) {\n // To be used by subscribers to the on('ready') event.\n // This will let caller through to access DB even when it is blocked while the db.ready() subscribers are firing.\n // This would have worked automatically if we were certain that the Provider was using Dexie.Promise for all asyncronic operations. The promise PSD\n // from the provider.connect() call would then be derived all the way to when provider would call localDatabase.applyChanges(). But since\n // the provider more likely is using non-promise async APIs or other thenable implementations, we cannot assume that.\n // Note that this method is only useful for on('ready') subscribers that is returning a Promise from the event. If not using vip()\n // the database could deadlock since it wont open until the returned Promise is resolved, and any non-VIPed operation started by\n // the caller will not resolve until database is opened.\n return Promise.newPSD(function () {\n Promise.PSD.letThrough = true; // Make sure we are let through if still blocking db due to onready is firing.\n return fn();\n });\n};\n\nDexie.async = function (generatorFn) {\n return function () {\n try {\n var rv = awaitIterable(generatorFn.apply(this, arguments));\n if (!rv || typeof rv.then !== 'function') return Dexie.Promise.resolve(rv);\n return rv;\n } catch (e) {\n return Dexie.Promise.reject(e);\n }\n };\n};\n\nDexie.spawn = function (generatorFn, args, thiz) {\n try {\n var rv = awaitIterable(generatorFn.apply(thiz, args || []));\n if (!rv || typeof rv.then !== 'function') return Dexie.Promise.resolve(rv);\n return rv;\n } catch (e) {\n return Dexie.Promise.reject(e);\n }\n};\n\n// Dexie.currentTransaction property. Only applicable for transactions entered using the new \"transact()\" method.\nsetProp(Dexie, \"currentTransaction\", {\n get: function () {\n /// \n return Promise.PSD && Promise.PSD.trans || null;\n }\n});\n\nfunction safariMultiStoreFix(storeNames) {\n return storeNames.length === 1 ? storeNames[0] : storeNames;\n}\n\n// Export our Promise implementation since it can be handy as a standalone Promise implementation\nDexie.Promise = Promise;\n// Export our derive/extend/override methodology\nDexie.derive = derive;\nDexie.extend = extend;\nDexie.extendProto = extendProto;\nDexie.override = override;\n// Export our Events() function - can be handy as a toolkit\nDexie.Events = Dexie.events = Events; // Backward compatible lowercase version.\n// Utilities\nDexie.getByKeyPath = getByKeyPath;\nDexie.setByKeyPath = setByKeyPath;\nDexie.delByKeyPath = delByKeyPath;\nDexie.shallowClone = shallowClone;\nDexie.deepClone = deepClone;\nDexie.addons = [];\nDexie.fakeAutoComplete = fakeAutoComplete;\nDexie.asap = asap;\nDexie.maxKey = maxKey;\nDexie.connections = connections;\nDexie.dump = messageAndStack;\n\n// Export Error classes\nextend(Dexie, fullNameExceptions); // Dexie.XXXError = class XXXError {...};\nDexie.MultiModifyError = Dexie.ModifyError; // Backward compatibility 0.9.8\nDexie.errnames = errnames;\n\n// Export other static classes\nDexie.IndexSpec = IndexSpec;\nDexie.TableSchema = TableSchema;\n\n//\n// Dependencies\n//\n// These will automatically work in browsers with indexedDB support, or where an indexedDB polyfill has been included.\n//\n// In node.js, however, these properties must be set \"manually\" before instansiating a new Dexie(). For node.js, you need to require indexeddb-js or similar and then set these deps.\n//\nvar idbshim = _global.idbModules && _global.idbModules.shimIndexedDB ? _global.idbModules : {};\nDexie.dependencies = {\n // Required:\n indexedDB: idbshim.shimIndexedDB || _global.indexedDB || _global.mozIndexedDB || _global.webkitIndexedDB || _global.msIndexedDB,\n IDBKeyRange: idbshim.IDBKeyRange || _global.IDBKeyRange || _global.webkitIDBKeyRange\n};\nminiTryCatch(function () {\n // Optional dependencies\n // localStorage\n Dexie.dependencies.localStorage = (typeof chrome !== \"undefined\" && chrome !== null ? chrome.storage : void 0) != null ? null : _global.localStorage;\n});\n\n// 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.\nDexie.semVer = \"{version}\";\nDexie.version = Dexie.semVer.split('.').map(function (n) {\n return parseInt(n);\n}).reduce(function (p, c, i) {\n return p + c / Math.pow(10, i * 2);\n});\n\nfunction getNativeGetDatabaseNamesFn(indexedDB) {\n var fn = indexedDB && (indexedDB.getDatabaseNames || indexedDB.webkitGetDatabaseNames);\n return fn && fn.bind(indexedDB);\n}\n\n// Fool IDE to improve autocomplete. Tested with Visual Studio 2013 and 2015.\ndoFakeAutoComplete(function () {\n Dexie.fakeAutoComplete = fakeAutoComplete = doFakeAutoComplete;\n Dexie.fake = fake = true;\n});\n\n// https://github.com/dfahlander/Dexie.js/issues/186\n// typescript compiler tsc in mode ts-->es5 & commonJS, will expect require() to return\n// x.default. Workaround: Set Dexie.default = Dexie.\nDexie.default = Dexie;"],"names":["asap"],"mappings":"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"} \ No newline at end of file diff --git a/dist/dexie.min.js b/dist/dexie.min.js new file mode 100644 index 000000000..b1ca6d4fa --- /dev/null +++ b/dist/dexie.min.js @@ -0,0 +1,3 @@ +!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):n.Dexie=t()}(this,function(){"use strict";function n(){}function t(n){return n}function e(n,e){return null==n||n===t?e:function(t){return e(n(t))}}function r(n,t){return function(){n.apply(this,arguments),t.apply(this,arguments)}}function i(t,e){return t===n?e:function(){var n=t.apply(this,arguments);void 0!==n&&(arguments[0]=n);var i=this.onsuccess,o=this.onerror;this.onsuccess=null,this.onerror=null;var u=e.apply(this,arguments);return i&&(this.onsuccess=this.onsuccess?r(i,this.onsuccess):i),o&&(this.onerror=this.onerror?r(o,this.onerror):o),void 0!==u?u:n}}function o(t,e){return t===n?e:function(){t.apply(this,arguments);var n=this.onsuccess,i=this.onerror;this.onsuccess=this.onerror=null,e.apply(this,arguments),n&&(this.onsuccess=this.onsuccess?r(n,this.onsuccess):n),i&&(this.onerror=this.onerror?r(i,this.onerror):i)}}function u(t,e){return t===n?e:function(){var n=t.apply(this,arguments);f(arguments[0],n);var i=this.onsuccess,o=this.onerror;this.onsuccess=null,this.onerror=null;var u=e.apply(this,arguments);return i&&(this.onsuccess=this.onsuccess?r(i,this.onsuccess):i),o&&(this.onerror=this.onerror?r(o,this.onerror):o),void 0===n?void 0===u?void 0:u:f(n,u)}}function c(t,e){return t===n?e:function(){return t.apply(this,arguments)===!1?!1:e.apply(this,arguments)}}function a(t,e){return t===n?e:function(){return e.apply(this,arguments)===!1?!1:t.apply(this,arguments)}}function s(t,e){return t===n?e:function(){var n=t.apply(this,arguments);if(n&&"function"==typeof n.then){var r=this,i=arguments;return n.then(function(){return e.apply(r,i)})}return e.apply(this,arguments)}}function f(n,t){return"object"!=typeof t?n:(on(t).forEach(function(e){n[e]=t[e]}),n)}function l(n,t){"function"==typeof t&&(t=t(Object.getPrototypeOf(n))),on(t).forEach(function(e){h(n,e,t[e])})}function h(n,t,e,r){Object.defineProperty(n,t,f("function"==typeof e.get?{get:e.get,set:e.set,configurable:!0}:{value:e,configurable:!0,writable:!0},r))}function d(n){return{from:function(t){return n.prototype=Object.create(t.prototype),h(n.prototype,"constructor",n),{extend:l.bind(null,n.prototype)}}}}function p(n,t,e){return an.call(n,t,e)}function v(n,t){return t(n)}function y(n){var t=setTimeout(n,1e3);clearTimeout(t)}function m(n){if(!n)throw new vn.Internal("Assertion failed")}function g(n){cn.setImmediate?setImmediate(n):setTimeout(n,0)}function b(n,t){try{n()}catch(e){t&&t(e)}}function w(n){var t=n&&n.stack;return t?t.indexOf(n+"")>0?t:n+". "+t:n}function _(n){if(n.stack)return n;try{var t=new Error(n.message||n);if(t.stack)return n.stack=t.stack,n;throw t}catch(e){n.stack=e.stack}return n}function x(n){return B.reject(_(n))}function P(n,t){if(n.hasOwnProperty(t))return n[t];if(!t)return n;if("string"!=typeof t){for(var e=[],r=0,i=t.length;i>r;++r){var o=P(n,t[r]);e.push(o)}return e}var u=t.indexOf(".");if(-1!==u){var c=n[t.substr(0,u)];return void 0===c?void 0:P(c,t.substr(u+1))}}function k(n,t,e){if(n&&void 0!==t&&!("isFrozen"in Object&&Object.isFrozen(n)))if("string"!=typeof t&&"length"in t){m("string"!=typeof e&&"length"in e);for(var r=0,i=t.length;i>r;++r)k(n,t[r],e[r])}else{var o=t.indexOf(".");if(-1!==o){var u=t.substr(0,o),c=t.substr(o+1);if(""===c)void 0===e?delete n[u]:n[u]=e;else{var a=n[u];a||(a=n[u]={}),k(a,c,e)}}else void 0===e?delete n[t]:n[t]=e}}function D(n,t){"string"==typeof t?k(n,t,void 0):"length"in t&&[].map.call(t,function(t){k(n,t,void 0)})}function S(n){var t={};for(var e in n)n.hasOwnProperty(e)&&(t[e]=n[e]);return t}function O(n){if(!n||"object"!=typeof n)return n;var t;if(un(n)){t=[];for(var e=0,r=n.length;r>e;++e)t.push(O(n[e]))}else if(n instanceof Date)t=new Date,t.setTime(n.getTime());else{t=n.constructor?Object.create(n.constructor.prototype):{};for(var i in n)n.hasOwnProperty(i)&&(t[i]=O(n[i]))}return t}function E(n,t,e,r){e=e||{},r=r||"";for(var i in n)if(n.hasOwnProperty(i))if(t.hasOwnProperty(i)){var o=n[i],u=t[i];"object"==typeof o&&"object"==typeof u?E(o,u,e,r+i+"."):o!==u&&(e[r+i]=t[i])}else e[r+i]=void 0;for(i in t)t.hasOwnProperty(i)&&!n.hasOwnProperty(i)&&(e[r+i]=t[i]);return e}function I(n,t){this.name=n,this.message=t}function C(n,t){return n+". Errors: "+t.map(function(n){return n.toString()}).filter(function(n,t,e){return e.indexOf(n)===t}).join("\n")}function A(n,t,e,r){this.name="ModifyError",this.failures=t,this.failedKeys=r,this.successCount=e,this.message=C(n,t)}function j(n,t){this.name="BulkError",this.failures=t,this.message=C(n,t)}function T(n,t){var e=n;return n instanceof I||!n.name||!yn[n.name]||(e=new yn[n.name](t||n.message,n),n.stack&&(e.stack=n.stack)),e}function K(t){function e(t,e,o){if(un(t))return i(t);if("object"==typeof t)return r(t);e||(e=c),o||(o=n);var s={subscribers:[],fire:o,subscribe:function(n){s.subscribers.push(n),s.fire=e(s.fire,n)},unsubscribe:function(n){s.subscribers=s.subscribers.filter(function(t){return t!==n}),s.fire=s.subscribers.reduce(e,o)}};return u[t]=a[t]=s,s}function r(n){on(n).forEach(function(t){var r=n[t];if(un(r))e(t,n[t][0],n[t][1]);else{if("asap"!==r)throw new vn.InvalidArgument("Invalid event config");var i=e(t,null,function(){var n=arguments;i.subscribers.forEach(function(t){g(function(){t.apply(cn,n)})})});i.subscribe=function(n){-1===i.subscribers.indexOf(n)&&i.subscribers.push(n)},i.unsubscribe=function(n){var t=i.subscribers.indexOf(n);-1!==t&&i.subscribers.splice(t,1)}}})}function i(n){function t(){return r?!1:void(r=!0)}var r=!1;n.forEach(function(n){e(n).subscribe(t)})}var o=arguments,u={},a=function(n,e){if(e){var r=p(arguments,1),i=u[n];return i.subscribe.apply(i,r),t}return"string"==typeof n?u[n]:void 0};a.addEventType=e;for(var s=1,f=o.length;f>s;++s)e(o[s]);return a}function F(){var n=_n;_n=[];for(var t=0,e=n.length;e>t;++t){var r=n[t];r[0].apply(cn,r[1])}}function B(n){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof n)throw new TypeError("not a function");this._state=null,this._value=null,this._deferreds=[],this._catched=!1;var t=this,e=!0;this._PSD=B.PSD;try{L(this,n,function(n){e?bn(M,t,n):M(t,n)},function(n){return e?(bn(U,t,n),!1):U(t,n)})}finally{e=!1}}function N(n,t){if(null===n._state)return void n._deferreds.push(t);var e=n._state?t.onFulfilled:t.onRejected;if(null===e)return(n._state?t.resolve:t.reject)(n._value);var r,i=wn;wn=!1,bn=Pn;try{var o=B.PSD;B.PSD=n._PSD,r=e(n._value),n._state||r&&"function"==typeof r.then&&r._state===!1||q(n),t.resolve(r)}catch(u){t.reject(u)}finally{if(B.PSD=o,i){do{for(;_n.length>0;)F();var c=xn.pop();if(c)try{c()}catch(u){}}while(xn.length>0||_n.length>0);bn=gn,wn=!0}}}function R(n){var t=wn;wn=!1,bn=Pn;try{return n()}finally{if(t){do{for(;_n.length>0;)F();var e=xn.pop();if(e)try{e()}catch(r){}}while(xn.length>0||_n.length>0);bn=gn,wn=!0}}}function q(n){n._catched=!0,n._parent&&!n._parent._catched&&q(n._parent)}function M(n,t){var e=B.PSD;B.PSD=n._PSD;try{if(t===n)throw new TypeError("A promise cannot be resolved with itself.");if(t&&("object"==typeof t||"function"==typeof t)&&"function"==typeof t.then)return t instanceof B&&null!==t._state?(n._state=t._state,n._value=t._value,void V.call(n)):void L(n,function(n,e){t.then(n,e)},function(t){M(n,t)},function(t){U(n,t)});n._state=!0,n._value=t,V.call(n)}catch(r){U(r)}finally{B.PSD=e}}function U(n,t){var e=B.PSD;if(B.PSD=n._PSD,n._state=!1,n._value=t,V.call(n),!n._catched)try{n.onuncatched?n.onuncatched(n._value):B.on.error.fire(n._value)}catch(r){}return B.PSD=e,n._catched}function V(){for(var n=0,t=this._deferreds.length;t>n;n++)N(this,this._deferreds[n]);this._deferreds=[]}function W(n,t,e,r){this.onFulfilled="function"==typeof n?n:null,this.onRejected="function"==typeof t?t:null,this.resolve=e,this.reject=r}function L(n,t,e,r){var i=!1;try{t(function(n){i||(i=!0,e(n))},function(t){return i?n._catched:(i=!0,r(t))})}catch(o){if(i)return;return r(o)}}function z(n){console.warn("Uncaught Promise: "+w(n))}function H(r,c){function y(){$n.on("versionchange",function(n){n.newVersion>0?console.warn("Another connection wants to upgrade database '"+$n.name+"'. Closing db now to resume the upgrade."):console.warn("Another connection wants to delete database '"+$n.name+"'. Closing db now to resume the delete request."),$n.close()}),$n.on("blocked",function(n){!n.newVersion||n.newVersionn});a.forEach(function(n){var r=Vn,i=n._cfg.dbschema;Kn(r,t),Kn(i,t),Vn=$n._dbSchema=i;var u=D(r,i);u.add.forEach(function(n){o.push(function(t,e){I(t,n[0],n[1].primKey,n[1].indexes),e()})}),u.change.forEach(function(n){if(n.recreate)throw new vn.Upgrade("Not yet support for changing primary key");o.push(function(t,e){var r=t.objectStore(n.name);n.add.forEach(function(n){N(r,n)}),n.change.forEach(function(n){r.deleteIndex(n.name),N(r,n)}),n.del.forEach(function(n){r.deleteIndex(n)}),e()})}),n._cfg.contentUpgrade&&o.push(function(t,r){c=!0;var o=$n._createTransaction(Zn,p(t.db.objectStoreNames),i);o.idbtrans=t;var u=0;o._promise=v(o._promise,function(n){return function(t,e,i){function o(n){return function(){n.apply(this,arguments),0===--u&&r()}}return++u,n.call(this,t,function(n,t){arguments[0]=o(n),arguments[1]=o(t),e.apply(this,arguments)},i)}}),t.onerror=Q(e,["running upgrader function for version",n._cfg.version]),o.on("error").subscribe(e),n._cfg.contentUpgrade(o),0===u&&r()}),c&&!Cn||o.push(function(n,t){F(i,n),t()})});var s=function(){try{o.length?o.shift()(t,s):C(Vn,t)}catch(n){r.onerror=t.onerror=function(n){n.preventDefault()};try{t.abort()}catch(i){}t.db.close(),e(n)}};s()}}function D(n,t){var e={del:[],add:[],change:[]};for(var r in n)t[r]||e.del.push(r);for(r in t){var i=n[r],o=t[r];if(i){var u={name:r,def:t[r],recreate:!1,del:[],add:[],change:[]};if(i.primKey.src!==o.primKey.src)u.recreate=!0,e.change.push(u);else{var c=i.indexes.reduce(function(n,t){return n[t.name]=t,n},{}),a=o.indexes.reduce(function(n,t){return n[t.name]=t,n},{});for(var s in c)a[s]||u.del.push(s);for(s in a){var f=c[s],l=a[s];f?f.src!==l.src&&u.change.push(l):u.add.push(l)}(u.recreate||u.del.length>0||u.add.length>0||u.change.length>0)&&e.change.push(u)}}else e.add.push([r,o])}return e}function I(n,t,e,r){var i=n.db.createObjectStore(t,e.keyPath?{keyPath:e.keyPath,autoIncrement:e.auto}:{autoIncrement:e.auto});return r.forEach(function(n){N(i,n)}),i}function C(n,t){on(n).forEach(function(e){t.db.objectStoreNames.contains(e)||I(t,e,n[e].primKey,n[e].indexes)})}function F(n,t){for(var e=0;er;++r){var u=e[r];i.call(s,u[0],u[1],t);var h=n["delete"](u[0]);s.onerror&&(h._err=s.onerror),s.onsuccess&&(h._suc=s.onsuccess),h.onerror=f,r===a?h.onsuccess=L(o,!0):h.onsuccess=l,s.onsuccess=null,s.onerror=null}},function(n){throw s.onerror&&s.onerror(n),n})}else for(var h=0;c>h;++h){var d=n["delete"](e[h]);d.onerror=function(n){return u(T(n.target.error))},h===a&&(d.onsuccess=function(){return o()})}})}function G(n,t,e,r){function i(n,t,e,r){return o._promise(n,e,r)}var o=this;this.db=$n,this.mode=n,this.storeNames=t,this.idbtrans=null,this.on=K(this,["complete","error"],"abort"),this._reculock=0,this._blockedFuncs=[],this._psd=null,this.active=!0,this._dbschema=e,r&&(this.parent=r),this._tpf=i,this.tables=Object.create(Hn);for(var u=t.length-1;-1!==u;--u){var c=t[u],a=$n._tableFactory(n,e[c],i);this.tables[c]=a,this[c]||(this[c]=a)}}function cn(n,t,e){this._ctx={table:n,index:":id"===t?null:t,collClass:n._collClass,or:e}}function an(n,t){var e=null,r=null;if(t)try{e=t()}catch(i){r=_(T(i))}var o=n._ctx,u=o.table;this._ctx={table:u,index:o.index,isPrimKey:!o.index||u.schema.primKey.keyPath&&o.index===u.schema.primKey.name,range:e,keysOnly:!1,dir:"next",unique:"",algorithm:null,filter:null,replayFilter:null,isMatch:null,offset:0,limit:1/0,error:r,or:o.or,valueFilter:u.hook.reading.fire}}function sn(){an.apply(this,arguments)}function fn(n,t){return n._cfg.version-t._cfg.version}function ln(n,t,e,r,i,o){e.forEach(function(e){var u=$n._tableFactory(r,i[e],t);n.forEach(function(n){n[e]||(o?h(n,e,{get:function(){var n=B.PSD&&B.PSD.trans;return n&&n.db===$n?n.tables[e]:u}},{enumerable:!0}):n[e]=u)})})}function hn(n){n.forEach(function(n){for(var t in n)n[t]instanceof M&&delete n[t]})}function dn(n,e,r,i,o,u){u=u||t,n.onerror||(n.onerror=Q(o)),e?n.onsuccess=J(function(){var t=n.result;if(t){var c=function(){t["continue"]()};e(t,function(n){c=n},i,o)&&r(u(t.value),t,function(n){c=n}),c()}else i()},o):n.onsuccess=J(function(){var t=n.result;if(t){var e=function(){t["continue"]()};r(u(t.value),t,function(n){e=n}),e()}else i()},o)}function pn(n){var t=[];return n.split(",").forEach(function(n){n=n.trim();var e=n.replace("&","").replace("++","").replace("*",""),r=0!==e.indexOf("[")?e:n.substring(n.indexOf("[")+1,n.indexOf("]")).split("+");t.push(new nn(e,r||null,-1!==n.indexOf("&"),-1!==n.indexOf("*"),-1!==n.indexOf("++"),un(r),-1!==r.indexOf(".")))}),t}function yn(n,t){return Mn.cmp(n,t)}function mn(n,t){return yn(n,t)<0?n:t}function gn(n,t){return yn(n,t)>0?n:t}function bn(n,t){return Mn.cmp(n,t)}function wn(n,t){return Mn.cmp(t,n)}function _n(n,t){return t>n?-1:n===t?0:1}function xn(n,t){return n>t?-1:n===t?0:1}function Pn(n,t){return n?t?function(){return n.apply(this,arguments)&&t.apply(this,arguments)}:n:t}function In(){if($n.verno=Jn.version/10,$n._dbSchema=Vn={},Ln=p(Jn.objectStoreNames,0),0!==Ln.length){var n=Jn.transaction(en(Ln),"readonly");Ln.forEach(function(t){for(var e=n.objectStore(t),r=e.keyPath,i=r&&"string"==typeof r&&-1!==r.indexOf("."),o=new nn(r,r||"",!1,!1,!!e.autoIncrement,r&&"string"!=typeof r,i),u=[],c=0;c0&&(tt=!1),!Mn)throw new vn.MissingAPI("indexedDB API not found. If using IE10+, make sure to run your code on a server URL (not locally). If using Safari, make sure to include indexedDB polyfill.");if(i=tt?Mn.open(r):Mn.open(r,Math.round(10*$n.verno)),!i)throw new vn.MissingAPI("IndexedDB API not available");i.onerror=Q(e,["opening database",r]),i.onblocked=Fn,i.onupgradeneeded=J(function(n){if(tt&&!$n._allowEmptyDB){i.onerror=function(n){n.preventDefault()},i.transaction.abort(),i.result.close();var t=Mn.deleteDatabase(r);t.onsuccess=t.onerror=function(){e(new vn.NoSuchDatabase("Database "+r+" doesnt exist"))}}else{i.transaction.onerror=Q(e);var o=n.oldVersion>Math.pow(2,62)?0:n.oldVersion;w(o/10,i.transaction,e,i)}},e),i.onsuccess=J(function(){if(Qn=!1,Jn=i.result,tt)In();else if(Jn.objectStoreNames.length>0)try{Kn(Vn,Jn.transaction(en(Jn.objectStoreNames),Xn))}catch(t){}Jn.onversionchange=function(n){$n._vcFired=!0,$n.on("versionchange").fire(n)},et||Z(function(n){return-1===n.indexOf(r)?n.push(r):void 0}),B.newPSD(function(){function t(){Gn=!1,R(),n()}B.PSD.letThrough=!0;try{var r=$n.on.ready.fire();r&&"function"==typeof r.then?r.then(t,function(n){Jn.close(),Jn=null,e(n)}):g(t)}catch(i){e(i)}})},e)}catch(o){e(o)}}).then(function(){return En.push($n),$n}))},this.close=function(){var n=En.indexOf($n);n>=0&&En.splice(n,1),Jn?(Jn.close(),Jn=null,qn=!1,Gn&&R(),Gn=!1,Yn=new vn.DatabaseClosed):Qn&&$n.on("ready",function(){return B.reject(new vn.DatabaseClosed)})},this["delete"]=function(){var n=arguments;return new B(function(t,e){function i(){$n.close();var n=Mn.deleteDatabase(r);n.onsuccess=function(){et||Z(function(n){var t=n.indexOf(r);return t>=0?n.splice(t,1):void 0}),t()},n.onerror=Q(e,["deleting",r]),n.onblocked=Fn}if(n.length>0)throw new vn.InvalidArgument("Arguments not allowed in db.delete()");Qn?nt.push({resume:i}):i()})},this.backendDB=function(){return Jn},this.isOpen=function(){return null!==Jn},this.hasFailed=function(){return null!==Yn},this.dynamicallyOpened=function(){return tt},this.name=r,h(this,"tables",{get:function(){return on(zn).map(function(n){return zn[n]})}}),this.on=K(this,"error","populate",{blocked:[a,n],ready:[s,n],versionchange:[a,n]}),this.on.ready.subscribe=v(this.on.ready.subscribe,function(n){return function(t,e){function r(){return e||$n.on.ready.unsubscribe(r),t.apply(this,arguments)}n.call(this,r),$n.isOpen()&&(Gn?nt.push({resume:r}):r())}}),jn(function(){$n.on("populate").fire($n._createTransaction(Zn,Ln,Vn)),$n.on("error").fire(new Error)}),this.transaction=function(n,t,e){function r(t,r){var o=null,u=!0;try{if(c)throw c;o=$n._createTransaction(n,a,Vn,i);var s=a.map(function(n){return o.tables[n]});s.push(o);var f,l=0;B.newPSD(function(){B.PSD.trans=o,o.scopeFunc=e,i&&(o.idbtrans=i.idbtrans,o._promise=v(o._promise,function(n){return function(t,e,r){function i(n){return function(t){var e;return B._rootExec(function(){e=n(t),B._tickFinalize(function(){0===--l&&o.active&&(o.active=!1,o.on.complete.fire())})}),e}}return++l,n.call(this,t,function(n,t,r){return e(i(n),i(t),r)},r)}})),o.complete(function(){t(f)}),o.error(function(n){function t(){var t=r(n);i||t||$n.on.error.fire(n)}o.idbtrans&&(o.idbtrans.onerror=X);try{o.abort()}catch(e){}i&&(i.active=!1,i.on.error.fire(n)),u?g(t):t()}),B._rootExec(function(){if(f=e.apply(o,s))if("function"==typeof f.next&&"function"==typeof f["throw"])f=$(f);else if("function"==typeof f.then&&!f.hasOwnProperty("_PSD"))throw new vn.IncompatiblePromise})}),(!o.idbtrans||i&&0===l)&&o._nop()}catch(h){o&&o.idbtrans&&(o.idbtrans.onerror=X),o&&o.abort(),i&&i.on.error.fire(h),g(function(){r(h)||$n.on("error").fire(h)})}u=!1}t=p(arguments,1,arguments.length-1),e=arguments[arguments.length-1];var i=B.PSD&&B.PSD.trans;i&&i.db===$n&&-1===n.indexOf("!")||(i=null);var o=-1!==n.indexOf("?");n=n.replace("!","").replace("?","");var u=un(t[0])?t.reduce(function(n,t){return n.concat(t)}):t,c=null,a=u.map(function(n){return"string"==typeof n?n:(n instanceof M||(c=c||new TypeError("Invalid type. Arguments following mode must be instances of Table or String")),n.name)});return"r"==n||n==Xn?n=Xn:"rw"==n||n==Zn?n=Zn:c=new vn.InvalidArgument("Invalid transaction mode: "+n),i&&(c||(i&&i.mode===Xn&&n===Zn&&(o?i=null:c=c||new vn.SubTransaction("Cannot enter a sub-transaction with READWRITE mode when parent transaction is READONLY")),i&&a.forEach(function(n){i.tables.hasOwnProperty(n)||(o?i=null:c=c||new vn.SubTransaction("Table "+n+" not included in parent transaction. Parent Transaction function: "+i.scopeFunc.toString()))}))),i?i._promise(n,r,"lock"):$n._whenReady(r)},this.table=function(n){if(Tn&&tt)return new U(n);if(!zn.hasOwnProperty(n))throw new vn.InvalidTable("Table "+n+" does not exist");return zn[n]},l(M.prototype,function(){function n(){throw new vn.ReadOnly("Current Transaction is READONLY")}return{_trans:function(n,t,e){return this._tpf(n,[this.name],t,e)},_idbstore:function(n,t,e){if(Tn)return new B(t);var r=this;return this._tpf(n,[this.name],function(n,e,i){t(n,e,i.idbtrans.objectStore(r.name),i)},e)},get:function(n,t){var e=this;return this._idbstore(Xn,function(t,r,i){Tn&&t(e.schema.instanceTemplate);var o=i.get(n);o.onerror=Q(r,["getting",n,"from",e.name]),o.onsuccess=function(){t(e.hook.reading.fire(o.result))}}).then(t)},where:function(n){return new cn(this,n)},count:function(n){return this.toCollection().count(n)},offset:function(n){return this.toCollection().offset(n)},limit:function(n){return this.toCollection().limit(n)},reverse:function(){return this.toCollection().reverse()},filter:function(n){return this.toCollection().and(n)},each:function(n){return this.toCollection().each(n)},toArray:function(n){return this.toCollection().toArray(n)},orderBy:function(n){return new this._collClass(new cn(this,n))},toCollection:function(){return new this._collClass(new cn(this))},mapToClass:function(n,t){this.schema.mappedClass=n;var e=Object.create(n.prototype);t&&Y(e,t),this.schema.instanceTemplate=e;var r=function(t){if(!t)return t;var e=Object.create(n.prototype);for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e};return this.schema.readHook&&this.hook.reading.unsubscribe(this.schema.readHook),this.schema.readHook=r,this.hook("reading",r),n},defineClass:function(n){return this.mapToClass(H.defineClass(n),n)},add:n,put:n,"delete":n,clear:n,update:n}}),d(U).from(M).extend(function(){return{bulkDelete:function(t){return this.hook.deleting.fire===n?this._idbstore(Zn,function(e,r,i,o){e(z(i,o,t,!1,n))}):this.where(":id").anyOf(t)["delete"]().then(function(){})},bulkPut:function(t,e){var r=this;return this._idbstore(Zn,function(i,o,u,c){if(!u.keyPath&&!r.schema.primKey.auto&&!e)throw new vn.InvalidArgument("bulkPut() with non-inbound keys requires keys array in second argument");if(u.keyPath&&e)throw new vn.InvalidArgument("bulkPut(): keys argument invalid on tables with inbound keys");if(e&&e.length!==t.length)throw new vn.InvalidArgument("Arguments objects and keys must have the same length");if(0===t.length)return i();var a,s,f=function(n){0===l.length?i(n):o(new j(r.name+".bulkPut(): "+l.length+" of "+h+" operations failed",l))},l=[],h=t.length,d=c.tables[r.name];if(r.hook.creating.fire===n&&r.hook.updating.fire===n){s=V(l);for(var p=0,v=t.length;v>p;++p)a=e?u.put(t[p],e[p]):u.put(t[p]),a.onerror=s;a.onerror=V(l,f),a.onsuccess=L(f)}else{var y=e||u.keyPath&&t.map(function(n){return P(n,u.keyPath)}),m=y&&y.reduce(function(n,e,r){return null!=e&&(n[e]=t[r]),n},{}),g=y?d.where(":id").anyOf(y.filter(function(n){return null!=n})).modify(function(){this.value=m[this.primKey],m[this.primKey]=null})["catch"](A,function(n){l=n.failures}).then(function(){for(var n=[],r=e&&[],i=y.length-1;i>=0;--i){var o=y[i];(null==o||m[o])&&(n.push(t[i]),e&&r.push(o),null!=o&&(m[o]=null))}return n.reverse(),e&&r.reverse(),d.bulkAdd(n,r)}).then(function(n){var t=y[y.length-1];return null!=t?t:n}):d.bulkAdd(t);g.then(f)["catch"](j,function(n){l=l.concat(n.failures),f()})["catch"](o)}},"locked")},bulkAdd:function(t,e){var r=this,i=this.hook.creating.fire;return this._idbstore(Zn,function(o,u,c,a){function s(n){0===d.length?o(n):u(new j(r.name+".bulkAdd(): "+d.length+" of "+p+" operations failed",d))}if(!c.keyPath&&!r.schema.primKey.auto&&!e)throw new vn.InvalidArgument("bulkAdd() with non-inbound keys requires keys array in second argument");if(c.keyPath&&e)throw new vn.InvalidArgument("bulkAdd(): keys argument invalid on tables with inbound keys");if(e&&e.length!==t.length)throw new vn.InvalidArgument("Arguments objects and keys must have the same length");if(0===t.length)return o();var f,l,h,d=[],p=t.length;if(i!==n){var v=c.keyPath,y={onerror:null,onsuccess:null};l=V(d,null),h=L(null,!0),b(function(){for(var n=0,r=t.length;r>n;++n){var o=e&&e[n],u=t[n],s=e?o:v?P(u,v):void 0,d=i.call(y,s,u,a);null==s&&null!=d&&(v?(u=O(u),k(u,v,d)):o=d),f=null!=o?c.add(u,o):c.add(u),y.onerror&&(f._err=y.onerror),y.onsuccess&&(f._suc=y.onsuccess),r-1>n&&(f.onerror=l,y.onsuccess&&(f.onsuccess=h),y.onerror=null,y.onsuccess=null)}},function(n){throw y.onerror&&y.onerror(n),n}),f.onerror=V(d,s),f.onsuccess=L(s,!0)}else{l=V(d);for(var m=0,g=t.length;g>m;++m)f=e?c.add(t[m],e[m]):c.add(t[m]),f.onerror=l;f.onerror=V(d,s),f.onsuccess=L(s)}})},add:function(t,e){var r=this,i=this.hook.creating.fire;return this._idbstore(Zn,function(o,u,c,a){var s={onsuccess:null,onerror:null};if(i!==n){var f=null!=e?e:c.keyPath?P(t,c.keyPath):void 0,l=i.call(s,f,t,a);null==f&&null!=l&&(c.keyPath?k(t,c.keyPath,l):e=l)}try{var h=null!=e?c.add(t,e):c.add(t),d=B.PSD;h.onerror=Q(function(n){return s.onerror&&B.usePSD(d,s.onerror.bind(s,n)),u(n)},["adding",t,"into",r.name]),h.onsuccess=function(n){var e=c.keyPath;e&&k(t,e,n.target.result),s.onsuccess&&B.usePSD(d,s.onsuccess.bind(s,n.target.result)),o(h.result)}}catch(p){throw s.onerror&&s.onerror(p),p}})},put:function(t,e){var r=this,i=this.hook.creating.fire,o=this.hook.updating.fire;return i!==n||o!==n?this._trans(Zn,function(n,i,o){var u=void 0!==e?e:r.schema.primKey.keyPath&&P(t,r.schema.primKey.keyPath);null==u?o.tables[r.name].add(t).then(n,i):(o._lock(),t=O(t),o.tables[r.name].where(":id").equals(u).modify(function(){this.value=t}).then(function(n){return 0===n?o.tables[r.name].add(t,e):u})["finally"](function(){o._unlock()}).then(n,i))}):this._idbstore(Zn,function(n,i,o){var u=void 0!==e?o.put(t,e):o.put(t);u.onerror=Q(i,["putting",t,"into",r.name]),u.onsuccess=function(e){var r=o.keyPath;r&&k(t,r,e.target.result),n(u.result)}})},"delete":function(n){return this.hook.deleting.subscribers.length?this.where(":id").equals(n)["delete"]():this._idbstore(Zn,function(t,e,r){var i=r["delete"](n);i.onerror=Q(e,["deleting",n,"from",r.name]),i.onsuccess=function(){t(i.result)}})},clear:function(){return this.hook.deleting.subscribers.length?this.toCollection()["delete"]():this._idbstore(Zn,function(n,t,e){var r=e.clear();r.onerror=Q(t,["clearing",e.name]),r.onsuccess=function(){n(r.result)}})},update:function(n,t){if("object"!=typeof t||un(t))throw new vn.InvalidArgument("db.update(keyOrObject, modifications). modifications must be an object.");if("object"!=typeof n||un(n))return this.where(":id").equals(n).modify(t);on(t).forEach(function(e){k(n,e,t[e])});var e=P(n,this.schema.primKey.keyPath);return void 0===e&&B.reject(new vn.InvalidArgument("Given object does not contain its primary key")),this.where(":id").equals(e).modify(t)}}}),l(G.prototype,{_lock:function(){return++this._reculock,1===this._reculock&&B.PSD&&(B.PSD.lockOwnerFor=this),this},_unlock:function(){if(0===--this._reculock)for(B.PSD&&(B.PSD.lockOwnerFor=null);this._blockedFuncs.length>0&&!this._locked();){var n=this._blockedFuncs.shift();try{n()}catch(t){}}return this},_locked:function(){return this._reculock&&(!B.PSD||B.PSD.lockOwnerFor!==this)},_nop:function(n){this.tables[this.storeNames[0]].get(0).then(n)},_promise:function(n,t,e){var r=this;return B.newPSD(function(){var i;return r._locked()?i=new B(function(i,o){r._blockedFuncs.push(function(){r._promise(n,t,e).then(i,o)})}):(i=r.active?new B(function(i,o){if(!r.idbtrans&&n){if(!Jn)throw!Yn||["DatabaseClosedError","MissingAPIError"].indexOf(Yn.name)>=0?Yn:new vn.OpenFailed(Yn);var u=r.idbtrans=Jn.transaction(en(r.storeNames),r.mode);u.onerror=function(n){r.on("error").fire(n&&n.target.error),n.preventDefault(),r.abort()},u.onabort=function(n){g(function(){r.on("error").fire(new vn.Abort("Transaction aborted for unknown reason"))}),r.active=!1,r.on("abort").fire(n)},u.oncomplete=function(n){r.active=!1,r.on("complete").fire(n)}}e&&r._lock();try{t(i,o,r)}catch(c){var a=_(T(c));H.ignoreTransaction(function(){ +r.on("error").fire(a)}),r.abort(),o(a)}}):B.reject(_(new vn.TransactionInactive("Transaction is inactive. Original Scope Function Source: "+r.scopeFunc.toString()))),r.active&&e&&i["finally"](function(){r._unlock()})),i.onuncatched=function(n){H.ignoreTransaction(function(){r.on("error").fire(n)}),r.abort()},i})},complete:function(n){return this.on("complete",n)},error:function(n){return this.on("error",n)},abort:function(){if(this.idbtrans&&this.active)try{this.active=!1,this.idbtrans.abort(),this.on.error.fire(new vn.Abort("Transaction Aborted"))}catch(n){}},table:function(n){if(!this.tables.hasOwnProperty(n))throw new vn.InvalidTable("Table "+n+" not in transaction");return this.tables[n]}}),l(cn.prototype,function(){function n(n,t,e){var r=n instanceof cn?new n._ctx.collClass(n):n;try{throw e?new e(t):new TypeError(t)}catch(i){r._ctx.error=i}return r}function t(n){return new n._ctx.collClass(n,function(){return Un.only("")}).limit(0)}function e(n){return p(1===n.length&&un(n[0])?n[0]:n)}function r(n){return"next"===n?function(n){return n.toUpperCase()}:function(n){return n.toLowerCase()}}function i(n){return"next"===n?function(n){return n.toLowerCase()}:function(n){return n.toUpperCase()}}function o(n,t,e,r,i,o){for(var u=Math.min(n.length,r.length),c=-1,a=0;u>a;++a){var s=t[a];if(s!==r[a])return i(n[a],e[a])<0?n.substr(0,a)+e[a]+e.substr(a+1):i(n[a],r[a])<0?n.substr(0,a)+r[a]+e.substr(a+1):c>=0?n.substr(0,c)+t[c]+e.substr(c+1):null;i(n[a],s)<0&&(c=a)}return uc?null:n.substr(0,c)+r[c]+e.substr(c+1)}function u(n,t,e,u){function c(n){a=r(n),s=i(n),f="next"===n?_n:xn;var t=e.map(function(n){return{lower:s(n),upper:a(n)}}).sort(function(n,t){return f(n.lower,t.lower)});l=t.map(function(n){return n.upper}),h=t.map(function(n){return n.lower}),d=n,p="next"===n?"":u}var a,s,f,l,h,d,p,v=e.length;c("next");var y=new n._ctx.collClass(n,function(){return Un.bound(l[0],h[v-1]+u)});y._ondirectionchange=function(n){c(n)};var m=0;return y._addAlgorithm(function(n,e,r){var i=n.key;if("string"!=typeof i)return!1;var u=s(i);if(t(u,h,m))return!0;for(var c=null,a=m;v>a;++a){var y=o(i,u,l[a],h[a],f,d);null===y&&null===c?m=a+1:(null===c||f(c,y)>0)&&(c=y)}return e(null!==c?function(){n["continue"](c+p)}:r),!1}),y}return{between:function(e,r,i,o){i=i!==!1,o=o===!0;try{return yn(e,r)>0||0===yn(e,r)&&(i||o)&&(!i||!o)?t(this):new this._ctx.collClass(this,function(){return Un.bound(e,r,!i,!o)})}catch(u){return n(this,Sn)}},equals:function(n){return new this._ctx.collClass(this,function(){return Un.only(n)})},above:function(n){return new this._ctx.collClass(this,function(){return Un.lowerBound(n,!0)})},aboveOrEqual:function(n){return new this._ctx.collClass(this,function(){return Un.lowerBound(n)})},below:function(n){return new this._ctx.collClass(this,function(){return Un.upperBound(n,!0)})},belowOrEqual:function(n){return new this._ctx.collClass(this,function(){return Un.upperBound(n)})},startsWith:function(t){return"string"!=typeof t?n(this,On):this.between(t,t+kn,!0,!0)},startsWithIgnoreCase:function(t){return"string"!=typeof t?n(this,On):""===t?this.startsWith(t):u(this,function(n,t){return 0===n.indexOf(t[0])},[t],kn)},equalsIgnoreCase:function(t){return"string"!=typeof t?n(this,On):u(this,function(n,t){return n===t[0]},[t],"")},anyOfIgnoreCase:function(){var r=e(arguments);return 0===r.length?t(this):r.every(function(n){return"string"==typeof n})?u(this,function(n,t){return-1!==t.indexOf(n)},r,""):n(this,"anyOfIgnoreCase() only works with strings")},startsWithAnyOfIgnoreCase:function(){var r=e(arguments);return 0===r.length?t(this):r.every(function(n){return"string"==typeof n})?u(this,function(n,t){return t.some(function(t){return 0===n.indexOf(t)})},r,kn):n(this,"startsWithAnyOfIgnoreCase() only works with strings")},anyOf:function(){var r=e(arguments),i=bn;try{r.sort(i)}catch(o){return n(this,Sn)}if(0===r.length)return t(this);var u=new this._ctx.collClass(this,function(){return Un.bound(r[0],r[r.length-1])});u._ondirectionchange=function(n){i="next"===n?bn:wn,r.sort(i)};var c=0;return u._addAlgorithm(function(n,t,e){for(var o=n.key;i(o,r[c])>0;)if(++c,c===r.length)return t(e),!1;return 0===i(o,r[c])?!0:(t(function(){n["continue"](r[c])}),!1)}),u},notEqual:function(n){return this.inAnyRange([[-(1/0),n],[n,Dn]],{includeLowers:!1,includeUppers:!1})},noneOf:function(){var t=e(arguments);if(0===t.length)return new this._ctx.collClass(this);try{t.sort(bn)}catch(r){return n(this,Sn)}var i=t.reduce(function(n,t){return n?n.concat([[n[n.length-1][1],t]]):[[-(1/0),t]]},null);return i.push([t[t.length-1],Dn]),this.inAnyRange(i,{includeLowers:!1,includeUppers:!1})},inAnyRange:function(e,r){function i(n,t){for(var e=0,r=n.length;r>e;++e){var i=n[e];if(yn(t[0],i[1])<0&&yn(t[1],i[0])>0){i[0]=mn(i[0],t[0]),i[1]=gn(i[1],t[1]);break}}return e===r&&n.push(t),n}function o(n,t){return l(n[0],t[0])}function u(n){return!p(n)&&!v(n)}var c=this._ctx;if(0===e.length)return t(this);if(!e.every(function(n){return void 0!==n[0]&&void 0!==n[1]&&bn(n[0],n[1])<=0}))return n(this,"First argument to inAnyRange() must be an Array of two-value Arrays [lower,upper] where upper must not be lower than lower",vn.InvalidArgument);var a,s=!r||r.includeLowers!==!1,f=r&&r.includeUppers===!0,l=bn;try{a=e.reduce(i,[]),a.sort(o)}catch(h){return n(this,Sn)}var d=0,p=f?function(n){return bn(n,a[d][1])>0}:function(n){return bn(n,a[d][1])>=0},v=s?function(n){return wn(n,a[d][0])>0}:function(n){return wn(n,a[d][0])>=0},y=p,m=new c.collClass(this,function(){return Un.bound(a[0][0],a[a.length-1][1],!s,!f)});return m._ondirectionchange=function(n){"next"===n?(y=p,l=bn):(y=v,l=wn),a.sort(o)},m._addAlgorithm(function(n,t,e){for(var r=n.key;y(r);)if(++d,d===a.length)return t(e),!1;return u(r)?!0:0===yn(r,a[d][1])||0===yn(r,a[d][0])?!1:(t(function(){l===bn?n["continue"](a[d][0]):n["continue"](a[d][1])}),!1)}),m},startsWithAnyOf:function(){var r=e(arguments);return r.every(function(n){return"string"==typeof n})?0===r.length?t(this):this.inAnyRange(r.map(function(n){return[n,n+kn]})):n(this,"startsWithAnyOf() only works with strings")}}}),l(an.prototype,function(){function n(n,t){n.filter=Pn(n.filter,t)}function t(n,t){var e=n.replayFilter;n.replayFilter=e?function(){return Pn(e(),t())}:t}function e(n,t){n.isMatch=Pn(n.isMatch,t)}function r(n,t){if(n.isPrimKey)return t;var e=n.table.schema.idxByName[n.index];if(!e)throw new vn.Schema("KeyPath "+n.index+" on object store "+t.name+" is not indexed");return t.index(e.name)}function i(n,t){var e=r(n,t);return n.keysOnly&&"openKeyCursor"in e?e.openKeyCursor(n.range||null,n.dir+n.unique):e.openCursor(n.range||null,n.dir+n.unique)}function o(n,t,e,r,o){var u=n.replayFilter?Pn(n.filter,n.replayFilter()):n.filter;n.or?!function(){function c(){2===++f&&e()}function a(n,e,i){if(!u||u(e,i,c,r)){var o=e.primaryKey.toString();s.hasOwnProperty(o)||(s[o]=!0,t(n,e,i))}}var s={},f=0;n.or._iterate(a,c,r,o),dn(i(n,o),n.algorithm,a,c,r,!n.keysOnly&&n.valueFilter)}():dn(i(n,o),Pn(n.algorithm,u),t,e,r,!n.keysOnly&&n.valueFilter)}function u(n){return n.table.schema.instanceTemplate}return{_read:function(n,t){var e=this._ctx;return e.error?e.table._trans(null,function(n,t){t(e.error)}):e.table._idbstore(Xn,n).then(t)},_write:function(n){var t=this._ctx;return t.error?t.table._trans(null,function(n,e){e(t.error)}):t.table._idbstore(Zn,n,"locked")},_addAlgorithm:function(n){var t=this._ctx;t.algorithm=Pn(t.algorithm,n)},_iterate:function(n,t,e,r){return o(this._ctx,n,t,e,r)},clone:function(n){var t=Object.create(this.constructor.prototype),e=Object.create(this._ctx);return n&&f(e,n),t._ctx=e,t},raw:function(){return this._ctx.valueFilter=null,this},each:function(n){var t=this._ctx;return Tn&&n(u(t)),this._read(function(e,r,i){o(t,n,e,r,i)})},count:function(n){if(Tn)return B.resolve(0).then(n);var t=this,e=this._ctx;if(e.filter||e.algorithm||e.or||e.replayFilter){var i=0;return this._read(function(n,t,r){o(e,function(){return++i,!1},function(){n(i)},t,r)},n)}return this._read(function(n,i,o){var u=r(e,o),c=e.range?u.count(e.range):u.count();c.onerror=Q(i,["calling","count()","on",t.name]),c.onsuccess=function(t){n(t.target.result)}},n)},sortBy:function(n,t){function e(n,t){return t?e(n[i[t]],t-1):n[o]}function r(n,t){var r=e(n,u),i=e(t,u);return i>r?-c:r>i?c:0}var i=n.split(".").reverse(),o=i[0],u=i.length-1,c="next"===this._ctx.dir?1:-1;return this.toArray(function(n){return n.sort(r)}).then(t)},toArray:function(n){var t=this._ctx;return this._read(function(n,e,r){Tn&&n([u(t)]);var i=[];o(t,function(n){i.push(n)},function(){n(i)},e,r)},n)},offset:function(n){var e=this._ctx;return 0>=n?this:(e.offset+=n,e.or||e.algorithm||e.filter||e.replayFilter?t(e,function(){var t=n;return function(){return--t<0}}):t(e,function(){var t=n;return function(n,e){return 0===t?!0:1===t?(--t,!1):(e(function(){n.advance(t),t=0}),!1)}}),this)},limit:function(n){return this._ctx.limit=Math.min(this._ctx.limit,n),t(this._ctx,function(){var t=n;return function(n,e,r){return--t<=0&&e(r),t>=0}}),this},until:function(t,e){var r=this._ctx;return Tn&&t(u(r)),n(this._ctx,function(n,r,i){return t(n.value)?(r(i),e):!0}),this},first:function(n){return this.limit(1).toArray(function(n){return n[0]}).then(n)},last:function(n){return this.reverse().first(n)},filter:function(t){return Tn&&t(u(this._ctx)),n(this._ctx,function(n){return t(n.value)}),e(this._ctx,t),this},and:function(n){return this.filter(n)},or:function(n){return new cn(this._ctx.table,n,this)},reverse:function(){return this._ctx.dir="prev"===this._ctx.dir?"next":"prev",this._ondirectionchange&&this._ondirectionchange(this._ctx.dir),this},desc:function(){return this.reverse()},eachKey:function(n){var t=this._ctx;return Tn&&n(P(u(this._ctx),this._ctx.index?this._ctx.table.schema.idxByName[this._ctx.index].keyPath:this._ctx.table.schema.primKey.keyPath)),t.keysOnly=!t.isMatch,this.each(function(t,e){n(e.key,e)})},eachUniqueKey:function(n){return this._ctx.unique="unique",this.eachKey(n)},keys:function(n){var t=this._ctx;t.keysOnly=!t.isMatch;var e=[];return Tn?new B(this.eachKey.bind(this)).then(function(n){return[n]}).then(n):this.each(function(n,t){e.push(t.key)}).then(function(){return e}).then(n)},uniqueKeys:function(n){return this._ctx.unique="unique",this.keys(n)},firstKey:function(n){return this.limit(1).keys(function(n){return n[0]}).then(n)},lastKey:function(n){return this.reverse().firstKey(n)},distinct:function(){var t=this._ctx,e=t.index&&t.table.schema.idxByName[t.index];if(!e||!e.multi)return this;var r={};return n(this._ctx,function(n){var t=n.primaryKey.toString(),e=r.hasOwnProperty(t);return r[t]=!0,!e}),this}}}),d(sn).from(an).extend({modify:function(t){var e=this,r=this._ctx,i=r.table.hook,o=i.updating.fire,u=i.deleting.fire;return Tn&&"function"==typeof t&&t.call({value:r.table.schema.instanceTemplate},r.table.schema.instanceTemplate),this._write(function(i,c,a,s){function l(n,t){function e(n){return x.push(n),D.push(i.primKey),i.onerror&&B.newPSD(function(){B.PSD.trans=s,i.onerror(n)}),d(),!0}I=t.primaryKey;var i={primKey:t.primaryKey,value:n,onsuccess:null,onerror:null};if(p.call(i,n,i)!==!1){var o=!i.hasOwnProperty("value");++g,b(function(){var u=o?t["delete"]():t.update(i.value);u.onerror=Q(e,o?["deleting",n,"from",r.table.name]:["modifying",n,"on",r.table.name]),u.onsuccess=function(){i.onsuccess&&B.newPSD(function(){B.PSD.trans=s,i.onsuccess(i.value)}),++w,d()}},e)}else i.onsuccess&&i.onsuccess(i.value)}function h(n){return n&&(x.push(n),D.push(I)),c(new A("Error modifying one or more objects",x,w,D))}function d(){_&&w+x.length===g&&(x.length>0?h():i(w))}var p;if("function"==typeof t)p=o===n&&u===n?t:function(n){var e=O(n);if(t.call(this,n,this)===!1)return!1;if(this.hasOwnProperty("value")){var r=E(e,this.value),i=o.call(this,r,this.primKey,e,s);i&&(n=this.value,on(i).forEach(function(t){k(n,t,i[t])}))}else u.call(this,this.primKey,n,s)};else if(o===n){var v=on(t),y=v.length;p=function(n){for(var e=!1,r=0;y>r;++r){var i=v[r],o=t[i];P(n,i)!==o&&(k(n,i,o),e=!0)}return e}}else{var m=t;t=S(m),p=function(n){var e=!1,r=o.call(this,t,this.primKey,O(n),s);return r&&f(t,r),on(t).forEach(function(r){var i=t[r];P(n,r)!==i&&(k(n,r,i),e=!0)}),r&&(t=S(m)),e}}var g=0,w=0,_=!1,x=[],D=[],I=null;e.clone().raw()._iterate(l,function(){_=!0,d()},h,a)})},"delete":function(){var t=this,e=this._ctx,r=e.range,i=e.table.hook.deleting.fire,o=i!==n;if(!o&&!e.or&&!e.algorithm&&!e.filter&&!e.replayFilter&&(e.isPrimKey&&!An||!r))return this._write(function(n,t,i){var o=Q(t,["deleting range from",e.table.name]),u=r?i.count(r):i.count();u.onerror=o,u.onsuccess=function(){var e=u.result;b(function(){var t=r?i["delete"](r):i.clear();t.onerror=o,t.onsuccess=function(){return n(e)}},function(n){return t(T(n))})}});var u=o?2e3:1e4;return this._write(function(n,r,c,a){var s=0,f=Object.create(e.table);f._tpf=a._tpf;var l=t.clone({table:f,keysOnly:!e.isMatch&&!o}).distinct().limit(u).raw(),h=[],d=function(){return l.each(o?function(n,t){h.push([t.primaryKey,t.value])}:function(n,t){h.push(t.primaryKey)}).then(function(){return o?h.sort(function(n,t){return bn(n[0],t[0])}):h.sort(bn),z(c,a,h,o,i)}).then(function(){var n=h.length;return s+=n,h=[],u>n?s:d()})};n(d())})}}),f(this,{Collection:an,Table:M,Transaction:G,Version:m,WhereClause:cn,WriteableCollection:sn,WriteableTable:U}),y(),Rn.forEach(function(n){n($n)})}function J(n,t){var e=B.PSD;return function(){var r=B.PSD;B.PSD=e;try{n.apply(this,arguments)}catch(i){t(i)}finally{B.PSD=r}}}function G(n){if("function"==typeof n)return new n;if(un(n))return[G(n[0])];if(n&&"object"==typeof n){var t={};return Y(t,n),t}return n}function Y(n,t){return on(t).forEach(function(e){var r=G(t[e]);n[e]=r}),n}function Q(n,t){return function(e){var r=e&&e.target.error||new Error("");if(t){var i=" occurred when "+t.map(function(n){switch(typeof n){case"function":return n();case"string":return n;default:return JSON.stringify(n)}}).join(" ");r.message&&r.message!=r.name&&(i+=". "+r.message),r.name?r=T(r,r.name+i):r+=i}return n(r),e&&(e.stopPropagation&&e.stopPropagation(),e.preventDefault&&e.preventDefault()),!1}}function X(n){n.preventDefault()}function Z(n){var t,e=H.dependencies.localStorage;if(!e)return n([]);try{t=JSON.parse(e.getItem("Dexie.DatabaseNames")||"[]")}catch(r){t=[]}n(t)&&e.setItem("Dexie.DatabaseNames",JSON.stringify(t))}function $(n){function t(n){return function(t){var r=n(t),i=r.value;return r.done?i:i&&"function"==typeof i.then?i.then(o,u):Array.isArray(i)?e(i,0):o(i)}}function e(n,t){if(t===n.length)return o(n);var r=n[t];return r.constructor&&"function"==typeof r.constructor.all?r.constructor.all(n).then(o,u):e(n,t+1)}var r=function(t){return n.next(t)},i=function(t){return n["throw"](t)},o=t(r),u=t(i);return t(r)()}function nn(n,t,e,r,i,o,u){this.name=n,this.keyPath=t,this.unique=e,this.multi=r,this.auto=i,this.compound=o,this.dotted=u;var c="string"==typeof t?t:t&&"["+[].join.call(t,"+")+"]";this.src=(e?"&":"")+(r?"*":"")+(i?"++":"")+c}function tn(n,t,e,r){this.name=n,this.primKey=t||new nn,this.indexes=e||[new nn],this.instanceTemplate=r,this.mappedClass=null,this.idxByName=e.reduce(function(n,t){return n[t.name]=t,n},{})}function en(n){return 1===n.length?n[0]:n}function rn(n){var t=n&&(n.getDatabaseNames||n.webkitGetDatabaseNames);return t&&t.bind(n)}var on=Object.keys,un=Array.isArray,cn="undefined"!=typeof self?self:"undefined"!=typeof window?window:global,an=[].slice,sn=["Modify","Bulk","OpenFailed","VersionChange","Schema","Upgrade","InvalidTable","MissingAPI","NoSuchDatabase","InvalidArgument","SubTransaction","Unsupported","Internal","DatabaseClosed","IncompatiblePromise"],fn=["Unknown","Constraint","Data","TransactionInactive","ReadOnly","Version","NotFound","InvalidState","InvalidAccess","Abort","Timeout","QuotaExceeded","Syntax","DataClone"],ln=sn.concat(fn),hn={VersionChanged:"Database version changed by other database connection",DatabaseClosed:"Database has been closed",IncompatiblePromise:"Incompatible Promise used in transaction scope. See http://tinyurl.com/znyqjqc"};d(I).from(Error).extend({dump:function(){return w(this)}}),d(A).from(I),d(j).from(I);var dn=ln.reduce(function(n,t){return n[t]=t+"Error",n},{}),pn=I,vn=ln.reduce(function(n,t){function e(n,e){this.name=r,"string"==typeof n?(this.message=n,this.inner=e||null):"object"==typeof n?(this.message=n.name+" "+n.message,this.inner=n):(this.message=hn[t],this.inner=null)}var r=t+"Error";return d(e).from(pn),n[t]=e,n},{});vn.Syntax=SyntaxError,vn.Type=TypeError,vn.Range=RangeError;var yn=fn.reduce(function(n,t){return n[t+"Error"]=vn[t],n},{}),mn=ln.reduce(function(n,t){return-1===["Syntax","Type","Range"].indexOf(t)&&(n[t+"Error"]=vn[t]),n},{});mn.ModifyError=A,mn.DexieError=I,mn.BulkError=j;var gn=cn.setImmediate||function(n){var t=p(arguments,1);setTimeout(function(){n.apply(cn,t)},0)};y(function(){gn=bn=Pn=function(n){var t=arguments;setTimeout(function(){n.apply(cn,p(t,1))},0)}});var bn=gn,wn=!0,_n=[],xn=[],Pn=function(n){_n.push([n,p(arguments,1)])};B.all=function(){var n=p(1===arguments.length&&un(arguments[0])?arguments[0]:arguments);return new B(function(t,e){function r(o,u){try{if(u&&("object"==typeof u||"function"==typeof u)){var c=u.then;if("function"==typeof c)return void c.call(u,function(n){r(o,n)},e)}n[o]=u,0===--i&&t(n)}catch(a){e(a)}}if(0===n.length)return t([]);for(var i=n.length,o=0;o