forked from mirrors/gecko-dev
		
	 f52cea06ac
			
		
	
	
		f52cea06ac
		
	
	
	
	
		
			
			# ignore-this-changeset These are all automatic changes via ESLint/prettier. Differential Revision: https://phabricator.services.mozilla.com/D37978 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			265 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			265 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 | |
|  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| "use strict";
 | |
| 
 | |
| var DEBUG = 0;
 | |
| var debug;
 | |
| if (DEBUG) {
 | |
|   debug = function(s) {
 | |
|     dump("-*- IndexedDBHelper: " + s + "\n");
 | |
|   };
 | |
| } else {
 | |
|   debug = function(s) {};
 | |
| }
 | |
| 
 | |
| var EXPORTED_SYMBOLS = ["IndexedDBHelper"];
 | |
| 
 | |
| Cu.importGlobalProperties(["indexedDB"]);
 | |
| 
 | |
| ChromeUtils.defineModuleGetter(
 | |
|   this,
 | |
|   "Services",
 | |
|   "resource://gre/modules/Services.jsm"
 | |
| );
 | |
| 
 | |
| function getErrorName(err) {
 | |
|   return (err && err.name) || "UnknownError";
 | |
| }
 | |
| 
 | |
| function IndexedDBHelper() {}
 | |
| 
 | |
| IndexedDBHelper.prototype = {
 | |
|   // Close the database
 | |
|   close: function close() {
 | |
|     if (this._db) {
 | |
|       this._db.close();
 | |
|       this._db = null;
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Open a new database.
 | |
|    * User has to provide upgradeSchema.
 | |
|    *
 | |
|    * @param successCb
 | |
|    *        Success callback to call once database is open.
 | |
|    * @param failureCb
 | |
|    *        Error callback to call when an error is encountered.
 | |
|    */
 | |
|   open: function open(aCallback) {
 | |
|     if (aCallback && !this._waitForOpenCallbacks.has(aCallback)) {
 | |
|       this._waitForOpenCallbacks.add(aCallback);
 | |
|       if (this._waitForOpenCallbacks.size !== 1) {
 | |
|         return;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     let self = this;
 | |
|     let invokeCallbacks = err => {
 | |
|       for (let callback of self._waitForOpenCallbacks) {
 | |
|         callback(err);
 | |
|       }
 | |
|       self._waitForOpenCallbacks.clear();
 | |
|     };
 | |
| 
 | |
|     if (DEBUG) {
 | |
|       debug("Try to open database:" + self.dbName + " " + self.dbVersion);
 | |
|     }
 | |
|     let req;
 | |
|     try {
 | |
|       req = indexedDB.open(this.dbName, this.dbVersion);
 | |
|     } catch (e) {
 | |
|       if (DEBUG) {
 | |
|         debug("Error opening database: " + self.dbName);
 | |
|       }
 | |
|       Services.tm.dispatchToMainThread(() => invokeCallbacks(getErrorName(e)));
 | |
|       return;
 | |
|     }
 | |
|     req.onsuccess = function(event) {
 | |
|       if (DEBUG) {
 | |
|         debug("Opened database:" + self.dbName + " " + self.dbVersion);
 | |
|       }
 | |
|       self._db = event.target.result;
 | |
|       self._db.onversionchange = function(event) {
 | |
|         if (DEBUG) {
 | |
|           debug("WARNING: DB modified from a different window.");
 | |
|         }
 | |
|       };
 | |
|       invokeCallbacks();
 | |
|     };
 | |
| 
 | |
|     req.onupgradeneeded = function(aEvent) {
 | |
|       if (DEBUG) {
 | |
|         debug(
 | |
|           "Database needs upgrade:" +
 | |
|             self.dbName +
 | |
|             aEvent.oldVersion +
 | |
|             aEvent.newVersion
 | |
|         );
 | |
|         debug(
 | |
|           "Correct new database version:" +
 | |
|             (aEvent.newVersion == this.dbVersion)
 | |
|         );
 | |
|       }
 | |
| 
 | |
|       let _db = aEvent.target.result;
 | |
|       self.upgradeSchema(
 | |
|         req.transaction,
 | |
|         _db,
 | |
|         aEvent.oldVersion,
 | |
|         aEvent.newVersion
 | |
|       );
 | |
|     };
 | |
|     req.onerror = function(aEvent) {
 | |
|       if (DEBUG) {
 | |
|         debug("Failed to open database: " + self.dbName);
 | |
|       }
 | |
|       invokeCallbacks(getErrorName(aEvent.target.error));
 | |
|     };
 | |
|     req.onblocked = function(aEvent) {
 | |
|       if (DEBUG) {
 | |
|         debug("Opening database request is blocked.");
 | |
|       }
 | |
|     };
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Use the cached DB or open a new one.
 | |
|    *
 | |
|    * @param successCb
 | |
|    *        Success callback to call.
 | |
|    * @param failureCb
 | |
|    *        Error callback to call when an error is encountered.
 | |
|    */
 | |
|   ensureDB: function ensureDB(aSuccessCb, aFailureCb) {
 | |
|     if (this._db) {
 | |
|       if (DEBUG) {
 | |
|         debug("ensureDB: already have a database, returning early.");
 | |
|       }
 | |
|       if (aSuccessCb) {
 | |
|         Services.tm.dispatchToMainThread(aSuccessCb);
 | |
|       }
 | |
|       return;
 | |
|     }
 | |
|     this.open(aError => {
 | |
|       if (aError) {
 | |
|         aFailureCb && aFailureCb(aError);
 | |
|       } else {
 | |
|         aSuccessCb && aSuccessCb();
 | |
|       }
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Start a new transaction.
 | |
|    *
 | |
|    * @param txn_type
 | |
|    *        Type of transaction (e.g. "readwrite")
 | |
|    * @param store_name
 | |
|    *        The object store you want to be passed to the callback
 | |
|    * @param callback
 | |
|    *        Function to call when the transaction is available. It will
 | |
|    *        be invoked with the transaction and the `store' object store.
 | |
|    * @param successCb
 | |
|    *        Success callback to call on a successful transaction commit.
 | |
|    *        The result is stored in txn.result (in the callback function).
 | |
|    * @param failureCb
 | |
|    *        Error callback to call when an error is encountered.
 | |
|    */
 | |
|   newTxn: function newTxn(
 | |
|     txn_type,
 | |
|     store_name,
 | |
|     callback,
 | |
|     successCb,
 | |
|     failureCb
 | |
|   ) {
 | |
|     this.ensureDB(() => {
 | |
|       if (DEBUG) {
 | |
|         debug("Starting new transaction" + txn_type);
 | |
|       }
 | |
|       let txn;
 | |
|       try {
 | |
|         txn = this._db.transaction(
 | |
|           Array.isArray(store_name) ? store_name : this.dbStoreNames,
 | |
|           txn_type
 | |
|         );
 | |
|       } catch (e) {
 | |
|         if (DEBUG) {
 | |
|           debug("Error starting transaction: " + this.dbName);
 | |
|         }
 | |
|         failureCb(getErrorName(e));
 | |
|         return;
 | |
|       }
 | |
|       if (DEBUG) {
 | |
|         debug("Retrieving object store: " + this.dbName);
 | |
|       }
 | |
|       let stores;
 | |
|       if (Array.isArray(store_name)) {
 | |
|         stores = [];
 | |
|         for (let i = 0; i < store_name.length; ++i) {
 | |
|           stores.push(txn.objectStore(store_name[i]));
 | |
|         }
 | |
|       } else {
 | |
|         stores = txn.objectStore(store_name);
 | |
|       }
 | |
| 
 | |
|       txn.oncomplete = function() {
 | |
|         if (DEBUG) {
 | |
|           debug("Transaction complete. Returning to callback.");
 | |
|         }
 | |
|         /*
 | |
|          * txn.result property is not part of the transaction object returned
 | |
|          * by this._db.transaction method called above.
 | |
|          * The property is expected to be set in the callback function.
 | |
|          * However, it can happen that the property is not set for some reason,
 | |
|          * so we have to check if the property exists before calling the
 | |
|          * success callback.
 | |
|          */
 | |
|         if (successCb) {
 | |
|           if ("result" in txn) {
 | |
|             successCb(txn.result);
 | |
|           } else {
 | |
|             successCb();
 | |
|           }
 | |
|         }
 | |
|       };
 | |
| 
 | |
|       txn.onabort = function() {
 | |
|         if (DEBUG) {
 | |
|           debug("Caught error on transaction");
 | |
|         }
 | |
|         /*
 | |
|          * txn.error property is part of the transaction object returned by
 | |
|          * this._db.transaction method called above.
 | |
|          * The attribute is defined in IDBTranscation WebIDL interface.
 | |
|          * It may be null.
 | |
|          */
 | |
|         if (failureCb) {
 | |
|           failureCb(getErrorName(txn.error));
 | |
|         }
 | |
|       };
 | |
|       callback(txn, stores);
 | |
|     }, failureCb);
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Initialize the DB. Does not call open.
 | |
|    *
 | |
|    * @param aDBName
 | |
|    *        DB name for the open call.
 | |
|    * @param aDBVersion
 | |
|    *        Current DB version. User has to implement upgradeSchema.
 | |
|    * @param aDBStoreName
 | |
|    *        ObjectStore that is used.
 | |
|    */
 | |
|   initDBHelper: function initDBHelper(aDBName, aDBVersion, aDBStoreNames) {
 | |
|     this.dbName = aDBName;
 | |
|     this.dbVersion = aDBVersion;
 | |
|     this.dbStoreNames = aDBStoreNames;
 | |
|     // Cache the database.
 | |
|     this._db = null;
 | |
|     this._waitForOpenCallbacks = new Set();
 | |
|   },
 | |
| };
 |