Bug 836513 - Support multiple object stores in IndexedDBHelper.jsm. r=gwagner
authorReuben Morais <reuben.morais@gmail.com>
Wed, 30 Jan 2013 18:03:46 -0800
changeset 120423 66068b93679090f8accca08b5844ec6384dd592e
parent 120422 f59f66def52517f0d9c91828c920fd3231cdfd71
child 120424 25c7af76b27408269a0acdd8c0c5305030215c90
push id24251
push userryanvm@gmail.com
push dateThu, 31 Jan 2013 20:56:22 +0000
treeherdermozilla-central@683b08dc1afd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgwagner
bugs836513
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 836513 - Support multiple object stores in IndexedDBHelper.jsm. r=gwagner
dom/activities/src/ActivitiesService.jsm
dom/alarm/AlarmDB.jsm
dom/base/IndexedDBHelper.jsm
dom/contacts/fallback/ContactDB.jsm
dom/network/src/NetworkStatsDB.jsm
dom/settings/SettingsDB.jsm
--- a/dom/activities/src/ActivitiesService.jsm
+++ b/dom/activities/src/ActivitiesService.jsm
@@ -35,17 +35,17 @@ function ActivitiesDb() {
 
 ActivitiesDb.prototype = {
   __proto__: IndexedDBHelper.prototype,
 
   init: function actdb_init() {
     let idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"]
                        .getService(Ci.nsIIndexedDatabaseManager);
     idbManager.initWindowless(idbGlobal);
-    this.initDBHelper(DB_NAME, DB_VERSION, STORE_NAME, idbGlobal);
+    this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME], idbGlobal);
   },
 
   /**
    * Create the initial database schema.
    *
    * The schema of records stored is as follows:
    *
    * {
@@ -83,49 +83,49 @@ ActivitiesDb.prototype = {
       hasher.update(data, data.length);
     });
 
     return hasher.finish(true);
   },
 
   // Add all the activities carried in the |aObjects| array.
   add: function actdb_add(aObjects, aSuccess, aError) {
-    this.newTxn("readwrite", function (txn, store) {
+    this.newTxn("readwrite", STORE_NAME, function (txn, store) {
       aObjects.forEach(function (aObject) {
         let object = {
           manifest: aObject.manifest,
           name: aObject.name,
           icon: aObject.icon || "",
           description: aObject.description
         };
         object.id = this.createId(object);
         debug("Going to add " + JSON.stringify(object));
         store.put(object);
       }, this);
     }.bind(this), aSuccess, aError);
   },
 
   // Remove all the activities carried in the |aObjects| array.
   remove: function actdb_remove(aObjects) {
-    this.newTxn("readwrite", function (txn, store) {
+    this.newTxn("readwrite", STORE_NAME, function (txn, store) {
       aObjects.forEach(function (aObject) {
         let object = {
           manifest: aObject.manifest,
           name: aObject.name
         };
         debug("Going to remove " + JSON.stringify(object));
         store.delete(this.createId(object));
       }, this);
     }.bind(this), function() {}, function() {});
   },
 
   find: function actdb_find(aObject, aSuccess, aError, aMatch) {
     debug("Looking for " + aObject.options.name);
 
-    this.newTxn("readonly", function (txn, store) {
+    this.newTxn("readonly", STORE_NAME, function (txn, store) {
       let index = store.index("name");
       let request = index.mozGetAll(aObject.options.name);
       request.onsuccess = function findSuccess(aEvent) {
         debug("Request successful. Record count: " + aEvent.target.result.length);
         if (!txn.result) {
           txn.result = {
             name: aObject.options.name,
             options: []
--- a/dom/alarm/AlarmDB.jsm
+++ b/dom/alarm/AlarmDB.jsm
@@ -29,17 +29,17 @@ this.AlarmDB = function AlarmDB(aGlobal)
 }
 
 AlarmDB.prototype = {
   __proto__: IndexedDBHelper.prototype,
 
   init: function init(aGlobal) {
     debug("init()");
 
-    this.initDBHelper(ALARMDB_NAME, ALARMDB_VERSION, ALARMSTORE_NAME, aGlobal);
+    this.initDBHelper(ALARMDB_NAME, ALARMDB_VERSION, [ALARMSTORE_NAME], aGlobal);
   },
 
   upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
     debug("upgradeSchema()");
 
     let objectStore = aDb.createObjectStore(ALARMSTORE_NAME, { keyPath: "id", autoIncrement: true });
 
     objectStore.createIndex("date",           "date",           { unique: false });
@@ -59,25 +59,26 @@ AlarmDB.prototype = {
    *        Callback function to invoke with result ID.
    * @param aErrorCb [optional]
    *        Callback function to invoke when there was an error.
    */
   add: function add(aAlarm, aSuccessCb, aErrorCb) {
     debug("add()");
 
     this.newTxn(
-      "readwrite", 
+      "readwrite",
+      ALARMSTORE_NAME,
       function txnCb(aTxn, aStore) {
         debug("Going to add " + JSON.stringify(aAlarm));
         aStore.put(aAlarm).onsuccess = function setTxnResult(aEvent) {
           aTxn.result = aEvent.target.result;
           debug("Request successful. New record ID: " + aTxn.result);
         };
       },
-      aSuccessCb, 
+      aSuccessCb,
       aErrorCb
     );
   },
 
   /**
    * @param aId
    *        The ID of record to be removed.
    * @param aManifestURL
@@ -88,17 +89,18 @@ AlarmDB.prototype = {
    *        Callback function to invoke with result.
    * @param aErrorCb [optional]
    *        Callback function to invoke when there was an error.
    */
   remove: function remove(aId, aManifestURL, aSuccessCb, aErrorCb) {
     debug("remove()");
 
     this.newTxn(
-      "readwrite", 
+      "readwrite",
+      ALARMSTORE_NAME,
       function txnCb(aTxn, aStore) {
         debug("Going to remove " + aId);
 
         // Look up the existing record and compare the manifestURL
         // to see if the alarm to be removed belongs to this app.
         aStore.get(aId).onsuccess = function doRemove(aEvent) {
           let alarm = aEvent.target.result;
 
@@ -109,18 +111,18 @@ AlarmDB.prototype = {
 
           if (aManifestURL && aManifestURL != alarm.manifestURL) {
             debug("Cannot remove the alarm added by other apps.");
             return;
           }
 
           aStore.delete(aId);
         };
-      }, 
-      aSuccessCb, 
+      },
+      aSuccessCb,
       aErrorCb
     );
   },
 
   /**
    * @param aManifestURL
    *        The manifest URL of the app that alarms belong to.
    *        If null, directly return all alarms; otherwise,
@@ -129,27 +131,28 @@ AlarmDB.prototype = {
    *        Callback function to invoke with result array.
    * @param aErrorCb [optional]
    *        Callback function to invoke when there was an error.
    */
   getAll: function getAll(aManifestURL, aSuccessCb, aErrorCb) {
     debug("getAll()");
 
     this.newTxn(
-      "readonly", 
+      "readonly",
+      ALARMSTORE_NAME,
       function txnCb(aTxn, aStore) {
         if (!aTxn.result)
           aTxn.result = [];
 
         aStore.mozGetAll().onsuccess = function setTxnResult(aEvent) {
           aEvent.target.result.forEach(function addAlarm(aAlarm) {
             if (!aManifestURL || aManifestURL == aAlarm.manifestURL)
               aTxn.result.push(aAlarm);
           });
 
           debug("Request successful. Record count: " + aTxn.result.length);
         };
-      }, 
-      aSuccessCb, 
+      },
+      aSuccessCb,
       aErrorCb
     );
   }
 };
--- a/dom/base/IndexedDBHelper.jsm
+++ b/dom/base/IndexedDBHelper.jsm
@@ -7,43 +7,43 @@
 let DEBUG = 0;
 let debug;
 if (DEBUG) {
   debug = function (s) { dump("-*- IndexedDBHelper: " + s + "\n"); }
 } else {
   debug = function (s) {}
 }
 
-const Cu = Components.utils; 
+const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 this.EXPORTED_SYMBOLS = ["IndexedDBHelper"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 this.IndexedDBHelper = function IndexedDBHelper() {}
 
 IndexedDBHelper.prototype = {
-  
+
   // Cache the database
   _db: null,
 
   // Close the database
   close: function close() {
     if (this._db) {
       this._db.close();
     }
   },
 
   /**
    * 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(aSuccessCb, aFailureCb) {
     let self = this;
     if (DEBUG) debug("Try to open database:" + self.dbName + " " + self.dbVersion);
@@ -72,51 +72,53 @@ IndexedDBHelper.prototype = {
     };
     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.");
       aSuccessCb();
       return;
     }
     this.open(aSuccessCb, aFailureCb);
   },
 
   /**
    * 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 'aDBStoreName' object store.
+   *        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.
    * @param failureCb
    *        Error callback to call when an error is encountered.
    */
-  newTxn: function newTxn(txn_type, callback, successCb, failureCb) {
+  newTxn: function newTxn(txn_type, store_name, callback, successCb, failureCb) {
     this.ensureDB(function () {
       if (DEBUG) debug("Starting new transaction" + txn_type);
-      let txn = this._db.transaction(this.dbName, txn_type);
+      let txn = this._db.transaction(this.dbStoreNames, txn_type);
       if (DEBUG) debug("Retrieving object store", this.dbName);
-      let store = txn.objectStore(this.dbStoreName);
+      let store = txn.objectStore(store_name);
 
       txn.oncomplete = function (event) {
         if (DEBUG) debug("Transaction complete. Returning to callback.");
         successCb(txn.result);
       };
 
       txn.onabort = function (event) {
         if (DEBUG) debug("Caught error on transaction");
@@ -130,25 +132,25 @@ IndexedDBHelper.prototype = {
             failureCb("UnknownError");
       };
       callback(txn, store);
     }.bind(this), 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.
    * @param aGlobal
    *        Global object that has indexedDB property.
    */
-  initDBHelper: function initDBHelper(aDBName, aDBVersion, aDBStoreName, aGlobal) {
+  initDBHelper: function initDBHelper(aDBName, aDBVersion, aDBStoreNames, aGlobal) {
     this.dbName = aDBName;
     this.dbVersion = aDBVersion;
-    this.dbStoreName = aDBStoreName;
+    this.dbStoreNames = aDBStoreNames;
     this.dbGlobal = aGlobal;
   }
 }
--- a/dom/contacts/fallback/ContactDB.jsm
+++ b/dom/contacts/fallback/ContactDB.jsm
@@ -42,17 +42,17 @@ ContactDB.prototype = {
          *
          * {id:            "...",       // UUID
          *  published:     Date(...),   // First published date.
          *  updated:       Date(...),   // Last updated date.
          *  properties:    {...}        // Object holding the ContactProperties
          * }
          */
         if (DEBUG) debug("create schema");
-        objectStore = db.createObjectStore(this.dbStoreName, {keyPath: "id"});
+        objectStore = db.createObjectStore(STORE_NAME, {keyPath: "id"});
 
         // Properties indexes
         objectStore.createIndex("familyName", "properties.familyName", { multiEntry: true });
         objectStore.createIndex("givenName",  "properties.givenName",  { multiEntry: true });
 
         objectStore.createIndex("familyNameLowerCase", "search.familyName", { multiEntry: true });
         objectStore.createIndex("givenNameLowerCase",  "search.givenName",  { multiEntry: true });
         objectStore.createIndex("telLowerCase",        "search.tel",        { multiEntry: true });
@@ -84,17 +84,17 @@ ContactDB.prototype = {
           }
         };
 
         // Create new searchable indexes.
         objectStore.createIndex("tel", "search.tel", { multiEntry: true });
         objectStore.createIndex("category", "properties.category", { multiEntry: true });
       } else if (currVersion == 2) {
         if (DEBUG) debug("upgrade 2");
-        // Create a new scheme for the email field. We move from an array of emailaddresses to an array of 
+        // Create a new scheme for the email field. We move from an array of emailaddresses to an array of
         // ContactEmail.
         if (!objectStore) {
           objectStore = aTransaction.objectStore(STORE_NAME);
         }
 
         // Delete old email index.
         if (objectStore.indexNames.contains("email")) {
           objectStore.deleteIndex("email");
@@ -379,17 +379,17 @@ ContactDB.prototype = {
     if (!record.published) {
       record.published = new Date();
     }
     record.updated = new Date();
   },
 
   saveContact: function saveContact(aContact, successCb, errorCb) {
     let contact = this.makeImport(aContact);
-    this.newTxn("readwrite", function (txn, store) {
+    this.newTxn("readwrite", STORE_NAME, function (txn, store) {
       if (DEBUG) debug("Going to update" + JSON.stringify(contact));
 
       // Look up the existing record and compare the update timestamp.
       // If no record exists, just add the new entry.
       let newRequest = store.get(contact.id);
       newRequest.onsuccess = function (event) {
         if (!event.target.result) {
           if (DEBUG) debug("new record!")
@@ -408,24 +408,24 @@ ContactDB.prototype = {
             store.put(contact);
           }
         }
       }.bind(this);
     }.bind(this), successCb, errorCb);
   },
 
   removeContact: function removeContact(aId, aSuccessCb, aErrorCb) {
-    this.newTxn("readwrite", function (txn, store) {
+    this.newTxn("readwrite", STORE_NAME, function (txn, store) {
       if (DEBUG) debug("Going to delete" + aId);
       store.delete(aId);
     }, aSuccessCb, aErrorCb);
   },
 
   clear: function clear(aSuccessCb, aErrorCb) {
-    this.newTxn("readwrite", function (txn, store) {
+    this.newTxn("readwrite", STORE_NAME, function (txn, store) {
       if (DEBUG) debug("Going to clear all!");
       store.clear();
     }, aSuccessCb, aErrorCb);
   },
 
   /**
    * @param successCb
    *        Callback function to invoke with result array.
@@ -436,17 +436,17 @@ ContactDB.prototype = {
    *        - filterBy
    *        - filterOp
    *        - filterValue
    *        - count
    */
   find: function find(aSuccessCb, aFailureCb, aOptions) {
     if (DEBUG) debug("ContactDB:find val:" + aOptions.filterValue + " by: " + aOptions.filterBy + " op: " + aOptions.filterOp + "\n");
     let self = this;
-    this.newTxn("readonly", function (txn, store) {
+    this.newTxn("readonly", STORE_NAME, function (txn, store) {
       if (aOptions && (aOptions.filterOp == "equals" || aOptions.filterOp == "contains")) {
         self._findWithIndex(txn, store, aOptions);
       } else {
         self._findAll(txn, store, aOptions);
       }
     }, aSuccessCb, aFailureCb);
   },
 
@@ -522,11 +522,11 @@ ContactDB.prototype = {
     store.mozGetAll(null, limit).onsuccess = function (event) {
       if (DEBUG) debug("Request successful. Record count:", event.target.result.length);
       for (let i in event.target.result)
         txn.result[event.target.result[i].id] = this.makeExport(event.target.result[i]);
     }.bind(this);
   },
 
   init: function init(aGlobal) {
-      this.initDBHelper(DB_NAME, DB_VERSION, STORE_NAME, aGlobal);
+      this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME], aGlobal);
   }
 };
--- a/dom/network/src/NetworkStatsDB.jsm
+++ b/dom/network/src/NetworkStatsDB.jsm
@@ -24,30 +24,30 @@ const VALUES_MAX_LENGTH = 6 * 30;
 
 // Constant defining the rate of the samples. Daily.
 const SAMPLE_RATE = 1000 * 60 * 60 * 24;
 
 this.NetworkStatsDB = function NetworkStatsDB(aGlobal) {
   if (DEBUG) {
     debug("Constructor");
   }
-  this.initDBHelper(DB_NAME, DB_VERSION, STORE_NAME, aGlobal);
+  this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME], aGlobal);
 }
 
 NetworkStatsDB.prototype = {
   __proto__: IndexedDBHelper.prototype,
 
   dbNewTxn: function dbNewTxn(txn_type, callback, txnCb) {
     function successCb(result) {
       txnCb(null, result);
     }
     function errorCb(error) {
       txnCb(error, null);
     }
-    return this.newTxn(txn_type, callback, successCb, errorCb);
+    return this.newTxn(txn_type, STORE_NAME, callback, successCb, errorCb);
   },
 
   upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
     if (DEBUG) {
       debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
     }
     let db = aDb;
     let objectStore;
--- a/dom/settings/SettingsDB.jsm
+++ b/dom/settings/SettingsDB.jsm
@@ -104,11 +104,11 @@ SettingsDB.prototype = {
           objectStore.add({ settingName: name, defaultValue: settings[name], userValue: undefined });
         }
       }
     };
   },
 
   init: function init(aGlobal) {
     this.initDBHelper(SETTINGSDB_NAME, SETTINGSDB_VERSION,
-                      SETTINGSSTORE_NAME, aGlobal);
+                      [SETTINGSSTORE_NAME], aGlobal);
   }
 }