1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/base/IndexedDBHelper.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,168 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +let DEBUG = 0; 1.11 +let debug; 1.12 +if (DEBUG) { 1.13 + debug = function (s) { dump("-*- IndexedDBHelper: " + s + "\n"); } 1.14 +} else { 1.15 + debug = function (s) {} 1.16 +} 1.17 + 1.18 +const Cu = Components.utils; 1.19 +const Cc = Components.classes; 1.20 +const Ci = Components.interfaces; 1.21 + 1.22 +this.EXPORTED_SYMBOLS = ["IndexedDBHelper"]; 1.23 + 1.24 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.25 +Cu.import("resource://gre/modules/Services.jsm"); 1.26 +Cu.importGlobalProperties(["indexedDB"]); 1.27 + 1.28 +this.IndexedDBHelper = function IndexedDBHelper() {} 1.29 + 1.30 +IndexedDBHelper.prototype = { 1.31 + 1.32 + // Cache the database 1.33 + _db: null, 1.34 + 1.35 + // Close the database 1.36 + close: function close() { 1.37 + if (this._db) { 1.38 + this._db.close(); 1.39 + this._db = null; 1.40 + } 1.41 + }, 1.42 + 1.43 + /** 1.44 + * Open a new database. 1.45 + * User has to provide upgradeSchema. 1.46 + * 1.47 + * @param successCb 1.48 + * Success callback to call once database is open. 1.49 + * @param failureCb 1.50 + * Error callback to call when an error is encountered. 1.51 + */ 1.52 + open: function open(aSuccessCb, aFailureCb) { 1.53 + let self = this; 1.54 + if (DEBUG) debug("Try to open database:" + self.dbName + " " + self.dbVersion); 1.55 + let req = indexedDB.open(this.dbName, this.dbVersion); 1.56 + req.onsuccess = function (event) { 1.57 + if (DEBUG) debug("Opened database:" + self.dbName + " " + self.dbVersion); 1.58 + self._db = event.target.result; 1.59 + self._db.onversionchange = function(event) { 1.60 + if (DEBUG) debug("WARNING: DB modified from a different window."); 1.61 + } 1.62 + aSuccessCb && aSuccessCb(); 1.63 + }; 1.64 + 1.65 + req.onupgradeneeded = function (aEvent) { 1.66 + if (DEBUG) { 1.67 + debug("Database needs upgrade:" + self.dbName + aEvent.oldVersion + aEvent.newVersion); 1.68 + debug("Correct new database version:" + (aEvent.newVersion == this.dbVersion)); 1.69 + } 1.70 + 1.71 + let _db = aEvent.target.result; 1.72 + self.upgradeSchema(req.transaction, _db, aEvent.oldVersion, aEvent.newVersion); 1.73 + }; 1.74 + req.onerror = function (aEvent) { 1.75 + if (DEBUG) debug("Failed to open database: " + self.dbName); 1.76 + aFailureCb && aFailureCb(aEvent.target.error.name); 1.77 + }; 1.78 + req.onblocked = function (aEvent) { 1.79 + if (DEBUG) debug("Opening database request is blocked."); 1.80 + }; 1.81 + }, 1.82 + 1.83 + /** 1.84 + * Use the cached DB or open a new one. 1.85 + * 1.86 + * @param successCb 1.87 + * Success callback to call. 1.88 + * @param failureCb 1.89 + * Error callback to call when an error is encountered. 1.90 + */ 1.91 + ensureDB: function ensureDB(aSuccessCb, aFailureCb) { 1.92 + if (this._db) { 1.93 + if (DEBUG) debug("ensureDB: already have a database, returning early."); 1.94 + aSuccessCb && aSuccessCb(); 1.95 + return; 1.96 + } 1.97 + this.open(aSuccessCb, aFailureCb); 1.98 + }, 1.99 + 1.100 + /** 1.101 + * Start a new transaction. 1.102 + * 1.103 + * @param txn_type 1.104 + * Type of transaction (e.g. "readwrite") 1.105 + * @param store_name 1.106 + * The object store you want to be passed to the callback 1.107 + * @param callback 1.108 + * Function to call when the transaction is available. It will 1.109 + * be invoked with the transaction and the `store' object store. 1.110 + * @param successCb 1.111 + * Success callback to call on a successful transaction commit. 1.112 + * The result is stored in txn.result. 1.113 + * @param failureCb 1.114 + * Error callback to call when an error is encountered. 1.115 + */ 1.116 + newTxn: function newTxn(txn_type, store_name, callback, successCb, failureCb) { 1.117 + this.ensureDB(function () { 1.118 + if (DEBUG) debug("Starting new transaction" + txn_type); 1.119 + let txn = this._db.transaction(Array.isArray(store_name) ? store_name : this.dbStoreNames, txn_type); 1.120 + if (DEBUG) debug("Retrieving object store", this.dbName); 1.121 + let stores; 1.122 + if (Array.isArray(store_name)) { 1.123 + stores = []; 1.124 + for (let i = 0; i < store_name.length; ++i) { 1.125 + stores.push(txn.objectStore(store_name[i])); 1.126 + } 1.127 + } else { 1.128 + stores = txn.objectStore(store_name); 1.129 + } 1.130 + 1.131 + txn.oncomplete = function (event) { 1.132 + if (DEBUG) debug("Transaction complete. Returning to callback."); 1.133 + if (successCb) { 1.134 + successCb(txn.result); 1.135 + } 1.136 + }; 1.137 + 1.138 + txn.onabort = function (event) { 1.139 + if (DEBUG) debug("Caught error on transaction"); 1.140 + /* 1.141 + * event.target.error may be null 1.142 + * if txn was aborted by calling txn.abort() 1.143 + */ 1.144 + if (failureCb) { 1.145 + if (event.target.error) { 1.146 + failureCb(event.target.error.name); 1.147 + } else { 1.148 + failureCb("UnknownError"); 1.149 + } 1.150 + } 1.151 + }; 1.152 + callback(txn, stores); 1.153 + }.bind(this), failureCb); 1.154 + }, 1.155 + 1.156 + /** 1.157 + * Initialize the DB. Does not call open. 1.158 + * 1.159 + * @param aDBName 1.160 + * DB name for the open call. 1.161 + * @param aDBVersion 1.162 + * Current DB version. User has to implement upgradeSchema. 1.163 + * @param aDBStoreName 1.164 + * ObjectStore that is used. 1.165 + */ 1.166 + initDBHelper: function initDBHelper(aDBName, aDBVersion, aDBStoreNames) { 1.167 + this.dbName = aDBName; 1.168 + this.dbVersion = aDBVersion; 1.169 + this.dbStoreNames = aDBStoreNames; 1.170 + } 1.171 +}