
Added creatorTypeID to the PK in itemCreators, because a creator could conceivably have two roles on an item Throw an error if attempt to save() an item with two identical creator/creatorTypeID combinations, since, assuming this shouldn't be allowed (i.e. we don't have a four-column PK), there's really no way to handle this elegantly on my end -- interface code can use new method Item.creatorExists(firstName, lastName, creatorTypeID, skipIndex), with skipIndex set to the current index, to make sure this isn't done
250 lines
6.1 KiB
JavaScript
250 lines
6.1 KiB
JavaScript
Scholar.Schema = new function(){
|
|
var _dbVersions = [];
|
|
var _schemaVersions = [];
|
|
|
|
this.updateSchema = updateSchema;
|
|
|
|
/*
|
|
* Checks if the DB schema exists and is up-to-date, updating if necessary
|
|
*/
|
|
function updateSchema(){
|
|
var dbVersion = _getDBVersion();
|
|
var schemaVersion = _getSchemaSQLVersion();
|
|
|
|
if (dbVersion == schemaVersion){
|
|
if (SCHOLAR_CONFIG['DB_REBUILD']){
|
|
if (confirm('Erase all data and recreate database from schema?')){
|
|
_initializeSchema();
|
|
return;
|
|
}
|
|
}
|
|
|
|
_updateScrapers();
|
|
return;
|
|
}
|
|
// If DB version is less than schema file, create or update
|
|
else if (dbVersion < schemaVersion){
|
|
if (!dbVersion){
|
|
Scholar.debug('Database does not exist -- creating\n');
|
|
_initializeSchema();
|
|
return;
|
|
}
|
|
|
|
_migrateSchema(dbVersion);
|
|
_updateScrapers();
|
|
return;
|
|
}
|
|
else {
|
|
throw("Scholar DB version is newer than schema version");
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
//
|
|
// Private methods
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
* Retrieve the DB schema version
|
|
*/
|
|
function _getDBVersion(schema){
|
|
// Default to schema.sql
|
|
if (!schema){
|
|
schema = 'schema';
|
|
}
|
|
|
|
if (_dbVersions[schema]){
|
|
return _dbVersions[schema];
|
|
}
|
|
|
|
if (Scholar.DB.tableExists('version')){
|
|
try {
|
|
var dbVersion = Scholar.DB.valueQuery("SELECT version FROM "
|
|
+ "version WHERE schema='" + schema + "'");
|
|
}
|
|
// DEBUG: this is temporary to handle version table schema change
|
|
catch(e){
|
|
if (e=='no such column: schema'){
|
|
Scholar.debug(e, 1);
|
|
return false;
|
|
}
|
|
|
|
// If some other problem, bail
|
|
throw(e);
|
|
}
|
|
_dbVersions[schema] = dbVersion;
|
|
return dbVersion;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
* Retrieve the version from the top line of the schema SQL file
|
|
*/
|
|
function _getSchemaSQLVersion(schema){
|
|
// Default to schema.sql
|
|
if (!schema){
|
|
schema = 'schema';
|
|
}
|
|
|
|
var schemaFile = schema + '.sql';
|
|
|
|
if (_schemaVersions[schema]){
|
|
return _schemaVersions[schema];
|
|
}
|
|
|
|
var file = Components.classes["@mozilla.org/extensions/manager;1"]
|
|
.getService(Components.interfaces.nsIExtensionManager)
|
|
.getInstallLocation(SCHOLAR_CONFIG['GUID'])
|
|
.getItemLocation(SCHOLAR_CONFIG['GUID']);
|
|
file.append(schemaFile);
|
|
|
|
// Open an input stream from file
|
|
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
|
|
.createInstance(Components.interfaces.nsIFileInputStream);
|
|
istream.init(file, 0x01, 0444, 0);
|
|
istream.QueryInterface(Components.interfaces.nsILineInputStream);
|
|
|
|
var line = {};
|
|
|
|
// Fetch the schema version from the first line of the file
|
|
istream.readLine(line);
|
|
var schemaVersion = line.value.match(/-- ([0-9]+)/)[1];
|
|
istream.close();
|
|
|
|
_schemaVersions[schema] = schemaVersion;
|
|
return schemaVersion;
|
|
}
|
|
|
|
|
|
/*
|
|
* Load in SQL schema
|
|
*
|
|
* Returns an _array_ of SQL statements for feeding into query()
|
|
*/
|
|
function _getSchemaSQL(schema){
|
|
// Default to schema.sql
|
|
if (!schema){
|
|
schema = 'schema';
|
|
}
|
|
|
|
var schemaFile = schema + '.sql';
|
|
|
|
// We pull the schema from an external file so we only have to process
|
|
// it when necessary
|
|
var file = Components.classes["@mozilla.org/extensions/manager;1"]
|
|
.getService(Components.interfaces.nsIExtensionManager)
|
|
.getInstallLocation(SCHOLAR_CONFIG['GUID'])
|
|
.getItemLocation(SCHOLAR_CONFIG['GUID']);
|
|
file.append(schemaFile);
|
|
|
|
// Open an input stream from file
|
|
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
|
|
.createInstance(Components.interfaces.nsIFileInputStream);
|
|
istream.init(file, 0x01, 0444, 0);
|
|
istream.QueryInterface(Components.interfaces.nsILineInputStream);
|
|
|
|
var line = {}, sql = '', hasmore;
|
|
|
|
// Skip the first line, which contains the schema version
|
|
istream.readLine(line);
|
|
//var schemaVersion = line.value.match(/-- ([0-9]+)/)[1];
|
|
|
|
do {
|
|
hasmore = istream.readLine(line);
|
|
sql += line.value + "\n";
|
|
} while(hasmore);
|
|
|
|
istream.close();
|
|
|
|
return sql;
|
|
}
|
|
|
|
|
|
/*
|
|
* Create new DB schema
|
|
*/
|
|
function _initializeSchema(){
|
|
try {
|
|
Scholar.DB.beginTransaction();
|
|
Scholar.DB.query(_getSchemaSQL());
|
|
Scholar.DB.query("INSERT INTO version VALUES ('schema', "
|
|
+ _getSchemaSQLVersion() + ")");
|
|
Scholar.DB.query(_getSchemaSQL('scrapers'));
|
|
Scholar.DB.query("INSERT INTO version VALUES ('scrapers', "
|
|
+ _getSchemaSQLVersion('scrapers') + ")");
|
|
Scholar.DB.commitTransaction();
|
|
}
|
|
catch(e){
|
|
alert(e);
|
|
Scholar.DB.rollbackTransaction();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Update a DB schema version tag in an existing database
|
|
*/
|
|
function _updateDBVersion(schema, version){
|
|
return Scholar.DB.query("UPDATE version SET version=" + version
|
|
+ " WHERE schema='" + schema + "'");
|
|
}
|
|
|
|
|
|
/*
|
|
* Update the scrapers in the DB to the latest bundled versions
|
|
*/
|
|
function _updateScrapers(){
|
|
var dbVersion = _getDBVersion('scrapers');
|
|
var schemaVersion = _getSchemaSQLVersion('scrapers');
|
|
|
|
if (dbVersion == schemaVersion){
|
|
return;
|
|
}
|
|
else if (dbVersion < schemaVersion){
|
|
Scholar.DB.beginTransaction();
|
|
Scholar.DB.query(_getSchemaSQL('scrapers'));
|
|
_updateDBVersion('scrapers', schemaVersion);
|
|
Scholar.DB.commitTransaction();
|
|
return;
|
|
}
|
|
else {
|
|
throw("Scraper set in DB is newer than schema version");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Migrate schema from an older version, preserving data
|
|
*/
|
|
function _migrateSchema(fromVersion){
|
|
//
|
|
// Change this value to match the schema version
|
|
//
|
|
var toVersion = 16;
|
|
|
|
if (toVersion != _getSchemaSQLVersion()){
|
|
throw('Schema version does not match version in _migrateSchema()');
|
|
}
|
|
|
|
Scholar.debug('Updating DB from version ' + fromVersion + ' to ' + toVersion + '\n');
|
|
|
|
Scholar.DB.beginTransaction();
|
|
|
|
// 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.
|
|
for (var i=parseInt(fromVersion) + 1; i<=toVersion; i++){
|
|
if (i==16){
|
|
_initializeSchema();
|
|
}
|
|
}
|
|
|
|
_updateDBVersion('schema', i-1);
|
|
Scholar.DB.commitTransaction();
|
|
}
|
|
}
|