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/. */
11 dump("-*- IndexedDBHelper: " + s + "\n");
14 debug = function(s) {};
17 var EXPORTED_SYMBOLS = ["IndexedDBHelper"];
19 Cu.importGlobalProperties(["indexedDB"]);
21 ChromeUtils.defineModuleGetter(
24 "resource://gre/modules/Services.jsm"
27 function getErrorName(err) {
28 return (err && err.name) || "UnknownError";
31 function IndexedDBHelper() {}
33 IndexedDBHelper.prototype = {
35 close: function close() {
43 * Open a new database.
44 * User has to provide upgradeSchema.
47 * Success callback to call once database is open.
49 * Error callback to call when an error is encountered.
51 open: function open(aCallback) {
52 if (aCallback && !this._waitForOpenCallbacks.has(aCallback)) {
53 this._waitForOpenCallbacks.add(aCallback);
54 if (this._waitForOpenCallbacks.size !== 1) {
60 let invokeCallbacks = err => {
61 for (let callback of self._waitForOpenCallbacks) {
64 self._waitForOpenCallbacks.clear();
68 debug("Try to open database:" + self.dbName + " " + self.dbVersion);
72 req = indexedDB.open(this.dbName, this.dbVersion);
75 debug("Error opening database: " + self.dbName);
77 Services.tm.dispatchToMainThread(() => invokeCallbacks(getErrorName(e)));
80 req.onsuccess = function(event) {
82 debug("Opened database:" + self.dbName + " " + self.dbVersion);
84 self._db = event.target.result;
85 self._db.onversionchange = function(event) {
87 debug("WARNING: DB modified from a different window.");
93 req.onupgradeneeded = function(aEvent) {
96 "Database needs upgrade:" +
102 "Correct new database version:" +
103 (aEvent.newVersion == this.dbVersion)
107 let _db = aEvent.target.result;
115 req.onerror = function(aEvent) {
117 debug("Failed to open database: " + self.dbName);
119 invokeCallbacks(getErrorName(aEvent.target.error));
121 req.onblocked = function(aEvent) {
123 debug("Opening database request is blocked.");
129 * Use the cached DB or open a new one.
132 * Success callback to call.
134 * Error callback to call when an error is encountered.
136 ensureDB: function ensureDB(aSuccessCb, aFailureCb) {
139 debug("ensureDB: already have a database, returning early.");
142 Services.tm.dispatchToMainThread(aSuccessCb);
146 this.open(aError => {
148 aFailureCb && aFailureCb(aError);
150 aSuccessCb && aSuccessCb();
156 * Start a new transaction.
159 * Type of transaction (e.g. "readwrite")
161 * The object store you want to be passed to the callback
163 * Function to call when the transaction is available. It will
164 * be invoked with the transaction and the `store' object store.
166 * Success callback to call on a successful transaction commit.
167 * The result is stored in txn.result (in the callback function).
169 * Error callback to call when an error is encountered.
171 newTxn: function newTxn(
178 this.ensureDB(() => {
180 debug("Starting new transaction" + txn_type);
184 txn = this._db.transaction(
185 Array.isArray(store_name) ? store_name : this.dbStoreNames,
190 debug("Error starting transaction: " + this.dbName);
192 failureCb(getErrorName(e));
196 debug("Retrieving object store: " + this.dbName);
199 if (Array.isArray(store_name)) {
201 for (let i = 0; i < store_name.length; ++i) {
202 stores.push(txn.objectStore(store_name[i]));
205 stores = txn.objectStore(store_name);
208 txn.oncomplete = function() {
210 debug("Transaction complete. Returning to callback.");
213 * txn.result property is not part of the transaction object returned
214 * by this._db.transaction method called above.
215 * The property is expected to be set in the callback function.
216 * However, it can happen that the property is not set for some reason,
217 * so we have to check if the property exists before calling the
221 if ("result" in txn) {
222 successCb(txn.result);
229 txn.onabort = function() {
231 debug("Caught error on transaction");
234 * txn.error property is part of the transaction object returned by
235 * this._db.transaction method called above.
236 * The attribute is defined in IDBTranscation WebIDL interface.
240 failureCb(getErrorName(txn.error));
243 callback(txn, stores);
248 * Initialize the DB. Does not call open.
251 * DB name for the open call.
253 * Current DB version. User has to implement upgradeSchema.
254 * @param aDBStoreName
255 * ObjectStore that is used.
257 initDBHelper: function initDBHelper(aDBName, aDBVersion, aDBStoreNames) {
258 this.dbName = aDBName;
259 this.dbVersion = aDBVersion;
260 this.dbStoreNames = aDBStoreNames;
261 // Cache the database.
263 this._waitForOpenCallbacks = new Set();