From 9f38337ec7b92aab67db4f053c07109e3282a7b3 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Tue, 21 Feb 2006 17:01:06 +0000 Subject: [PATCH] Initial import of repository structure, basic extension layout, and functions for DB abstraction and schema maintenance --- chrome.manifest | 6 + chrome/chromeFiles/content/scholar/db.js | 257 ++++++++++++++++++ chrome/chromeFiles/content/scholar/schema.xml | 85 ++++++ chrome/chromeFiles/content/scholar/scholar.js | 53 ++++ .../chromeFiles/content/scholar/scholar.xul | 14 + .../chromeFiles/content/scholar/test/test.js | 1 + .../chromeFiles/content/scholar/test/test.xul | 18 ++ .../locale/en-US/scholar/scholar.dtd | 1 + .../skin/default/scholar/scholar.css | 0 install.rdf | 17 ++ 10 files changed, 452 insertions(+) create mode 100644 chrome.manifest create mode 100644 chrome/chromeFiles/content/scholar/db.js create mode 100644 chrome/chromeFiles/content/scholar/schema.xml create mode 100644 chrome/chromeFiles/content/scholar/scholar.js create mode 100644 chrome/chromeFiles/content/scholar/scholar.xul create mode 100644 chrome/chromeFiles/content/scholar/test/test.js create mode 100644 chrome/chromeFiles/content/scholar/test/test.xul create mode 100644 chrome/chromeFiles/locale/en-US/scholar/scholar.dtd create mode 100644 chrome/chromeFiles/skin/default/scholar/scholar.css create mode 100644 install.rdf diff --git a/chrome.manifest b/chrome.manifest new file mode 100644 index 0000000000..b643817ad0 --- /dev/null +++ b/chrome.manifest @@ -0,0 +1,6 @@ +content scholar chrome/chromeFiles/content/scholar/ +locale scholar en-US chrome/chromeFiles/locale/en-US/scholar/ +skin scholar default chrome/chromeFiles/skin/default/scholar/ + +overlay chrome://browser/content/browser.xul chrome://scholar/content/scholar.xul +style chrome://browser/content/browser.xul chrome://scholar/skin/scholar.css diff --git a/chrome/chromeFiles/content/scholar/db.js b/chrome/chromeFiles/content/scholar/db.js new file mode 100644 index 0000000000..982b62dee0 --- /dev/null +++ b/chrome/chromeFiles/content/scholar/db.js @@ -0,0 +1,257 @@ +var scholarDB = new Scholar_DB(); + +/* + * DB connection and schema management class + */ +function Scholar_DB(){ + // Private members + var _connection; + + // Privileged methods + this.query = query; + this.valueQuery = valueQuery; + this.rowQuery = rowQuery; + this.statementQuery = statementQuery; + this.updateSchema = updateSchema; + + + ///////////////////////////////////////////////////////////////// + // + // Privileged methods + // + ///////////////////////////////////////////////////////////////// + + /* + * Run an SQL query + * + * Returns: + * - mozIStorageStatementWrapper for SELECT's + * - lastInsertId for INSERT's + * - TRUE for other successful queries + * - FALSE on error + */ + function query(sql){ + var db = _getDBConnection(); + + try { + // Parse out the SQL command being used + var op = sql.match(/^[^a-z]*[^ ]+/i).toString().toLowerCase(); + + // If SELECT statement, return result + if (op=='select'){ + var wrapper = + Components.classes['@mozilla.org/storage/statement-wrapper;1'] + .createInstance(Components.interfaces.mozIStorageStatementWrapper); + + wrapper.initialize(db.createStatement(sql)); + return wrapper; + } + else { + db.executeSimpleSQL(sql); + + if (op=='insert'){ + return db.lastInsertId; + } + // DEBUG: Can't get affected rows for UPDATE or DELETE? + else { + return true; + } + } + } + catch(ex){ + alert(db.lastErrorString); + return false; + } + } + + + /* + * Query a single value and return it + */ + function valueQuery(sql){ + var db = _getDBConnection(); + try { + var statement = db.createStatement(sql); + } + catch (e){ + alert(db.lastErrorString); + return false; + } + + // No rows + if (!statement.executeStep()){ + return false; + } + var value = statement.getAsUTF8String(0); + statement.reset(); + return value; + } + + + /* + * Run a query and return the first row + */ + function rowQuery(sql){ + var result = query(sql); + if (result && result.step()){ + return result.row; + } + } + + + /* + * Run a query, returning a mozIStorageStatement for direct manipulation + */ + function statementQuery(sql){ + var db = _getDBConnection(); + + try { + return db.createStatement(sql); + } + catch (e){ + return false; + } + } + + + /* + * Checks if the DB schema exists and is up-to-date, updating if necessary + */ + function updateSchema(){ + var DBVersion = _getDBVersion(); + + if (DBVersion > SCHOLAR_CONFIG['DB_VERSION']){ + throw("Scholar DB version is newer than config version"); + } + else if (DBVersion < SCHOLAR_CONFIG['DB_VERSION']){ + if (!DBVersion){ + dump('Database does not exist -- creating\n'); + return _initializeSchema(); + } + + return _migrateSchema(DBVersion); + } + } + + + + ///////////////////////////////////////////////////////////////// + // + // Private methods + // + ///////////////////////////////////////////////////////////////// + + /* + * Retrieve a link to the data store + */ + function _getDBConnection(){ + if (_connection){ + return _connection; + } + + // Get the storage service + var store = Components.classes["@mozilla.org/storage/service;1"]. + getService(Components.interfaces.mozIStorageService); + + // Get the profile directory + var file = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("ProfD", Components.interfaces.nsILocalFile); + + // This makes file point to PROFILE_DIR/ + file.append(SCHOLAR_CONFIG['DB_FILE']); + + _connection = store.openDatabase(file); + + return _connection; + } + + + /* + * Retrieve the DB schema version + */ + function _getDBVersion(){ + if (_getDBConnection().tableExists('version')){ + return valueQuery("SELECT version FROM version;"); + } + return false; + } + + + /* + * Load in SQL schema + */ + function _getSchemaSQL(){ + // We pull the schema from an external file so we only have to process + // it when necessary + var req = new XMLHttpRequest(); + req.open("GET", "chrome://scholar/content/schema.xml", false); + req.send(null); + + var schemaVersion = + req.responseXML.documentElement.getAttribute('version'); + + if (schemaVersion!=SCHOLAR_CONFIG['DB_VERSION']){ + throw("Scholar config version does not match schema version"); + } + + return req.responseXML.documentElement.firstChild.data; + } + + + /* + * Retrieve the version attribute of the schema SQL XML + */ + function _getSchemaSQLVersion(){ + var req = new XMLHttpRequest(); + req.open("GET", "chrome://scholar/content/schema.xml", false); + req.send(null); + return req.responseXML.documentElement.getAttribute('version'); + } + + + /* + * Create new DB schema + */ + function _initializeSchema(){ + query(_getSchemaSQL()); + query("INSERT INTO version VALUES (" + SCHOLAR_CONFIG['DB_VERSION'] + ")"); + } + + + /* + * Migrate schema from an older version, preserving data + */ + function _migrateSchema(fromVersion){ + var toVersion = SCHOLAR_CONFIG['DB_VERSION']; + var schemaVersion = _getSchemaSQLVersion(); + + if (toVersion!=schemaVersion){ + throw("Scholar config version does not match schema version"); + } + + dump('Updating DB from version ' + fromVersion + ' to ' + toVersion + '\n'); + + // Step through version changes until we reach the current version + // + // Each block performs the changes necessary to move from the + // previous revision to that one. + // + // N.B. Be sure to call _updateDBVersion(i) at the end of each block! + for (var i=fromVersion+1; i<=toVersion; i++){ + + if (i==1){ + // do stuff + // _updateDBVersion(i); + } + } + } + + + /* + * Update the DB schema version tag of an existing database + */ + function _updateDBVersion(version){ + return query("UPDATE version SET version=" + version); + } +} diff --git a/chrome/chromeFiles/content/scholar/schema.xml b/chrome/chromeFiles/content/scholar/schema.xml new file mode 100644 index 0000000000..f4ca318ea9 --- /dev/null +++ b/chrome/chromeFiles/content/scholar/schema.xml @@ -0,0 +1,85 @@ + +BEGIN; + CREATE TABLE version ( + version INT PRIMARY KEY + ); + + CREATE TABLE objects ( + objectID INT PRIMARY KEY, + objectTypeID INT, + objectTitle TEXT, + objectDate DATETIME, + objectDateAdded DATETIME DEFAULT CURRENT_TIMESTAMP, + objectDateModified DATETIME DEFAULT CURRENT_TIMESTAMP, + objectSource TEXT, + objectRights TEXT, + parentID INT, + orderIndex INT + ); + CREATE INDEX parentID ON objects (parentID); + + CREATE TABLE objectTypes ( + objectTypeID INT PRIMARY KEY, + typeName TEXT + ); + + CREATE TABLE fields ( + fieldID INT PRIMARY KEY, + fieldName TEXT, + regex TEXT + ); + + CREATE TABLE objectTypeFields ( + objectTypeID, + fieldID INT, + orderIndex INT, + PRIMARY KEY (objectTypeID, fieldID), + FOREIGN KEY (objectTypeID) REFERENCES objectTypes(objectTypeID), + FOREIGN KEY (fieldID) REFERENCES objectTypes(objectTypeID) + ); + + CREATE TABLE objectData ( + objectID INT, + fieldID INT, + value NONE, + PRIMARY KEY (objectID, fieldID), + FOREIGN KEY (objectID) REFERENCES objects(objectID), + FOREIGN KEY (fieldID) REFERENCES fields(fieldID) + ); + CREATE INDEX value ON objectData (value); + + CREATE TABLE keywords ( + keywordID INT PRIMARY KEY, + keyword TEXT + ); + + CREATE TABLE objectKeywords ( + objectID INT, + keywordID INT, + PRIMARY KEY (objectID, keywordID), + FOREIGN KEY (objectID) REFERENCES objects(objectID), + FOREIGN KEY (keywordID) REFERENCES keywords(keywordID) + ); + + CREATE TABLE creators ( + creatorID INT PRIMARY KEY, + firstName TEXT, + lastName TEXT + ); + + CREATE TABLE creatorTypes ( + creatorTypeID INT PRIMARY KEY, + creatorType TEXT + ); + + CREATE TABLE objectCreators ( + objectID INT, + creatorID INT, + creatorTypeID INT, + orderIndex INT, + PRIMARY KEY (objectID, creatorID), + FOREIGN KEY (objectID) REFERENCES objects(objectID), + FOREIGN KEY (creatorID) REFERENCES creators(creatorID) + ); +COMMIT; + diff --git a/chrome/chromeFiles/content/scholar/scholar.js b/chrome/chromeFiles/content/scholar/scholar.js new file mode 100644 index 0000000000..d21300a1c0 --- /dev/null +++ b/chrome/chromeFiles/content/scholar/scholar.js @@ -0,0 +1,53 @@ +const SCHOLAR_CONFIG = { + DB_FILE : 'scholar.sdb', + DB_VERSION : 1, + DEBUG_LOGGING : true +}; + +/* + * Core functions + */ +var Scholar = { + /* + * Initialize the extension + */ + init: function() { + scholarDB.updateSchema(); + }, + + /* + * Debug logging function + * + * Uses DebugLogger extension available from http://mozmonkey.com/debuglogger/ + * if available, otherwise the console + * + * Defaults to log level 3 if level not provided + */ + debug: function(message, level) { + if (!SCHOLAR_CONFIG['DEBUG_LOGGING']){ + return false; + } + + if (!level){ + level = 3; + } + + try { + var logManager = + Components.classes["@mozmonkey.com/debuglogger/manager;1"] + .getService(Components.interfaces.nsIDebugLoggerManager); + var logger = logManager.registerLogger("Firefox Scholar"); + } + catch (e){} + + if (logger){ + logger.log(level, message); + } + else { + dump('scholar(' + level + '): ' + message); + } + return true; + } +} + +window.addEventListener("load", function(e) { Scholar.init(e); }, false); diff --git a/chrome/chromeFiles/content/scholar/scholar.xul b/chrome/chromeFiles/content/scholar/scholar.xul new file mode 100644 index 0000000000..6df1370c98 --- /dev/null +++ b/chrome/chromeFiles/content/scholar/scholar.xul @@ -0,0 +1,14 @@ + + + + + + +