Bug 746933 - Create a JS helper module for common IndexedDB functionality. r=fabrice

This commit is contained in:
Gregor Wagner 2012-04-26 15:10:04 -07:00
parent d971875173
commit f3aea8b4a6
5 changed files with 196 additions and 175 deletions

View File

@ -0,0 +1,154 @@
/* 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"
let DEBUG = 0;
if (DEBUG) {
debug = function (s) { dump("-*- IndexedDBHelper: " + s + "\n"); }
} else {
debug = function (s) {}
}
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
let EXPORTED_SYMBOLS = ["IndexedDBHelper"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
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 createSchema and 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;
debug("Try to open database:" + this.dbName + " " + this.dbVersion);
let req = this.dbGlobal.mozIndexedDB.open(this.dbName, this.dbVersion);
req.onsuccess = function (event) {
debug("Opened database:" + self.dbName + " " + self.dbName);
self._db = event.target.result;
self._db.onversionchange = function(event) {
debug("WARNING: DB modified from a different window.");
}
aSuccessCb();
};
req.onupgradeneeded = function (aEvent) {
debug("Database needs upgrade:" + this.dbName + aEvent.oldVersion + aEvent.newVersion);
debug("Correct new database version:" + aEvent.newVersion == this.dbVersion);
let _db = aEvent.target.result;
switch (aEvent.oldVersion) {
case 0:
debug("New database");
self.createSchema(_db);
break;
default:
self.upgradeSchema(_db, aEvent.oldVersion, aEvent.newVersion);
break;
}
};
req.onerror = function (aEvent) {
debug("Failed to open database:" + this.dbName);
aFailureCb(aEvent.target.errorMessage);
};
req.onblocked = function (aEvent) {
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) {
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 callback
* Function to call when the transaction is available. It will
* be invoked with the transaction and the 'aDBStoreName' 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) {
this.ensureDB(function () {
debug("Starting new transaction" + txn_type);
let txn = this._db.transaction(this.dbName, txn_type);
debug("Retrieving object store", this.dbName);
let store = txn.objectStore(this.dbStoreName);
txn.oncomplete = function (event) {
debug("Transaction complete. Returning to callback.");
successCb(txn.result);
};
txn.onabort = function (event) {
debug("Caught error on transaction");
// FIXXMEE: this will work in the future. Bug 748630
// failureCb(event.target.error.name);
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 createSchema and upgradeSchema.
* @param aDBStoreName
* ObjectStore that is used.
* @param aGlobal
* Global object that has mozIndexedDB property.
*/
initDBHelper: function initDBHelper(aDBName, aDBVersion, aDBStoreName, aGlobal) {
this.dbName = aDBName;
this.dbVersion = aDBVersion;
this.dbStoreName = aDBStoreName;
this.dbGlobal = aGlobal;
}
}

View File

@ -52,25 +52,27 @@ DIRS = \
$(NULL)
EXTRA_PP_COMPONENTS = \
ConsoleAPI.js \
ConsoleAPI.manifest \
BrowserElementAPI.js \
BrowserElementAPI.manifest \
$(NULL)
ConsoleAPI.js \
ConsoleAPI.manifest \
BrowserElementAPI.js \
BrowserElementAPI.manifest \
$(NULL)
EXTRA_JS_MODULES = ConsoleAPIStorage.jsm \
$(NULL)
$(NULL)
EXTRA_COMPONENTS = \
Webapps.js \
Webapps.manifest \
$(NULL)
Webapps.js \
Webapps.manifest \
$(NULL)
EXTRA_PP_JS_MODULES += Webapps.jsm \
$(NULL)
$(NULL)
EXTRA_JS_MODULES += DOMRequestHelper.jsm \
$(NULL)
EXTRA_JS_MODULES += \
DOMRequestHelper.jsm \
IndexedDBHelper.jsm \
$(NULL)
XPIDLSRCS = \
nsIDOMDOMError.idl \

View File

@ -8,16 +8,18 @@ const EXPORTED_SYMBOLS = ['ContactDB'];
let DEBUG = 0;
/* static functions */
if (DEBUG)
debug = function (s) { dump("-*- ContactDB component: " + s + "\n"); }
else
debug = function (s) {}
if (DEBUG) {
debug = function (s) { dump("-*- ContactDB component: " + s + "\n"); }
} else {
debug = function (s) {}
}
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
const DB_NAME = "contacts";
const DB_VERSION = 1;
@ -29,66 +31,7 @@ function ContactDB(aGlobal) {
}
ContactDB.prototype = {
// Cache the DB
db: null,
close: function close() {
debug("close");
if (this.db)
this.db.close();
},
/**
* Prepare the database. This may include opening the database and upgrading
* it to the latest schema version.
*
* @return (via callback) a database ready for use.
*/
ensureDB: function ensureDB(callback, failureCb) {
if (this.db) {
debug("ensureDB: already have a database, returning early.");
callback(this.db);
return;
}
let self = this;
debug("try to open database:" + DB_NAME + " " + DB_VERSION);
let request = this._global.mozIndexedDB.open(DB_NAME, DB_VERSION);
request.onsuccess = function (event) {
debug("Opened database:", DB_NAME, DB_VERSION);
self.db = event.target.result;
self.db.onversionchange = function(event) {
debug("WARNING: DB modified from a different window.");
}
callback(self.db);
};
request.onupgradeneeded = function (event) {
debug("Database needs upgrade:" + DB_NAME + event.oldVersion + event.newVersion);
debug("Correct new database version:" + event.newVersion == DB_VERSION);
let db = event.target.result;
switch (event.oldVersion) {
case 0:
debug("New database");
self.createSchema(db);
break;
default:
debug("No idea what to do with old database version:" + event.oldVersion);
failureCb(event.target.errorMessage);
break;
}
};
request.onerror = function (event) {
debug("Failed to open database:", DB_NAME);
failureCb(event.target.errorMessage);
};
request.onblocked = function (event) {
debug("Opening database request is blocked.");
};
},
__proto__: IndexedDBHelper.prototype,
/**
* Create the initial database schema.
*
@ -101,7 +44,7 @@ ContactDB.prototype = {
* }
*/
createSchema: function createSchema(db) {
let objectStore = db.createObjectStore(STORE_NAME, {keyPath: "id"});
let objectStore = db.createObjectStore(this.dbStoreName, {keyPath: "id"});
// Metadata indexes
objectStore.createIndex("published", "published", { unique: false });
@ -127,41 +70,6 @@ ContactDB.prototype = {
debug("Created object stores and indexes");
},
/**
* Start a new transaction.
*
* @param txn_type
* Type of transaction (e.g. "readwrite")
* @param callback
* Function to call when the transaction is available. It will
* be invoked with the transaction and the 'contacts' object store.
* @param successCb [optional]
* Success callback to call on a successful transaction commit.
* @param failureCb [optional]
* Error callback to call when an error is encountered.
*/
newTxn: function newTxn(txn_type, callback, successCb, failureCb) {
this.ensureDB(function (db) {
debug("Starting new transaction" + txn_type);
let txn = db.transaction(STORE_NAME, txn_type);
debug("Retrieving object store", STORE_NAME);
let store = txn.objectStore(STORE_NAME);
txn.oncomplete = function (event) {
debug("Transaction complete. Returning to callback.");
successCb(txn.result);
};
txn.onabort = function (event) {
debug("Caught error on transaction");
// FIXXMEE: this will work in the future. Bug 748630
// failureCb(event.target.error.name);
failureCb("UnknownError");
};
callback(txn, store);
}, failureCb);
},
makeImport: function makeImport(aContact) {
let contact = {};
contact.properties = {
@ -403,5 +311,9 @@ ContactDB.prototype = {
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);
}
};

View File

@ -37,6 +37,7 @@ let DOMContactManager = {
var idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
idbManager.initWindowless(myGlobal);
this._db = new ContactDB(myGlobal);
this._db.init(myGlobal);
Services.obs.addObserver(this, "profile-before-change", false);

View File

@ -36,6 +36,12 @@ Queue.prototype = {
}
}
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
const DB_NAME = "settings";
const DB_VERSION = 1;
const STORE_NAME = "settings";
@ -43,74 +49,19 @@ const STORE_NAME = "settings";
function SettingsDB() {}
SettingsDB.prototype = {
db: null,
close: function close() {
if (this.db)
this.db.close();
},
/**
* Prepare the database. This may include opening the database and upgrading
* it to the latest schema version.
*
* @return (via callback) a database ready for use.
*/
ensureDB: function ensureDB(aSuccessCb, aFailureCb, aGlobal) {
if (this.db) {
debug("ensureDB: already have a database, returning early.");
return;
}
let self = this;
debug("try to open database:" + DB_NAME + " " + DB_VERSION + " " + this.db);
let req = aGlobal.mozIndexedDB.open(DB_NAME, DB_VERSION);
req.onsuccess = function (event) {
debug("Opened database:", DB_NAME, DB_VERSION);
self.db = event.target.result;
self.db.onversionchange = function(event) {
debug("WARNING: DB modified from a different window.");
}
aSuccessCb();
};
req.onupgradeneeded = function (aEvent) {
debug("Database needs upgrade:" + DB_NAME + aEvent.oldVersion + aEvent.newVersion);
debug("Correct new database version:" + aEvent.newVersion == DB_VERSION);
let db = aEvent.target.result;
switch (aEvent.oldVersion) {
case 0:
debug("New database");
self.createSchema(db);
break;
default:
debug("No idea what to do with old database version:" + aEvent.oldVersion);
aFailureCb(aEvent.target.errorMessage);
break;
}
};
req.onerror = function (aEvent) {
debug("Failed to open database:", DB_NAME);
aFailureCb(aEvent.target.errorMessage);
};
req.onblocked = function (aEvent) {
debug("Opening database request is blocked.");
};
},
__proto__: IndexedDBHelper.prototype,
createSchema: function createSchema(aDb) {
let objectStore = aDb.createObjectStore(STORE_NAME, {keyPath: "settingName"});
let objectStore = aDb.createObjectStore(STORE_NAME, { keyPath: "settingName" });
objectStore.createIndex("settingValue", "settingValue", { unique: false });
debug("Created object stores and indexes");
},
init: function init(aGlobal) {
this.initDBHelper(DB_NAME, DB_VERSION, STORE_NAME, aGlobal);
}
}
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -197,11 +148,11 @@ SettingsLock.prototype = {
},
createTransactionAndProcess: function() {
if (this._settingsManager._settingsDB.db) {
if (this._settingsManager._settingsDB._db) {
var lock;
while (lock = this._settingsManager._locks.dequeue()) {
if (!lock._transaction) {
lock._transaction = lock._settingsManager._settingsDB.db.transaction(STORE_NAME, "readwrite");
lock._transaction = lock._settingsManager._settingsDB._db.transaction(STORE_NAME, "readwrite");
}
lock.process();
}
@ -278,6 +229,7 @@ function SettingsManager()
var idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
idbManager.initWindowless(myGlobal);
this._settingsDB = new SettingsDB();
this._settingsDB.init(myGlobal);
}
SettingsManager.prototype = {