diff --git a/chrome/chromeFiles/content/scholar/xpcom/data_access.js b/chrome/chromeFiles/content/scholar/xpcom/data_access.js index 34e91dd81f..e69252da5a 100644 --- a/chrome/chromeFiles/content/scholar/xpcom/data_access.js +++ b/chrome/chromeFiles/content/scholar/xpcom/data_access.js @@ -981,6 +981,60 @@ Scholar.Item.prototype.removeTag = function(tagID){ } +// +// Methods dealing with See Also links +// +// save() is not required for See Also functions +// +Scholar.Item.prototype.addSeeAlso = function(itemID){ + if (itemID==this.getID()){ + Scholar.debug('Cannot add item as See Also of itself', 2); + return false; + } + + Scholar.DB.beginTransaction(); + + if (!Scholar.Items.get(itemID)){ + Scholar.DB.commitTransaction(); + throw ("Cannot add invalid item " + itemID + " as See Also"); + return false; + } + + // Check both ways, using a UNION to take advantage of indexes + var sql = "SELECT (SELECT COUNT(*) FROM itemSeeAlso WHERE itemID=?1 AND " + + "linkedItemID=?2) + (SELECT COUNT(*) FROM itemSeeAlso WHERE " + + "linkedItemID=?1 AND itemID=?2)"; + if (Scholar.DB.valueQuery(sql, [this.getID(), itemID])){ + Scholar.DB.commitTransaction(); + Scholar.debug("Item " + itemID + " already linked", 2); + return false; + } + + var sql = "INSERT INTO itemSeeAlso VALUES (?,?)"; + Scholar.DB.query(sql, [this.getID(), {int:itemID}]); + Scholar.DB.commitTransaction(); + Scholar.Notifier.trigger('modify', 'item', [this.getID(), itemID]); + return true; +} + +Scholar.Item.prototype.removeSeeAlso = function(itemID){ + Scholar.DB.beginTransaction(); + var sql = "DELETE FROM itemSeeAlso WHERE itemID=? AND linkedItemID=?"; + Scholar.DB.query(sql, [this.getID(), itemID]); + var sql = "DELETE FROM itemSeeAlso WHERE itemID=? AND linkedItemID=?"; + Scholar.DB.query(sql, [itemID, this.getID()]); + Scholar.DB.commitTransaction(); + Scholar.Notifier.trigger('modify', 'item', [this.getID(), itemID]); +} + +Scholar.Item.prototype.getSeeAlso = function(){ + // Check both ways, using a UNION to take advantage of indexes + var sql ="SELECT linkedItemID FROM itemSeeAlso WHERE itemID=?1 UNION " + + "SELECT itemID FROM itemSeeAlso WHERE linkedItemID=?1"; + return Scholar.DB.columnQuery(sql, this.getID()); +} + + /** * Delete item from database and clear from Scholar.Items internal array **/ @@ -990,7 +1044,9 @@ Scholar.Item.prototype.erase = function(){ } Scholar.debug('Deleting item ' + this.getID()); - + + var changedItems = []; + Scholar.DB.beginTransaction(); // Remove item from parent collections @@ -1006,7 +1062,7 @@ Scholar.Item.prototype.erase = function(){ if (sourceItemID){ var sourceItem = Scholar.Items.get(sourceItemID); sourceItem.decrementNoteCount(); - Scholar.Notifier.trigger('modify', 'item', sourceItemID); + changedItems.push(sourceItemID); } } // If not note, unassociate any notes for which this is a source @@ -1015,16 +1071,25 @@ Scholar.Item.prototype.erase = function(){ var sql = "SELECT itemID FROM itemNotes WHERE sourceItemID=" + this.getID(); var childNotes = Scholar.DB.columnQuery(sql); + if (childNotes){ + changedItems.push(childNotes); + } var sql = "UPDATE itemNotes SET sourceItemID=NULL WHERE sourceItemID=" + this.getID(); Scholar.DB.query(sql); } - // TODO: remove item from See Also table + // Flag See Also links for notification + var seeAlso = this.getSeeAlso(); + if (seeAlso){ + changedItems = changedItems.concat(seeAlso); + } sql = 'DELETE FROM itemCreators WHERE itemID=' + this.getID() + ";\n"; sql += 'DELETE FROM itemNotes WHERE itemID=' + this.getID() + ";\n"; + sql += 'DELETE FROM itemSeeAlso WHERE itemID=' + this.getID() + ";\n"; + sql += 'DELETE FROM itemSeeAlso WHERE linkedItemID=' + this.getID() + ";\n"; sql += 'DELETE FROM itemTags WHERE itemID=' + this.getID() + ";\n"; sql += 'DELETE FROM itemData WHERE itemID=' + this.getID() + ";\n"; sql += 'DELETE FROM items WHERE itemID=' + this.getID() + ";\n"; @@ -1045,9 +1110,9 @@ Scholar.Item.prototype.erase = function(){ Scholar.Items.unload(this.getID()); - // Send notification of unlinked notes - if (childNotes){ - Scholar.Notifier.trigger('modify', 'item', childNotes); + // Send notification of changed items + if (changedItems.length){ + Scholar.Notifier.trigger('modify', 'item', changedItems); } // If we're not in the middle of a larger commit, trigger the notifier now diff --git a/chrome/chromeFiles/content/scholar/xpcom/schema.js b/chrome/chromeFiles/content/scholar/xpcom/schema.js index 5c15095d4d..34b76e3ea1 100644 --- a/chrome/chromeFiles/content/scholar/xpcom/schema.js +++ b/chrome/chromeFiles/content/scholar/xpcom/schema.js @@ -385,7 +385,7 @@ Scholar.Schema = new function(){ // // Change this value to match the schema version // - var toVersion = 27; + var toVersion = 28; if (toVersion != _getSchemaSQLVersion()){ throw('Schema version does not match version in _migrateSchema()'); @@ -400,10 +400,9 @@ Scholar.Schema = new function(){ // 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==26){ + if (i==28){ Scholar.DB.query("DROP TABLE IF EXISTS keywords"); Scholar.DB.query("DROP TABLE IF EXISTS itemKeywords"); - } else if(i==27) { Scholar.DB.query("DROP TABLE IF EXISTS scrapers"); _initializeSchema(); } diff --git a/schema.sql b/schema.sql index d4c9aebf1a..1d82fdc671 100644 --- a/schema.sql +++ b/schema.sql @@ -1,4 +1,4 @@ --- 27 +-- 28 DROP TABLE IF EXISTS version; CREATE TABLE version ( @@ -89,6 +89,17 @@ DROP INDEX IF EXISTS itemTags_tagID; CREATE INDEX itemTags_tagID ON itemTags(tagID); + DROP TABLE IF EXISTS itemSeeAlso; + CREATE TABLE itemSeeAlso ( + itemID INT, + linkedItemID INT, + PRIMARY KEY (itemID, linkedItemID), + FOREIGN KEY (itemID) REFERENCES items(itemID), + FOREIGN KEY (linkedItemID) REFERENCES items(itemID) + ); + DROP INDEX IF EXISTS itemSeeAlso_linkedItemID; + CREATE INDEX itemSeeAlso_linkedItemID ON itemSeeAlso(linkedItemID); + DROP TABLE IF EXISTS creators; CREATE TABLE creators ( creatorID INT,