From 4782c725e716c91ae9535c5c258c1ddcbb92bd0f Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Fri, 10 Oct 2008 01:48:19 +0000 Subject: [PATCH] Reworked and standarized data object caching -- this should fix problems of long-term references containing stale, orphaned versions of data objects --- .../content/zotero/xpcom/data/collection.js | 1 - .../content/zotero/xpcom/data/collections.js | 125 +++++++----------- chrome/content/zotero/xpcom/data/creator.js | 43 ++++-- chrome/content/zotero/xpcom/data/creators.js | 102 +++++++------- .../content/zotero/xpcom/data/dataObjects.js | 90 +++++++++++++ chrome/content/zotero/xpcom/data/item.js | 4 +- chrome/content/zotero/xpcom/data/items.js | 97 +++++--------- chrome/content/zotero/xpcom/data/tag.js | 28 ++-- chrome/content/zotero/xpcom/data/tags.js | 79 +++++++---- chrome/content/zotero/xpcom/zotero.js | 4 +- 10 files changed, 317 insertions(+), 256 deletions(-) diff --git a/chrome/content/zotero/xpcom/data/collection.js b/chrome/content/zotero/xpcom/data/collection.js index 5defa0e4b..f822f30b6 100644 --- a/chrome/content/zotero/xpcom/data/collection.js +++ b/chrome/content/zotero/xpcom/data/collection.js @@ -310,7 +310,6 @@ Zotero.Collection.prototype.save = function () { Zotero.DB.query("DELETE FROM collections WHERE collectionID=?", oldID); Zotero.DB.query("UPDATE collections SET key=? WHERE collectionID=?", [row.key, this.id]); - Zotero.Collections.unload(oldID); Zotero.Notifier.trigger('id-change', 'collection', oldID + '-' + this.id); // Update child collections that have cached the previous id diff --git a/chrome/content/zotero/xpcom/data/collections.js b/chrome/content/zotero/xpcom/data/collections.js index f366926a0..f16698c5e 100644 --- a/chrome/content/zotero/xpcom/data/collections.js +++ b/chrome/content/zotero/xpcom/data/collections.js @@ -28,26 +28,20 @@ Zotero.Collections = new function() { Zotero.DataObjects.apply(this, ['collection']); this.constructor.prototype = new Zotero.DataObjects(); - var _collections = {}; - var _collectionsLoaded = false; - this.get = get; this.add = add; this.getUpdated = getUpdated; this.getCollectionsContainingItems = getCollectionsContainingItems; - this.reload = reload; - this.reloadAll = reloadAll; this.erase = erase; - this.unload = unload; /* * Returns a Zotero.Collection object for a collectionID */ function get(id) { - if (!_collectionsLoaded) { + if (this._reloadCache) { this.reloadAll(); } - return (typeof _collections[id]!='undefined') ? _collections[id] : false; + return this._objectCache[id] ? this._objectCache[id] : false; } @@ -107,8 +101,8 @@ Zotero.Collections = new function() { ids = Zotero.flattenArguments(ids); for each(var id in ids) { - if (_collections[id]) { - _collections[id]._refreshParent(); + if (this._objectCache[id]) { + this._objectCache[id]._refreshParent(); } } } @@ -124,68 +118,13 @@ Zotero.Collections = new function() { ids = Zotero.flattenArguments(ids); for each(var id in ids) { - if (_collections[id]) { - _collections[id]._refreshChildCollections(); + if (this._objectCache[id]) { + this._objectCache[id]._refreshChildCollections(); } } } - function reload(id) { - if (!_collectionsLoaded) { - this.reloadAll(); - return; - } - - if (!_collections[id]) { - _collections[id] = new Zotero.Collection(id); - } - _collections[id].load(); - } - - - /** - * Loads collection data from DB and adds to internal cache - **/ - function reloadAll() { - Zotero.debug('Loading all collections'); - - // This should be the same as the query in Zotero.Collection.load(), - // just without a specific collectionID - var sql = "SELECT C.*, " - + "(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 = Zotero.DB.query(sql); - - var collectionIDs = []; - - if (result) { - for (var i=0; i 0) { + this._load(items); + } + else { + this._load(); + } var primaryFields = []; var fieldIDs = []; @@ -270,7 +248,7 @@ Zotero.Items = new function() { var rows = Zotero.DB.query(sql); for each(var row in rows) { //Zotero.debug('Calling loadFromRow for item ' + row.itemID); - _items[row.itemID].loadFromRow(row); + this._objectCache[row.itemID].loadFromRow(row); } } @@ -292,8 +270,8 @@ Zotero.Items = new function() { var itemDataRows = Zotero.DB.query(sql); for each(var row in itemDataRows) { //Zotero.debug('Setting field ' + row.fieldID + ' for item ' + row.itemID); - if (_items[row.itemID]) { - _items[row.itemID].setField(row.fieldID, row.value, true); + if (this._objectCache[row.itemID]) { + this._objectCache[row.itemID].setField(row.fieldID, row.value, true); } else { if (!missingItems) { @@ -323,8 +301,8 @@ Zotero.Items = new function() { for each(var row in rows) { //Zotero.debug('Setting title for note ' + row.itemID); - if (_items[row.itemID]) { - _items[row.itemID].setField(titleFieldID, row['title'], true); + if (this._objectCache[row.itemID]) { + this._objectCache[row.itemID].setField(titleFieldID, row.title, true); } else { if (!missingItems) { @@ -341,10 +319,10 @@ Zotero.Items = new function() { // Set nonexistent fields in the cache list to false (instead of null) for each(var itemID in allItemIDs) { for each(var fieldID in fieldIDs) { - if (Zotero.ItemFields.isValidForType(fieldID, _items[itemID].itemTypeID)) { + if (Zotero.ItemFields.isValidForType(fieldID, this._objectCache[itemID].itemTypeID)) { if (!itemFieldsCached[itemID] || !itemFieldsCached[itemID][fieldID]) { //Zotero.debug('Setting field ' + fieldID + ' to false for item ' + itemID); - _items[itemID].setField(fieldID, false, true); + this._objectCache[itemID].setField(fieldID, false, true); } } } @@ -409,14 +387,6 @@ Zotero.Items = new function() { } - /** - * Clear item from internal array (used by Zotero.Item.erase()) - **/ - function unload(id) { - delete _items[id]; - } - - /* * Generate SQL to retrieve firstCreator field * @@ -541,8 +511,8 @@ Zotero.Items = new function() { } - function _load() { - if (!arguments[0] && _itemsLoaded) { + this._load = function () { + if (!arguments[0] && !this._reloadCache) { return; } @@ -552,9 +522,8 @@ Zotero.Items = new function() { + "(SELECT COUNT(*) FROM itemNotes WHERE sourceItemID=I.itemID) AS numNotes, " + "(SELECT COUNT(*) FROM itemAttachments WHERE sourceItemID=I.itemID) AS numAttachments " + 'FROM items I WHERE 1'; - if (arguments[0]) { - sql += ' AND I.itemID IN (' + Zotero.join(arguments,',') + ')'; + sql += ' AND I.itemID IN (' + Zotero.join(arguments[0], ',') + ')'; } var itemsRows = Zotero.DB.query(sql); var itemIDs = []; @@ -564,30 +533,28 @@ Zotero.Items = new function() { itemIDs.push(itemID); // Item doesn't exist -- create new object and stuff in array - if (!_items[row.itemID]) { + if (!this._objectCache[row.itemID]) { var item = new Zotero.Item(); item.loadFromRow(row, true); - _items[row.itemID] = item; + this._objectCache[row.itemID] = item; } // Existing item -- reload in place else { - _items[row.itemID].loadFromRow(row, true); + this._objectCache[row.itemID].loadFromRow(row, true); } } // If loading all items, remove old items that no longer exist if (!arguments[0]) { - for each(var c in _items) { + for each(var c in this._objectCache) { if (itemIDs.indexOf(c.id) == -1) { this.unload(c.id); } } - } - - if (!arguments[0]) { - _itemsLoaded = true; + _cachedFields = ['itemID', 'itemTypeID', 'dateAdded', 'dateModified', 'firstCreator', 'numNotes', 'numAttachments', 'numChildren']; + this._reloadCache = false; } } } diff --git a/chrome/content/zotero/xpcom/data/tag.js b/chrome/content/zotero/xpcom/data/tag.js index 46dd86f5d..8a946443e 100644 --- a/chrome/content/zotero/xpcom/data/tag.js +++ b/chrome/content/zotero/xpcom/data/tag.js @@ -118,21 +118,26 @@ Zotero.Tag.prototype.load = function() { } var sql = "SELECT name, type, dateModified, key FROM tags WHERE tagID=?"; - var data = Zotero.DB.rowQuery(sql, this.id); + var row = Zotero.DB.rowQuery(sql, this.id); - this._init(); - this._loaded = true; - - if (!data) { - return; - } - - for (var key in data) { - this['_' + key] = data[key]; - } + this.loadFromRow(row); + return true; } +Zotero.Tag.prototype.loadFromRow = function (row) { + this._init(); + + for (var col in row) { + //Zotero.debug("Setting field '" + col + "' to '" + row[col] + "' for tag " + this.id); + this['_' + col] = row[col] ? row[col] : ''; + } + + this._loaded = true; +} + + + /** * Returns items linked to this tag * @@ -249,7 +254,6 @@ Zotero.Tag.prototype.save = function () { Zotero.DB.query("UPDATE tags SET key=? WHERE tagID=?", [row.key, this.id]); - Zotero.Tags.unload(oldID); Zotero.Notifier.trigger('id-change', 'tag', oldID + '-' + this.id); // update caches diff --git a/chrome/content/zotero/xpcom/data/tags.js b/chrome/content/zotero/xpcom/data/tags.js index c9057a667..adb21fe6f 100644 --- a/chrome/content/zotero/xpcom/data/tags.js +++ b/chrome/content/zotero/xpcom/data/tags.js @@ -29,7 +29,6 @@ Zotero.Tags = new function() { this.constructor.prototype = new Zotero.DataObjects(); var _tags = {}; // indexed by tag text - var _tagsByID = {}; // indexed by tagID this.get = get; this.getName = getName; @@ -42,31 +41,18 @@ Zotero.Tags = new function() { this.getTagItems = getTagItems; this.search = search; this.rename = rename; - this.reload = reload; this.erase = erase; this.purge = purge; - this.unload = unload; /* * Returns a tag and type for a given tagID */ - function get(tagID, skipCheck) { - if (_tagsByID[tagID]) { - return _tagsByID[tagID]; + function get(id, skipCheck) { + if (this._reloadCache) { + this.reloadAll(); } - - if (!skipCheck) { - var sql = 'SELECT COUNT(*) FROM tags WHERE tagID=?'; - var result = Zotero.DB.valueQuery(sql, tagID); - - if (!result) { - return false; - } - } - - _tagsByID[tagID] = new Zotero.Tag(tagID); - return _tagsByID[tagID]; + return this._objectCache[id] ? this._objectCache[id] : false; } @@ -326,11 +312,6 @@ Zotero.Tags = new function() { } - function reload(ids) { - this.unload(ids); - } - - function erase(ids) { ids = Zotero.flattenArguments(ids); @@ -415,12 +396,12 @@ Zotero.Tags = new function() { * * @param int|array ids One or more tagIDs */ - function unload() { + this.unload = function () { var ids = Zotero.flattenArguments(arguments); for each(var id in ids) { - var tag = _tagsByID[id]; - delete _tagsByID[id]; + var tag = this._objectCache[id]; + delete this._objectCache[id]; if (tag && _tags[tag.type]) { delete _tags[tag.type]['_' + tag.name]; } @@ -428,9 +409,49 @@ Zotero.Tags = new function() { } - this.unloadAll = function (ids) { - _tags = {}; - _tagsByID = {}; + this._load = function () { + if (!arguments[0] && !this._reloadCache) { + return; + } + + if (this._reloadCache) { + _tags = {}; + } + + this._reloadCache = false; + + // This should be the same as the query in Zotero.Tag.load(), + // just without a specific tagID + var sql = "SELECT * FROM tags WHERE 1"; + if (arguments[0]) { + sql += " AND tagID IN (" + Zotero.join(arguments[0], ",") + ")"; + } + var rows = Zotero.DB.query(sql); + var ids = []; + for each(var row in rows) { + var id = row.tagID; + ids.push(id); + + // Tag doesn't exist -- create new object and stuff in array + if (!this._objectCache[id]) { + //this.get(id); + this._objectCache[id] = new Zotero.Tag; + this._objectCache[id].loadFromRow(row); + } + // Existing tag -- reload in place + else { + this._objectCache[id].loadFromRow(row); + } + } + + if (!arguments[0]) { + // If loading all tags, remove old tags that no longer exist + for each(var c in this._objectCache) { + if (ids.indexOf(c.id) == -1) { + this.unload(c.id); + } + } + } } } diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js index 33a4553e9..36a2e9119 100644 --- a/chrome/content/zotero/xpcom/zotero.js +++ b/chrome/content/zotero/xpcom/zotero.js @@ -934,9 +934,9 @@ var Zotero = new function(){ function reloadDataObjects() { - Zotero.Tags.unloadAll(); + Zotero.Tags.reloadAll(); Zotero.Collections.reloadAll(); - Zotero.Creators.unloadAll(); + Zotero.Creators.reloadAll(); Zotero.Items.reloadAll(); } };