From 03637a6c6374bbea48ac68cc16bafdb49e16c654 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Thu, 1 Jun 2006 00:22:18 +0000 Subject: [PATCH] Updated schema for new collections ("projects"?) model and updated sample data accordingly; added a couple extra indexes; made 'rights' and 'source' regular metadata fields so that items can be used for things like notes Overhauled data access layer to support new model: - Changed Item.getParent to Item.getCollections() to get ids of parent collections - Removed Item.setPosition() -- item positions are set internally when items are added to and deleted from collections, but the orderIndex is not currently used or manipulatable externally - Item constructor/Items.getNewItemByType()/Items.add() no longer take folderID and orderIndex as parameters - Split getTreeRows() into Scholar.getCollections(parent) and Scholar.getItems(parent), which return root collections or all library items, respectively, if no parent given - All references to folders in object/method/property names changed to collections - New methods Collection.addItem(itemID), Collection.hasItem(itemID), Collection.removeItem(itemID) - Collection.erase() takes optional deleteItems parameter to delete items from DB -- otherwise just removes association and leaves item in library (does, however, delete all descendent collections from DB regardless) * Note: This will break displaying of items until interface code is updated. * --- .../content/scholar/xpcom/data_access.js | 591 +++++++++--------- .../chromeFiles/content/scholar/xpcom/db.js | 6 +- .../content/scholar/xpcom/scholar.js | 2 +- schema.sql | 159 +++-- 4 files changed, 365 insertions(+), 393 deletions(-) diff --git a/chrome/chromeFiles/content/scholar/xpcom/data_access.js b/chrome/chromeFiles/content/scholar/xpcom/data_access.js index 17ad7c405..8e01d7a36 100644 --- a/chrome/chromeFiles/content/scholar/xpcom/data_access.js +++ b/chrome/chromeFiles/content/scholar/xpcom/data_access.js @@ -6,12 +6,9 @@ Scholar.Item = function(){ this._init(); - // Accept itemTypeID, folderID and orderIndex in constructor + // Accept itemTypeIDin constructor if (arguments.length){ this.setType(arguments[0]); - if (arguments.length>1){ - this.setPosition(arguments[1], arguments[2] ? arguments[2] : false); - } } } @@ -42,20 +39,17 @@ Scholar.Item.prototype._init = function(){ * Check if the specified field is a primary field from the items table */ Scholar.Item.prototype.isPrimaryField = function(field){ + // Create primaryFields hash array if not yet created if (!Scholar.Item.primaryFields){ Scholar.Item.primaryFields = Scholar.DB.getColumnHash('items'); Scholar.Item.primaryFields['firstCreator'] = true; - Scholar.Item.primaryFields['parentFolderID'] = true; - Scholar.Item.primaryFields['orderIndex'] = true; } return !!Scholar.Item.primaryFields[field]; } Scholar.Item.editableFields = { - title: true, - source: true, - rights: true + title: true }; /* @@ -70,14 +64,12 @@ Scholar.Item.prototype.isEditableField = function(field){ * Build object from database */ Scholar.Item.prototype.loadFromID = function(id){ - var sql = 'SELECT I.*, lastName AS firstCreator, TS.parentFolderID, ' - + 'TS.orderIndex ' + var sql = 'SELECT I.*, lastName AS firstCreator ' + 'FROM items I ' - + 'LEFT JOIN treeStructure TS ON (I.itemID=TS.id AND isFolder=0) ' + 'LEFT JOIN itemCreators IC ON (I.itemID=IC.itemID) ' + 'LEFT JOIN creators C ON (IC.creatorID=C.creatorID) ' + 'WHERE itemID=' + id - + ' AND (IC.orderIndex=0 OR IC.orderIndex IS NULL)'; + + ' AND (IC.orderIndex=0 OR IC.orderIndex IS NULL)'; // first creator var row = Scholar.DB.rowQuery(sql); this.loadFromRow(row); } @@ -89,9 +81,13 @@ Scholar.Item.prototype.loadFromID = function(id){ Scholar.Item.prototype.loadFromRow = function(row){ this._init(); for (col in row){ - if (this.isPrimaryField(col) || col=='firstCreator'){ + // Only accept primary field data through loadFromRow() + if (this.isPrimaryField(col)){ this._data[col] = row[col]; } + else { + Scholar.debug(col + ' is not a valid primary field'); + } } return true; } @@ -116,11 +112,6 @@ Scholar.Item.prototype.getType = function(){ } -Scholar.Item.prototype.getParent = function(){ - return this._data['parentFolderID'] ? this._data['parentFolderID'] : false; -} - - /* * Set or change the item's type */ @@ -150,6 +141,15 @@ Scholar.Item.prototype.setType = function(itemTypeID){ } +/** +* Return an array of collectionIDs for all collections the item belongs to +**/ +Scholar.Item.prototype.getCollections = function(){ + return Scholar.DB.columnQuery("SELECT collectionID FROM collectionItems " + + "WHERE itemID=" + this.getID()); +} + + /* * Returns the number of creators for this item */ @@ -160,6 +160,7 @@ Scholar.Item.prototype.numCreators = function(){ return this._creators.length; } + /* * Returns an array of the creator data at the given position, or false if none */ @@ -313,89 +314,6 @@ Scholar.Item.prototype.setField = function(field, value, loadIn){ } } - -/* - * Move item to new position and shift surrounding items - * - * N.B. Unless isNew is set or the item doesn't yet have an id, - * this function updates the DB immediately and - * reloads all cached items -- a save() is not required - * - * If isNew is true, a transaction is not started or committed, so if - * the item has an id it should only be run from an existing transaction - * within Scholar.Item.save() - */ -Scholar.Item.prototype.setPosition = function(newFolder, newPos, isNew){ - var oldFolder = this.getField('parentFolderID'); - var oldPos = this.getField('orderIndex'); - - if (this.getID()){ - if (!isNew && newFolder==oldFolder && newPos==oldPos){ - return true; - } - - if (!isNew){ - Scholar.DB.beginTransaction(); - } - - if (!newFolder){ - newFolder = 0; - } - // Do a foreign key check manually - else if (!parseInt(Scholar.DB.valueQuery('SELECT COUNT(*) FROM folders ' - + 'WHERE folderID=' + newFolder))){ - throw('Attempt to add item to invalid folder'); - } - - // If no position provided, drop at end of folder - if (!newPos){ - newPos = Scholar.DB.valueQuery('SELECT MAX(orderIndex)+1 FROM ' + - 'treeStructure WHERE parentFolderID=' + newFolder); - } - // Otherwise shift down above it in old folder and shift up at it or - // above it in new folder - else { - sql = 'UPDATE treeStructure SET orderIndex=orderIndex-1 ' + - 'WHERE parentFolderID=' + oldFolder + - ' AND orderIndex>' + oldPos + ";\n"; - - sql += 'UPDATE treeStructure SET orderIndex=orderIndex+1 ' + - 'WHERE parentFolderID=' + newFolder + - ' AND orderIndex>=' + newPos + ";\n"; - - Scholar.DB.query(sql); - } - - // If a new item, insert - if (isNew){ - var sql = 'INSERT INTO treeStructure ' - + '(id, isFolder, orderIndex, parentFolderID) VALUES (' - + this.getID() + ', 0, ' + newPos + ', ' + newFolder + ')'; - } - // Otherwise update - else { - var sql = 'UPDATE treeStructure SET parentFolderID=' + newFolder + - ', orderIndex=' + newPos + ' WHERE id=' + this.getID() + - " AND isFolder=0;\n"; - } - Scholar.DB.query(sql); - - if (!isNew){ - Scholar.DB.commitTransaction(); - } - } - - this._data['parentFolderID'] = newFolder; - this._data['orderIndex'] = newPos; - - if (this.getID() && !isNew){ - Scholar.Items.reloadAll(); - Scholar.Folders.reloadAll(); // needed to recheck isEmpty - } - return true; -} - - /* * Save changes back to database */ @@ -428,12 +346,6 @@ Scholar.Item.prototype.save = function(){ if (this._changed.has('title')){ sql += "title='" + this.getField('title') + "', "; } - if (this._changed.has('source')){ - sql += "source='" + this.getField('source') + "', "; - } - if (this._changed.has('rights')){ - sql += "rights='" + this.getField('rights') + "', "; - } // Always update modified time sql += "dateModified=CURRENT_TIMESTAMP "; @@ -583,14 +495,6 @@ Scholar.Item.prototype.save = function(){ sqlColumns.push('title'); sqlValues.push({'string':this.getField('title')}); } - if (this._changed.has('source')){ - sqlColumns.push('source'); - sqlValues.push({'string':this.getField('source')}); - } - if (this._changed.has('rights')){ - sqlColumns.push('rights'); - sqlValues.push({'string':this.getField('rights')}); - } try { Scholar.DB.beginTransaction(); @@ -668,20 +572,11 @@ Scholar.Item.prototype.save = function(){ } } - // Set the position of the new item - var newFolder = this.getField('parentFolderID') - ? this.getField('parentFolderID') : 0; - - var newPos = this.getField('orderIndex') - ? this.getField('orderIndex') : false; - - this.setPosition(newFolder, newPos, true); - Scholar.DB.commitTransaction(); - // Reload folders to update isEmpty, - // in case this was the first item in a folder - Scholar.Folders.reloadAll(); + // Reload collection to update isEmpty, + // in case this was the first item in a collection + Scholar.Collections.reloadAll(); } catch (e){ Scholar.DB.rollbackTransaction(); @@ -707,15 +602,11 @@ Scholar.Item.prototype.erase = function(){ Scholar.DB.beginTransaction(); - - var parentFolderID = this.getField('parentFolderID'); - var orderIndex = this.getField('orderIndex'); - - var sql = 'DELETE FROM treeStructure WHERE id=' + this.getID() + ";\n"; - - sql += 'UPDATE treeStructure SET orderIndex=orderIndex-1 ' + - 'WHERE parentFolderID=' + parentFolderID + - ' AND orderIndex>' + orderIndex + ";\n\n"; + // Remove item from parent collections + var parentCollectionIDs = this.getCollections(); + for (var i=0; i0"; // skip 'root' folder + // This should be the same as the query in Scholar.Collection.loadFromID, + // just without a specific collectionID + var sql = "SELECT collectionID, collectionName, parentCollectionID, " + + "(SELECT COUNT(*) FROM collections WHERE " + + "parentCollectionID=C.collectionID)!=0 AS hasChildCollections, " + + "(SELECT COUNT(*) FROM collectionItems WHERE " + + "collectionID=C.collectionID)!=0 AS hasChildItems " + + "FROM collections C"; + var result = Scholar.DB.query(sql); if (!result){ - throw ('No folders exist'); + throw ('No collections exist'); } for (var i=0; i