diff --git a/chrome/content/zotero/xpcom/data/collection.js b/chrome/content/zotero/xpcom/data/collection.js index 52c4bcbbe..91e356a94 100644 --- a/chrome/content/zotero/xpcom/data/collection.js +++ b/chrome/content/zotero/xpcom/data/collection.js @@ -590,72 +590,70 @@ Zotero.Collection.prototype.clone = function (includePrimary, newCollection) { /** * Deletes collection and all descendent collections (and optionally items) **/ -Zotero.Collection.prototype.erase = function(deleteItems) { - var collections = [this.id]; - var notifierData = {}; +Zotero.Collection.prototype._eraseData = Zotero.Promise.coroutine(function* (deleteItems) { + Zotero.DB.requireTransaction(); - return Zotero.DB.executeTransaction(function* () { - var descendents = yield this.getDescendents(false, null, true); - var items = []; - notifierData[this.id] = { - libraryID: this.libraryID, - key: this.key - }; - - var del = []; - for(var i=0, len=descendents.length; i { - // Clear deleted collection from internal memory - this.ObjectsClass.unload(collections); - //return Zotero.Collections.reloadAll(); - }) - .then(function () { - Zotero.Notifier.trigger('delete', 'collection', collections, notifierData); - }); -} + } + if (del.length) { + yield this.ChildObjects.trash(del); + } + + // Remove relations + var uri = Zotero.URI.getCollectionURI(this); + yield Zotero.Relations.eraseByURI(uri); + + var placeholders = collections.map(function () '?').join(); + + // Remove item associations for all descendent collections + yield Zotero.DB.queryAsync('DELETE FROM collectionItems WHERE collectionID IN ' + + '(' + placeholders + ')', collections); + + // Remove parent definitions first for FK check + yield Zotero.DB.queryAsync('UPDATE collections SET parentCollectionID=NULL ' + + 'WHERE parentCollectionID IN (' + placeholders + ')', collections); + + // And delete all descendent collections + yield Zotero.DB.queryAsync ('DELETE FROM collections WHERE collectionID IN ' + + '(' + placeholders + ')', collections); + + // TODO: Update member items + // Clear deleted collection from internal memory + this.ObjectsClass.unload(collections); + //return Zotero.Collections.reloadAll(); + + Zotero.Notifier.trigger('delete', 'collection', collections, notifierData); +}); Zotero.Collection.prototype.isCollection = function() { diff --git a/chrome/content/zotero/xpcom/data/collections.js b/chrome/content/zotero/xpcom/data/collections.js index acee37d24..30bcc43db 100644 --- a/chrome/content/zotero/xpcom/data/collections.js +++ b/chrome/content/zotero/xpcom/data/collections.js @@ -209,7 +209,7 @@ Zotero.Collections = function() { } this.unload(ids); - }); + }.bind(this)); }; Zotero.DataObjects.call(this); diff --git a/chrome/content/zotero/xpcom/data/dataObject.js b/chrome/content/zotero/xpcom/data/dataObject.js index 3bbdee504..5cda6d362 100644 --- a/chrome/content/zotero/xpcom/data/dataObject.js +++ b/chrome/content/zotero/xpcom/data/dataObject.js @@ -714,20 +714,45 @@ Zotero.DataObject.prototype._recoverFromSaveError = Zotero.Promise.coroutine(fun /** * Delete object from database */ -Zotero.DataObject.prototype.erase = Zotero.Promise.coroutine(function* () { - var env = {}; +Zotero.DataObject.prototype.erase = Zotero.Promise.coroutine(function* (options) { + options = options || {}; + var env = { + options: options + }; + + if (!env.options.tx && !Zotero.DB.inTransaction()) { + Zotero.logError("erase() called on Zotero." + this._ObjectType + " without a wrapping " + + "transaction -- use eraseTx() instead"); + Zotero.debug((new Error).stack, 2); + env.options.tx = true; + } var proceed = yield this._eraseInit(env); if (!proceed) return false; Zotero.debug('Deleting ' + this.objectType + ' ' + this.id); - Zotero.DB.requireTransaction(); - yield this._eraseData(env); - yield this._erasePreCommit(env); - return this._erasePostCommit(env); + if (env.options.tx) { + return Zotero.DB.executeTransaction(function* () { + yield this._eraseData(env); + yield this._erasePreCommit(env); + return this._erasePostCommit(env); + }.bind(this)) + } + else { + Zotero.DB.requireTransaction(); + yield this._eraseData(env); + yield this._erasePreCommit(env); + return this._erasePostCommit(env); + } }); +Zotero.DataObject.prototype.eraseTx = function (options) { + options = options || {}; + options.tx = true; + return this.erase(options); +}; + Zotero.DataObject.prototype._eraseInit = function(env) { if (!this.id) return Zotero.Promise.resolve(false); diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index a3ca5c1c7..2f47c6621 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -1174,10 +1174,7 @@ Zotero.Item.prototype.isEditable = function() { } Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) { - // Sanity check - if (!Zotero.DB.inTransaction()) { - throw new Error("Not in transaction saving item " + this.libraryKey); - } + Zotero.DB.requireTransaction(); var isNew = env.isNew; var options = env.options; @@ -1729,10 +1726,7 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) { } } - // Sanity check - if (!Zotero.DB.inTransaction()) { - throw new Error("Not in transaction saving item " + this.libraryKey); - } + Zotero.DB.requireTransaction(); }); Zotero.Item.prototype._finalizeSave = Zotero.Promise.coroutine(function* (env) { @@ -3919,6 +3913,8 @@ Zotero.Item.prototype._eraseInit = Zotero.Promise.coroutine(function* (env) { }); Zotero.Item.prototype._eraseData = Zotero.Promise.coroutine(function* (env) { + Zotero.DB.requireTransaction(); + // Remove item from parent collections var parentCollectionIDs = this.collections; if (parentCollectionIDs) { diff --git a/chrome/content/zotero/xpcom/search.js b/chrome/content/zotero/xpcom/search.js index e0e86d9cd..0d46ec524 100644 --- a/chrome/content/zotero/xpcom/search.js +++ b/chrome/content/zotero/xpcom/search.js @@ -92,25 +92,28 @@ Zotero.Search.prototype._set = function (field, value) { return this._setIdentifier(field, value); } - switch (field) { - case 'name': - value = value.trim().normalize(); - break; - - case 'version': - value = parseInt(value); - break; - - case 'synced': - value = !!value; - break; - } - this._requireData('primaryData'); + switch (field) { + case 'name': + value = value.trim().normalize(); + break; + + case 'version': + value = parseInt(value); + break; + + case 'synced': + value = !!value; + break; + } + if (this['_' + field] != value) { this._markFieldChange(field, this['_' + field]); - this._changed.primaryData = true; + if (!this._changed.primaryData) { + this._changed.primaryData = {}; + } + this._changed.primaryData[field] = true; switch (field) { default: @@ -119,13 +122,12 @@ Zotero.Search.prototype._set = function (field, value) { } } - Zotero.Search.prototype.loadFromRow = function (row) { this._id = row.savedSearchID; - this._libraryID = row.libraryID; + this._libraryID = parseInt(row.libraryID); this._key = row.key; this._name = row.name; - this._version = row.version; + this._version = parseInt(row.version); this._synced = !!row.synced; this._loaded.primaryData = true; @@ -147,8 +149,7 @@ Zotero.Search.prototype._saveData = Zotero.Promise.coroutine(function* (env) { var searchID = env.id = this._id = this.id ? this.id : yield Zotero.ID.get('savedSearches'); env.sqlColumns.push( - 'savedSearchName', - 'savedSearchID' + 'savedSearchName' ); env.sqlValues.push( { string: this.name } @@ -251,6 +252,25 @@ Zotero.Search.prototype.clone = function (libraryID) { }; +Zotero.Search.prototype._eraseData = Zotero.Promise.coroutine(function* () { + Zotero.DB.requireTransaction(); + + var notifierData = {}; + notifierData[this.id] = { + libraryID: this.libraryID, + key: this.key + }; + + var sql = "DELETE FROM savedSearchConditions WHERE savedSearchID=?"; + yield Zotero.DB.queryAsync(sql, this.id); + + var sql = "DELETE FROM savedSearches WHERE savedSearchID=?"; + yield Zotero.DB.queryAsync(sql, this.id); + + Zotero.Notifier.trigger('delete', 'search', this.id, notifierData); +}); + + Zotero.Search.prototype.addCondition = function (condition, operator, value, required) { this._requireData('conditions'); @@ -1690,29 +1710,13 @@ Zotero.Searches = function() { */ this.erase = Zotero.Promise.coroutine(function* (ids) { ids = Zotero.flattenArguments(ids); - var notifierData = {}; yield Zotero.DB.executeTransaction(function* () { for (let i=0; i