diff --git a/chrome/content/zotero/xpcom/id.js b/chrome/content/zotero/xpcom/id.js index 1d2130234..6712858b3 100644 --- a/chrome/content/zotero/xpcom/id.js +++ b/chrome/content/zotero/xpcom/id.js @@ -24,18 +24,19 @@ Zotero.ID = new function () { this.get = get; this.getKey = getKey; this.getBigInt = getBigInt; + this.skip = skip; + this.getTableName = getTableName; _available = {}; _min = {}; + _skip = {}; + /* * Gets an unused primary key id for a DB table */ - function get(table, notNull, skip) { - // Used in sync.js - if (table == 'searches') { - table = 'savedSearches'; - } + function get(table, notNull) { + table = this.getTableName(table); switch (table) { // Autoincrement tables @@ -48,9 +49,9 @@ Zotero.ID = new function () { case 'collections': case 'savedSearches': case 'tags': - var id = _getNextAvailable(table, skip); + var id = _getNextAvailable(table); if (!id && notNull) { - return _getNext(table, skip); + return _getNext(table); } return id; @@ -58,10 +59,10 @@ Zotero.ID = new function () { // // TODO: use autoincrement instead where available in 1.5 case 'itemDataValues': - var id = _getNextAvailable(table, skip); + var id = _getNextAvailable(table); if (!id) { // If we can't find an empty id quickly, just use MAX() + 1 - return _getNext(table, skip); + return _getNext(table); } return id; @@ -82,10 +83,67 @@ Zotero.ID = new function () { } + /** + * Mark ids as used + * + * @param string table + * @param int|array ids Item ids to skip + */ + function skip(table, ids) { + table = this.getTableName(table); + + switch (ids.constructor.name) { + case 'Array': + break; + + case 'Number': + ids = [ids]; + break; + + default: + throw ("ids must be an int or array of ints in Zotero.ID.skip()"); + } + + if (!ids.length) { + return; + } + + if (!_skip[table]) { + _skip[table] = {}; + } + + for (var i=0, len=ids.length; i max) { + max = id; + } + } + if (!max) { + throw ("_skip['" + table + "'] must contain positive values in Zotero.ID._getNext()"); + } sql += 'MAX(' + column + ', ' + max + ')'; } else { @@ -287,3 +353,31 @@ Zotero.ID = new function () { } } + + +/** + * Notifier observer to mark saved object ids as used + */ +Zotero.ID.EventListener = new function () { + this.init = init; + this.notify = notify; + + function init() { + Zotero.Notifier.registerObserver(this); + } + + + function notify(event, type, ids) { + if (event == 'add') { + try { + var table = Zotero.ID.getTableName(type); + } + // Skip if not a table we handle + catch (e) { + return; + } + Zotero.ID.skip(table, ids); + } + } +} + diff --git a/chrome/content/zotero/xpcom/sync.js b/chrome/content/zotero/xpcom/sync.js index c4062d1df..b60a61544 100644 --- a/chrome/content/zotero/xpcom/sync.js +++ b/chrome/content/zotero/xpcom/sync.js @@ -1189,15 +1189,7 @@ Zotero.Sync.Server.Data = new function() { else { var oldID = parseInt(xmlNode.@id); - // Don't use assigned-but-unsaved ids for the new id - var skip = []; - for each(var o in toSaveParents) { - skip.push(o.id); - } - for each(var o in toSaveChildren) { - skip.push(o.id); - } - var newID = Zotero.ID.get(types, true, skip); + var newID = Zotero.ID.get(types, true); Zotero.debug("Changing " + type + " " + oldID + " id to " + newID); @@ -1289,6 +1281,9 @@ Zotero.Sync.Server.Data = new function() { else { toSaveParents.push(obj); } + + // Don't use assigned-but-unsaved ids for new ids + Zotero.ID.skip(types, obj.id); } @@ -1378,6 +1373,9 @@ Zotero.Sync.Server.Data = new function() { toSaveChildren.push(obj.ref); } + // Don't use assigned-but-unsaved ids for new ids + Zotero.ID.skip(types, obj.id); + // Item had been deleted locally, so remove from // deleted array if (obj.left == 'deleted') {