1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
9 dump("-*- IndexedDBHelper: " + s + "\n");
12 debug = function (s) {};
15 function getErrorName(err) {
16 return (err && err.name) || "UnknownError";
19 export function IndexedDBHelper() {}
21 IndexedDBHelper.prototype = {
23 close: function close() {
31 * Open a new database.
32 * User has to provide upgradeSchema.
35 * Success callback to call once database is open.
37 * Error callback to call when an error is encountered.
39 open: function open(aCallback) {
40 if (aCallback && !this._waitForOpenCallbacks.has(aCallback)) {
41 this._waitForOpenCallbacks.add(aCallback);
42 if (this._waitForOpenCallbacks.size !== 1) {
48 let invokeCallbacks = err => {
49 for (let callback of self._waitForOpenCallbacks) {
52 self._waitForOpenCallbacks.clear();
56 debug("Try to open database:" + self.dbName + " " + self.dbVersion);
60 req = indexedDB.open(this.dbName, this.dbVersion);
63 debug("Error opening database: " + self.dbName);
65 Services.tm.dispatchToMainThread(() => invokeCallbacks(getErrorName(e)));
68 req.onsuccess = function (event) {
70 debug("Opened database:" + self.dbName + " " + self.dbVersion);
72 self._db = event.target.result;
73 self._db.onversionchange = function (event) {
75 debug("WARNING: DB modified from a different window.");
81 req.onupgradeneeded = function (aEvent) {
84 "Database needs upgrade:" +
90 "Correct new database version:" +
91 (aEvent.newVersion == this.dbVersion)
95 let _db = aEvent.target.result;
103 req.onerror = function (aEvent) {
105 debug("Failed to open database: " + self.dbName);
107 invokeCallbacks(getErrorName(aEvent.target.error));
109 req.onblocked = function (aEvent) {
111 debug("Opening database request is blocked.");
117 * Use the cached DB or open a new one.
120 * Success callback to call.
122 * Error callback to call when an error is encountered.
124 ensureDB: function ensureDB(aSuccessCb, aFailureCb) {
127 debug("ensureDB: already have a database, returning early.");
130 Services.tm.dispatchToMainThread(aSuccessCb);
134 this.open(aError => {
136 aFailureCb && aFailureCb(aError);
138 aSuccessCb && aSuccessCb();
144 * Start a new transaction.
147 * Type of transaction (e.g. "readwrite")
149 * The object store you want to be passed to the callback
151 * Function to call when the transaction is available. It will
152 * be invoked with the transaction and the `store' object store.
154 * Success callback to call on a successful transaction commit.
155 * The result is stored in txn.result (in the callback function).
157 * Error callback to call when an error is encountered.
159 newTxn: function newTxn(
166 this.ensureDB(() => {
168 debug("Starting new transaction" + txn_type);
172 txn = this._db.transaction(
173 Array.isArray(store_name) ? store_name : this.dbStoreNames,
178 debug("Error starting transaction: " + this.dbName);
180 failureCb(getErrorName(e));
184 debug("Retrieving object store: " + this.dbName);
187 if (Array.isArray(store_name)) {
189 for (let i = 0; i < store_name.length; ++i) {
190 stores.push(txn.objectStore(store_name[i]));
193 stores = txn.objectStore(store_name);
196 txn.oncomplete = function () {
198 debug("Transaction complete. Returning to callback.");
201 * txn.result property is not part of the transaction object returned
202 * by this._db.transaction method called above.
203 * The property is expected to be set in the callback function.
204 * However, it can happen that the property is not set for some reason,
205 * so we have to check if the property exists before calling the
209 if ("result" in txn) {
210 successCb(txn.result);
217 txn.onabort = function () {
219 debug("Caught error on transaction");
222 * txn.error property is part of the transaction object returned by
223 * this._db.transaction method called above.
224 * The attribute is defined in IDBTranscation WebIDL interface.
228 failureCb(getErrorName(txn.error));
231 callback(txn, stores);
236 * Initialize the DB. Does not call open.
239 * DB name for the open call.
241 * Current DB version. User has to implement upgradeSchema.
242 * @param aDBStoreName
243 * ObjectStore that is used.
245 initDBHelper: function initDBHelper(aDBName, aDBVersion, aDBStoreNames) {
246 this.dbName = aDBName;
247 this.dbVersion = aDBVersion;
248 this.dbStoreNames = aDBStoreNames;
249 // Cache the database.
251 this._waitForOpenCallbacks = new Set();