Closes #711, Remove support for nested transactions
This commit is contained in:
parent
e584dbf5dd
commit
14d435b8d8
23 changed files with 862 additions and 856 deletions
|
@ -1109,7 +1109,7 @@
|
||||||
this.item.setType(itemTypeID);
|
this.item.setType(itemTypeID);
|
||||||
|
|
||||||
if (this.saveOnEdit) {
|
if (this.saveOnEdit) {
|
||||||
this.item.save();
|
this.item.saveTx();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
|
@ -1357,7 +1357,7 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.item.removeCreator(index);
|
this.item.removeCreator(index);
|
||||||
this.item.save();
|
this.item.saveTx();
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
@ -1766,7 +1766,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.saveOnEdit) {
|
if (this.saveOnEdit) {
|
||||||
yield this.item.save();
|
yield this.item.saveTx();
|
||||||
}
|
}
|
||||||
|
|
||||||
var val = this.item.getCreator(creatorIndex);
|
var val = this.item.getCreator(creatorIndex);
|
||||||
|
@ -1915,7 +1915,7 @@
|
||||||
return Zotero.spawn(function* () {
|
return Zotero.spawn(function* () {
|
||||||
this.item.setField(field, value);
|
this.item.setField(field, value);
|
||||||
if (save) {
|
if (save) {
|
||||||
yield this.item.save();
|
yield this.item.saveTx();
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
]]></body>
|
]]></body>
|
||||||
|
@ -2034,14 +2034,14 @@
|
||||||
}
|
}
|
||||||
this.item.removeCreator(index);
|
this.item.removeCreator(index);
|
||||||
if (this.saveOnEdit && !skipSave) {
|
if (this.saveOnEdit && !skipSave) {
|
||||||
return this.item.save();
|
return this.item.saveTx();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var changed = this.item.setCreator(index, fields);
|
var changed = this.item.setCreator(index, fields);
|
||||||
if (changed && this.saveOnEdit && !skipSave) {
|
if (changed && this.saveOnEdit && !skipSave) {
|
||||||
return this.item.save();
|
return this.item.saveTx();
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
]]></body>
|
]]></body>
|
||||||
|
@ -2091,7 +2091,7 @@
|
||||||
this.item.setCreator(newIndex, a);
|
this.item.setCreator(newIndex, a);
|
||||||
this.item.setCreator(index, b);
|
this.item.setCreator(index, b);
|
||||||
if (this.saveOnEdit) {
|
if (this.saveOnEdit) {
|
||||||
return this.item.save();
|
return this.item.saveTx();
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
]]>
|
]]>
|
||||||
|
|
|
@ -239,7 +239,7 @@
|
||||||
|
|
||||||
let changed = this.item.setNote(noteField.value);
|
let changed = this.item.setNote(noteField.value);
|
||||||
if (changed && this.saveOnEdit) {
|
if (changed && this.saveOnEdit) {
|
||||||
yield this.item.save();
|
yield this.item.saveTx();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,7 @@
|
||||||
item.parentKey = this.parentItem.key;
|
item.parentKey = this.parentItem.key;
|
||||||
}
|
}
|
||||||
if (this.saveOnEdit) {
|
if (this.saveOnEdit) {
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
|
|
||||||
if (!this.parentItem && this.collection) {
|
if (!this.parentItem && this.collection) {
|
||||||
this.collection.addItem(id);
|
this.collection.addItem(id);
|
||||||
|
|
|
@ -333,7 +333,7 @@
|
||||||
if (tagData) {
|
if (tagData) {
|
||||||
let item = document.getBindingParent(this).item
|
let item = document.getBindingParent(this).item
|
||||||
item.removeTag(tagName);
|
item.removeTag(tagName);
|
||||||
yield item.save()
|
yield item.saveTx()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return focus to items pane
|
// Return focus to items pane
|
||||||
|
@ -682,13 +682,13 @@
|
||||||
if (oldValue !== value) {
|
if (oldValue !== value) {
|
||||||
// The existing textbox will be removed in notify()
|
// The existing textbox will be removed in notify()
|
||||||
this.item.replaceTag(oldValue, value);
|
this.item.replaceTag(oldValue, value);
|
||||||
yield this.item.save();
|
yield this.item.saveTx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Existing tag cleared
|
// Existing tag cleared
|
||||||
else {
|
else {
|
||||||
this.item.removeTag(oldValue);
|
this.item.removeTag(oldValue);
|
||||||
yield this.item.save();
|
yield this.item.saveTx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Multiple tags
|
// Multiple tags
|
||||||
|
@ -710,7 +710,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
this.item.addTags(tags);
|
this.item.addTags(tags);
|
||||||
yield this.item.save();
|
yield this.item.saveTx();
|
||||||
|
|
||||||
if (lastTag) {
|
if (lastTag) {
|
||||||
this._lastTabIndex = this.item.getTags().length;
|
this._lastTabIndex = this.item.getTags().length;
|
||||||
|
@ -724,7 +724,7 @@
|
||||||
// if it doesn't already exist.
|
// if it doesn't already exist.
|
||||||
row.parentNode.removeChild(row);
|
row.parentNode.removeChild(row);
|
||||||
this.item.addTag(value);
|
this.item.addTag(value);
|
||||||
yield this.item.save();
|
yield this.item.saveTx();
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
]]></body>
|
]]></body>
|
||||||
|
|
|
@ -45,7 +45,7 @@ Zotero.Attachments = new function(){
|
||||||
throw ("'" + file.leafName + "' must be a file in Zotero.Attachments.importFromFile()");
|
throw ("'" + file.leafName + "' must be a file in Zotero.Attachments.importFromFile()");
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemID, newFile;
|
var itemID, newFile, contentType;
|
||||||
yield Zotero.DB.executeTransaction(function* () {
|
yield Zotero.DB.executeTransaction(function* () {
|
||||||
// Create a new attachment
|
// Create a new attachment
|
||||||
var attachmentItem = new Zotero.Item('attachment');
|
var attachmentItem = new Zotero.Item('attachment');
|
||||||
|
@ -73,15 +73,15 @@ Zotero.Attachments = new function(){
|
||||||
// Copy file to unique filename, which automatically shortens long filenames
|
// Copy file to unique filename, which automatically shortens long filenames
|
||||||
newFile = Zotero.File.copyToUnique(file, newFile);
|
newFile = Zotero.File.copyToUnique(file, newFile);
|
||||||
|
|
||||||
var contentType = yield Zotero.MIME.getMIMETypeFromFile(newFile);
|
contentType = yield Zotero.MIME.getMIMETypeFromFile(newFile);
|
||||||
|
|
||||||
attachmentItem.attachmentContentType = contentType;
|
attachmentItem.attachmentContentType = contentType;
|
||||||
attachmentItem.attachmentPath = this.getPath(newFile, this.LINK_MODE_IMPORTED_FILE);
|
attachmentItem.attachmentPath = this.getPath(newFile, this.LINK_MODE_IMPORTED_FILE);
|
||||||
yield attachmentItem.save();
|
yield attachmentItem.save();
|
||||||
|
|
||||||
// Determine charset and build fulltext index
|
|
||||||
yield _postProcessFile(itemID, newFile, contentType);
|
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
|
.then(function () {
|
||||||
|
return _postProcessFile(itemID, newFile, contentType);
|
||||||
|
})
|
||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
Zotero.debug(e, 1);
|
Zotero.debug(e, 1);
|
||||||
var msg = "Failed importing file " + file.path;
|
var msg = "Failed importing file " + file.path;
|
||||||
|
@ -112,21 +112,21 @@ Zotero.Attachments = new function(){
|
||||||
|
|
||||||
var title = file.leafName;
|
var title = file.leafName;
|
||||||
var contentType = yield Zotero.MIME.getMIMETypeFromFile(file);
|
var contentType = yield Zotero.MIME.getMIMETypeFromFile(file);
|
||||||
|
var itemID;
|
||||||
|
|
||||||
return Zotero.DB.executeTransaction(function* () {
|
return Zotero.DB.executeTransaction(function* () {
|
||||||
var itemID = yield _addToDB({
|
itemID = yield _addToDB({
|
||||||
file: file,
|
file: file,
|
||||||
title: title,
|
title: title,
|
||||||
linkMode: this.LINK_MODE_LINKED_FILE,
|
linkMode: this.LINK_MODE_LINKED_FILE,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
parentItemID: parentItemID
|
parentItemID: parentItemID
|
||||||
});
|
});
|
||||||
|
}.bind(this))
|
||||||
// Determine charset and build fulltext index
|
.then(function () {
|
||||||
yield _postProcessFile(itemID, file, contentType);
|
return _postProcessFile(itemID, file, contentType);
|
||||||
|
})
|
||||||
return itemID;
|
.then(() => itemID);
|
||||||
}.bind(this));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ Zotero.Attachments = new function(){
|
||||||
throw new Error("parentItemID not provided");
|
throw new Error("parentItemID not provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
var destDir;
|
var itemID, destDir, newFile;
|
||||||
yield Zotero.DB.executeTransaction(function* () {
|
yield Zotero.DB.executeTransaction(function* () {
|
||||||
// Create a new attachment
|
// Create a new attachment
|
||||||
var attachmentItem = new Zotero.Item('attachment');
|
var attachmentItem = new Zotero.Item('attachment');
|
||||||
|
@ -164,7 +164,7 @@ Zotero.Attachments = new function(){
|
||||||
// DEBUG: this should probably insert access date too so as to
|
// DEBUG: this should probably insert access date too so as to
|
||||||
// create a proper item, but at the moment this is only called by
|
// create a proper item, but at the moment this is only called by
|
||||||
// translate.js, which sets the metadata fields itself
|
// translate.js, which sets the metadata fields itself
|
||||||
var itemID = yield attachmentItem.save();
|
itemID = yield attachmentItem.save();
|
||||||
attachmentItem = yield Zotero.Items.getAsync(itemID)
|
attachmentItem = yield Zotero.Items.getAsync(itemID)
|
||||||
|
|
||||||
destDir = this.getStorageDirectory(attachmentItem);
|
destDir = this.getStorageDirectory(attachmentItem);
|
||||||
|
@ -172,15 +172,15 @@ Zotero.Attachments = new function(){
|
||||||
file.parent.copyTo(storageDir, destDir.leafName);
|
file.parent.copyTo(storageDir, destDir.leafName);
|
||||||
|
|
||||||
// Point to copied file
|
// Point to copied file
|
||||||
var newFile = destDir.clone();
|
newFile = destDir.clone();
|
||||||
newFile.append(file.leafName);
|
newFile.append(file.leafName);
|
||||||
|
|
||||||
attachmentItem.attachmentPath = this.getPath(newFile, this.LINK_MODE_IMPORTED_URL);
|
attachmentItem.attachmentPath = this.getPath(newFile, this.LINK_MODE_IMPORTED_URL);
|
||||||
yield attachmentItem.save();
|
yield attachmentItem.save();
|
||||||
|
|
||||||
// Determine charset and build fulltext index
|
|
||||||
yield _postProcessFile(itemID, newFile, contentType);
|
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
|
.then(function () {
|
||||||
|
return _postProcessFile(itemID, newFile, contentType);
|
||||||
|
})
|
||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
Zotero.debug(e, 1);
|
Zotero.debug(e, 1);
|
||||||
|
|
||||||
|
@ -1130,7 +1130,7 @@ Zotero.Attachments = new function(){
|
||||||
if (parentItemID) {
|
if (parentItemID) {
|
||||||
newAttachment.parentID = parentItemID;
|
newAttachment.parentID = parentItemID;
|
||||||
}
|
}
|
||||||
yield newAttachment.save();
|
yield newAttachment.saveTx();
|
||||||
|
|
||||||
// Copy over files if they exist
|
// Copy over files if they exist
|
||||||
if (newAttachment.isImportedAttachment() && attachment.getFile()) {
|
if (newAttachment.isImportedAttachment() && attachment.getFile()) {
|
||||||
|
@ -1362,7 +1362,7 @@ Zotero.Attachments = new function(){
|
||||||
var item = yield Zotero.Items.getAsync(itemID);
|
var item = yield Zotero.Items.getAsync(itemID);
|
||||||
charset = yield Zotero.CharacterSets.add(charset);
|
charset = yield Zotero.CharacterSets.add(charset);
|
||||||
item.attachmentCharset = charset;
|
item.attachmentCharset = charset;
|
||||||
yield item.save();
|
yield item.saveTx();
|
||||||
|
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
Zotero.Notifier.enable();
|
Zotero.Notifier.enable();
|
||||||
|
|
|
@ -70,13 +70,14 @@ Zotero.Creators = new function() {
|
||||||
/**
|
/**
|
||||||
* Returns the creatorID matching given fields, or creates a new creator and returns its id
|
* Returns the creatorID matching given fields, or creates a new creator and returns its id
|
||||||
*
|
*
|
||||||
|
* @requireTransaction
|
||||||
* @param {Object} data Creator data in API JSON format
|
* @param {Object} data Creator data in API JSON format
|
||||||
* @param {Boolean} [create=false] If no matching creator, create one
|
* @param {Boolean} [create=false] If no matching creator, create one
|
||||||
* @return {Promise<Integer>} creatorID
|
* @return {Promise<Integer>} creatorID
|
||||||
*/
|
*/
|
||||||
this.getIDFromData = Zotero.Promise.method(function (data, create) {
|
this.getIDFromData = Zotero.Promise.coroutine(function* (data, create) {
|
||||||
|
Zotero.DB.requireTransaction();
|
||||||
data = this.cleanData(data);
|
data = this.cleanData(data);
|
||||||
return Zotero.DB.executeTransaction(function* () {
|
|
||||||
var sql = "SELECT creatorID FROM creators WHERE "
|
var sql = "SELECT creatorID FROM creators WHERE "
|
||||||
+ "firstName=? AND lastName=? AND fieldMode=?";
|
+ "firstName=? AND lastName=? AND fieldMode=?";
|
||||||
var id = yield Zotero.DB.valueQueryAsync(
|
var id = yield Zotero.DB.valueQueryAsync(
|
||||||
|
@ -95,7 +96,6 @@ Zotero.Creators = new function() {
|
||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
this.updateCreator = Zotero.Promise.coroutine(function* (creatorID, creatorData) {
|
this.updateCreator = Zotero.Promise.coroutine(function* (creatorID, creatorData) {
|
||||||
|
|
|
@ -547,11 +547,19 @@ Zotero.DataObject.prototype.editCheck = function () {
|
||||||
* TRUE on item update, or FALSE if item was unchanged
|
* TRUE on item update, or FALSE if item was unchanged
|
||||||
*/
|
*/
|
||||||
Zotero.DataObject.prototype.save = Zotero.Promise.coroutine(function* (options) {
|
Zotero.DataObject.prototype.save = Zotero.Promise.coroutine(function* (options) {
|
||||||
|
options = options || {};
|
||||||
var env = {
|
var env = {
|
||||||
options: options || {},
|
options: options,
|
||||||
transactionOptions: {}
|
transactionOptions: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!env.options.tx && !Zotero.DB.inTransaction()) {
|
||||||
|
Zotero.logError("save() called on Zotero." + this._ObjectType + " without a wrapping "
|
||||||
|
+ "transaction -- use saveTx() instead");
|
||||||
|
Zotero.debug((new Error).stack, 2);
|
||||||
|
env.options.tx = true;
|
||||||
|
}
|
||||||
|
|
||||||
var proceed = yield this._initSave(env);
|
var proceed = yield this._initSave(env);
|
||||||
if (!proceed) return false;
|
if (!proceed) return false;
|
||||||
|
|
||||||
|
@ -562,7 +570,7 @@ Zotero.DataObject.prototype.save = Zotero.Promise.coroutine(function* (options)
|
||||||
Zotero.debug('Updating database with new ' + this._objectType + ' data', 4);
|
Zotero.debug('Updating database with new ' + this._objectType + ' data', 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Zotero.DB.executeTransaction(function* () {
|
try {
|
||||||
if (Zotero.DataObject.prototype._finalizeSave == this._finalizeSave) {
|
if (Zotero.DataObject.prototype._finalizeSave == this._finalizeSave) {
|
||||||
throw new Error("_finalizeSave not implement for Zotero." + this._ObjectType);
|
throw new Error("_finalizeSave not implement for Zotero." + this._ObjectType);
|
||||||
}
|
}
|
||||||
|
@ -574,27 +582,49 @@ Zotero.DataObject.prototype.save = Zotero.Promise.coroutine(function* (options)
|
||||||
if (!env.isNew) {
|
if (!env.isNew) {
|
||||||
env.changed = this._previousData;
|
env.changed = this._previousData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create transaction
|
||||||
|
if (env.options.tx) {
|
||||||
|
let result = yield Zotero.DB.executeTransaction(function* () {
|
||||||
yield this._saveData(env);
|
yield this._saveData(env);
|
||||||
yield Zotero.DataObject.prototype._finalizeSave.call(this, env);
|
yield Zotero.DataObject.prototype._finalizeSave.call(this, env);
|
||||||
return this._finalizeSave(env);
|
return this._finalizeSave(env);
|
||||||
}.bind(this), env.transactionOptions)
|
}.bind(this), env.transactionOptions);
|
||||||
.catch(e => {
|
return result;
|
||||||
|
}
|
||||||
|
// Use existing transaction
|
||||||
|
else {
|
||||||
|
Zotero.DB.requireTransaction();
|
||||||
|
yield this._saveData(env);
|
||||||
|
yield Zotero.DataObject.prototype._finalizeSave.call(this, env);
|
||||||
|
return this._finalizeSave(env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
return this._recoverFromSaveError(env, e)
|
return this._recoverFromSaveError(env, e)
|
||||||
.catch(function(e2) {
|
.catch(function(e2) {
|
||||||
Zotero.debug(e2, 1);
|
Zotero.debug(e2, 1);
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
if (options.errorHandler) {
|
if (env.options.errorHandler) {
|
||||||
options.errorHandler(e);
|
env.options.errorHandler(e);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Zotero.debug(e, 1);
|
Zotero.debug(e, 1);
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
})
|
})
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Zotero.DataObject.prototype.saveTx = function (options) {
|
||||||
|
options = options || {};
|
||||||
|
options.tx = true;
|
||||||
|
return this.save(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Zotero.DataObject.prototype.hasChanged = function() {
|
Zotero.DataObject.prototype.hasChanged = function() {
|
||||||
Zotero.debug(this._changed);
|
Zotero.debug(this._changed);
|
||||||
return !!Object.keys(this._changed).filter(dataType => this._changed[dataType]).length
|
return !!Object.keys(this._changed).filter(dataType => this._changed[dataType]).length
|
||||||
|
@ -618,9 +648,15 @@ Zotero.DataObject.prototype._initSave = Zotero.Promise.coroutine(function* (env)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undo registerIdentifiers() on failure
|
// Undo registerIdentifiers() on failure
|
||||||
env.transactionOptions.onRollback = function () {
|
var func = function () {
|
||||||
this.ObjectsClass.unload(env.id);
|
this.ObjectsClass.unload(env.id);
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
if (env.options.tx) {
|
||||||
|
env.transactionOptions.onRollback = func;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Zotero.DB.addCurrentCallback("rollback", func);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
@ -653,11 +689,9 @@ Zotero.DataObject.prototype.erase = Zotero.Promise.coroutine(function* () {
|
||||||
|
|
||||||
Zotero.debug('Deleting ' + this.objectType + ' ' + this.id);
|
Zotero.debug('Deleting ' + this.objectType + ' ' + this.id);
|
||||||
|
|
||||||
yield Zotero.DB.executeTransaction(function* () {
|
Zotero.DB.requireTransaction();
|
||||||
yield this._eraseData(env);
|
yield this._eraseData(env);
|
||||||
yield this._erasePreCommit(env);
|
yield this._erasePreCommit(env);
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
return this._erasePostCommit(env);
|
return this._erasePostCommit(env);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1173,6 +1173,11 @@ Zotero.Item.prototype.isEditable = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
var isNew = env.isNew;
|
var isNew = env.isNew;
|
||||||
var options = env.options;
|
var options = env.options;
|
||||||
|
|
||||||
|
@ -1740,6 +1745,11 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
||||||
parentItem.clearBestAttachmentState();
|
parentItem.clearBestAttachmentState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
if (!Zotero.DB.inTransaction()) {
|
||||||
|
throw new Error("Not in transaction saving item " + this.libraryKey);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Zotero.Item.prototype._finalizeSave = Zotero.Promise.coroutine(function* (env) {
|
Zotero.Item.prototype._finalizeSave = Zotero.Promise.coroutine(function* (env) {
|
||||||
|
|
|
@ -169,8 +169,8 @@ Zotero.Relations = function () {
|
||||||
* @param {String} prefix
|
* @param {String} prefix
|
||||||
* @param {String[]} ignorePredicates
|
* @param {String[]} ignorePredicates
|
||||||
*/
|
*/
|
||||||
this.eraseByURIPrefix = function (prefix, ignorePredicates) {
|
this.eraseByURIPrefix = Zotero.Promise.coroutine(function* (prefix, ignorePredicates) {
|
||||||
return Zotero.DB.executeTransaction(function* () {
|
Zotero.DB.requireTransaction();
|
||||||
prefix = prefix + '%';
|
prefix = prefix + '%';
|
||||||
var sql = "SELECT ROWID FROM relations WHERE (subject LIKE ? OR object LIKE ?)";
|
var sql = "SELECT ROWID FROM relations WHERE (subject LIKE ? OR object LIKE ?)";
|
||||||
var params = [prefix, prefix];
|
var params = [prefix, prefix];
|
||||||
|
@ -187,15 +187,14 @@ Zotero.Relations = function () {
|
||||||
yield relation.load();
|
yield relation.load();
|
||||||
yield relation.erase();
|
yield relation.erase();
|
||||||
}
|
}
|
||||||
}.bind(this));
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
this.eraseByURI = function (uri, ignorePredicates) {
|
this.eraseByURI = Zotero.Promise.coroutine(function* (uri, ignorePredicates) {
|
||||||
return Zotero.DB.executeTransaction(function* () {
|
Zotero.DB.requireTransaction();
|
||||||
var sql = "SELECT ROWID FROM relations WHERE (subject=? OR object=?)";
|
var sql = "SELECT ROWID FROM relations WHERE (subject=? OR object=?)";
|
||||||
var params = [uri, uri];
|
var params = [uri, uri];
|
||||||
if (ignorePredicates) {
|
if (ignorePredicates) {
|
||||||
|
@ -211,8 +210,7 @@ Zotero.Relations = function () {
|
||||||
yield relation.load();
|
yield relation.load();
|
||||||
yield relation.erase();
|
yield relation.erase();
|
||||||
}
|
}
|
||||||
}.bind(this));
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
this.purge = Zotero.Promise.coroutine(function* () {
|
this.purge = Zotero.Promise.coroutine(function* () {
|
||||||
|
|
|
@ -76,16 +76,17 @@ Zotero.Tags = new function() {
|
||||||
/**
|
/**
|
||||||
* Returns the tagID matching given fields, or creates a new tag and returns its id
|
* Returns the tagID matching given fields, or creates a new tag and returns its id
|
||||||
*
|
*
|
||||||
|
* @requireTransaction
|
||||||
* @param {Number} libraryID
|
* @param {Number} libraryID
|
||||||
* @param {String} name - Tag data in API JSON format
|
* @param {String} name - Tag data in API JSON format
|
||||||
* @param {Boolean} [create=false] - If no matching tag, create one
|
* @param {Boolean} [create=false] - If no matching tag, create one
|
||||||
* @return {Promise<Integer>} tagID
|
* @return {Promise<Integer>} tagID
|
||||||
*/
|
*/
|
||||||
this.getIDFromName = Zotero.Promise.method(function (libraryID, name, create) {
|
this.getIDFromName = Zotero.Promise.coroutine(function* (libraryID, name, create) {
|
||||||
|
Zotero.DB.requireTransaction();
|
||||||
data = this.cleanData({
|
data = this.cleanData({
|
||||||
tag: name
|
tag: name
|
||||||
});
|
});
|
||||||
return Zotero.DB.executeTransaction(function* () {
|
|
||||||
var sql = "SELECT tagID FROM tags WHERE libraryID=? AND name=?";
|
var sql = "SELECT tagID FROM tags WHERE libraryID=? AND name=?";
|
||||||
var id = yield Zotero.DB.valueQueryAsync(sql, [libraryID, data.tag]);
|
var id = yield Zotero.DB.valueQueryAsync(sql, [libraryID, data.tag]);
|
||||||
if (!id && create) {
|
if (!id && create) {
|
||||||
|
@ -99,7 +100,6 @@ Zotero.Tags = new function() {
|
||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -297,6 +297,12 @@ Zotero.DBConnection.prototype.addCallback = function (type, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Zotero.DBConnection.prototype.addCurrentCallback = function (type, cb) {
|
||||||
|
this.requireTransaction();
|
||||||
|
this._callbacks.current[type].push(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Zotero.DBConnection.prototype.removeCallback = function (type, id) {
|
Zotero.DBConnection.prototype.removeCallback = function (type, id) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'begin':
|
case 'begin':
|
||||||
|
@ -453,41 +459,16 @@ Zotero.DBConnection.prototype.executeTransaction = Zotero.Promise.coroutine(func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((options.exclusive && this._inTransaction) || this._inExclusiveTransaction) {
|
var startedTransaction = false;
|
||||||
yield Zotero.DB.waitForTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this._inTransaction) {
|
while (this._inTransaction) {
|
||||||
Zotero.debug("Async DB transaction in progress -- increasing level to "
|
yield Zotero.DB.waitForTransaction().timeout(options.waitTimeout || 10000);
|
||||||
+ ++this._asyncTransactionNestingLevel, 5);
|
}
|
||||||
|
this._inTransaction = startedTransaction = true;
|
||||||
|
|
||||||
if (options.onCommit) {
|
|
||||||
this._callbacks.current.commit.push(options.onCommit);
|
|
||||||
}
|
|
||||||
if (options.onRollback) {
|
|
||||||
this._callbacks.current.rollback.push(options.onRollback);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
var result = yield Zotero.Promise.coroutine(func)();
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
Zotero.debug("Rolling back nested async DB transaction", 5);
|
|
||||||
this._asyncTransactionNestingLevel = 0;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
Zotero.debug("Decreasing async DB transaction level to "
|
|
||||||
+ --this._asyncTransactionNestingLevel, 5);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Zotero.debug("Beginning async DB transaction", 5);
|
Zotero.debug("Beginning async DB transaction", 5);
|
||||||
|
|
||||||
this._inTransaction = true;
|
|
||||||
this._inExclusiveTransaction = options.exclusive;
|
|
||||||
|
|
||||||
this._transactionPromise = new Zotero.Promise(function () {
|
this._transactionPromise = new Zotero.Promise(function () {
|
||||||
resolve = arguments[0];
|
resolve = arguments[0];
|
||||||
});
|
});
|
||||||
|
@ -504,14 +485,19 @@ Zotero.DBConnection.prototype.executeTransaction = Zotero.Promise.coroutine(func
|
||||||
var conn = this._getConnection(options) || (yield this._getConnectionAsync(options));
|
var conn = this._getConnection(options) || (yield this._getConnectionAsync(options));
|
||||||
var result = yield conn.executeTransaction(func);
|
var result = yield conn.executeTransaction(func);
|
||||||
Zotero.debug("Committed async DB transaction", 5);
|
Zotero.debug("Committed async DB transaction", 5);
|
||||||
this._inTransaction = false;
|
|
||||||
|
|
||||||
// Clear transaction time
|
// Clear transaction time
|
||||||
if (this._transactionDate) {
|
if (this._transactionDate) {
|
||||||
this._transactionDate = null;
|
this._transactionDate = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options) {
|
if (options.vacuumOnCommit) {
|
||||||
|
Zotero.debug('Vacuuming database');
|
||||||
|
yield Zotero.DB.queryAsync('VACUUM');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._inTransaction = false;
|
||||||
|
|
||||||
// Function to run once transaction has been committed but before any
|
// Function to run once transaction has been committed but before any
|
||||||
// permanent callbacks
|
// permanent callbacks
|
||||||
if (options.onCommit) {
|
if (options.onCommit) {
|
||||||
|
@ -519,12 +505,6 @@ Zotero.DBConnection.prototype.executeTransaction = Zotero.Promise.coroutine(func
|
||||||
}
|
}
|
||||||
this._callbacks.current.rollback = [];
|
this._callbacks.current.rollback = [];
|
||||||
|
|
||||||
if (options.vacuumOnCommit) {
|
|
||||||
Zotero.debug('Vacuuming database');
|
|
||||||
yield Zotero.DB.queryAsync('VACUUM');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run temporary commit callbacks
|
// Run temporary commit callbacks
|
||||||
var f;
|
var f;
|
||||||
while (f = this._callbacks.current.commit.shift()) {
|
while (f = this._callbacks.current.commit.shift()) {
|
||||||
|
@ -540,20 +520,23 @@ Zotero.DBConnection.prototype.executeTransaction = Zotero.Promise.coroutine(func
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
if (e.name == "TimeoutError") {
|
||||||
|
Zotero.debug("Timed out waiting for transaction", 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
Zotero.debug("Rolled back async DB transaction", 5);
|
Zotero.debug("Rolled back async DB transaction", 5);
|
||||||
Zotero.debug(e, 1);
|
Zotero.debug(e, 1);
|
||||||
|
}
|
||||||
|
if (startedTransaction) {
|
||||||
this._inTransaction = false;
|
this._inTransaction = false;
|
||||||
this._inExclusiveTransaction = false;
|
}
|
||||||
|
|
||||||
if (options) {
|
|
||||||
// Function to run once transaction has been committed but before any
|
// Function to run once transaction has been committed but before any
|
||||||
// permanent callbacks
|
// permanent callbacks
|
||||||
if (options.onRollback) {
|
if (options.onRollback) {
|
||||||
this._callbacks.current.rollback.push(options.onRollback);
|
this._callbacks.current.rollback.push(options.onRollback);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Run temporary commit callbacks
|
// Run temporary commit callbacks
|
||||||
var f;
|
var f;
|
||||||
|
@ -586,15 +569,28 @@ Zotero.DBConnection.prototype.executeTransaction = Zotero.Promise.coroutine(func
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Zotero.DBConnection.prototype.inTransaction = function () {
|
||||||
|
return this._inTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Zotero.DBConnection.prototype.waitForTransaction = function () {
|
Zotero.DBConnection.prototype.waitForTransaction = function () {
|
||||||
if (!this._inTransaction) {
|
if (!this._inTransaction) {
|
||||||
return Zotero.Promise.resolve();
|
return Zotero.Promise.resolve().cancellable();
|
||||||
}
|
}
|
||||||
Zotero.debug("Waiting for transaction to finish");
|
Zotero.debug("Waiting for transaction to finish");
|
||||||
|
Zotero.debug((new Error).stack);
|
||||||
return this._transactionPromise;
|
return this._transactionPromise;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Zotero.DBConnection.prototype.requireTransaction = function () {
|
||||||
|
if (!this._inTransaction) {
|
||||||
|
throw new Error("Not in transaction");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} sql SQL statement to run
|
* @param {String} sql SQL statement to run
|
||||||
* @param {Array|String|Integer} [params] SQL parameters to bind
|
* @param {Array|String|Integer} [params] SQL parameters to bind
|
||||||
|
@ -818,7 +814,7 @@ Zotero.DBConnection.prototype.tableExists = function (table) {
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
Zotero.DBConnection.prototype.executeSQLFile = function (sql) {
|
Zotero.DBConnection.prototype.executeSQLFile = Zotero.Promise.coroutine(function* (sql) {
|
||||||
var nonCommentRE = /^[^-]/;
|
var nonCommentRE = /^[^-]/;
|
||||||
var trailingCommentRE = /^(.*?)(?:--.+)?$/;
|
var trailingCommentRE = /^(.*?)(?:--.+)?$/;
|
||||||
|
|
||||||
|
@ -836,13 +832,13 @@ Zotero.DBConnection.prototype.executeSQLFile = function (sql) {
|
||||||
var statements = sql.split(";")
|
var statements = sql.split(";")
|
||||||
.map(function (x) x.replace(/TEMPSEMI/g, ";"));
|
.map(function (x) x.replace(/TEMPSEMI/g, ";"));
|
||||||
|
|
||||||
return this.executeTransaction(function* () {
|
this.requireTransaction();
|
||||||
|
|
||||||
var statement;
|
var statement;
|
||||||
while (statement = statements.shift()) {
|
while (statement = statements.shift()) {
|
||||||
yield Zotero.DB.queryAsync(statement);
|
yield Zotero.DB.queryAsync(statement);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -403,13 +403,14 @@ Zotero.Fulltext = new function(){
|
||||||
/**
|
/**
|
||||||
* Index multiple words at once
|
* Index multiple words at once
|
||||||
*
|
*
|
||||||
|
* @requireTransaction
|
||||||
* @param {Number} itemID
|
* @param {Number} itemID
|
||||||
* @param {Array<string>} words
|
* @param {Array<string>} words
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
function indexWords(itemID, words) {
|
var indexWords = Zotero.Promise.coroutine(function* (itemID, words) {
|
||||||
|
Zotero.DB.requireTransaction();
|
||||||
let chunk;
|
let chunk;
|
||||||
return Zotero.DB.executeTransaction(function* () {
|
|
||||||
yield Zotero.DB.queryAsync("DELETE FROM indexing.fulltextWords");
|
yield Zotero.DB.queryAsync("DELETE FROM indexing.fulltextWords");
|
||||||
while (words.length > 0) {
|
while (words.length > 0) {
|
||||||
chunk = words.splice(0, 100);
|
chunk = words.splice(0, 100);
|
||||||
|
@ -420,8 +421,7 @@ Zotero.Fulltext = new function(){
|
||||||
yield Zotero.DB.queryAsync('INSERT OR IGNORE INTO fulltextItemWords (wordID, itemID) SELECT wordID, ? FROM fulltextWords JOIN indexing.fulltextWords USING(word)', [itemID]);
|
yield Zotero.DB.queryAsync('INSERT OR IGNORE INTO fulltextItemWords (wordID, itemID) SELECT wordID, ? FROM fulltextWords JOIN indexing.fulltextWords USING(word)', [itemID]);
|
||||||
yield Zotero.DB.queryAsync("REPLACE INTO fulltextItems (itemID, version) VALUES (?,?)", [itemID, 0]);
|
yield Zotero.DB.queryAsync("REPLACE INTO fulltextItems (itemID, version) VALUES (?,?)", [itemID, 0]);
|
||||||
yield Zotero.DB.queryAsync("DELETE FROM indexing.fulltextWords");
|
yield Zotero.DB.queryAsync("DELETE FROM indexing.fulltextWords");
|
||||||
}.bind(this));
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -559,7 +559,6 @@ Zotero.Fulltext = new function(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
yield Zotero.DB.executeTransaction(function* () {
|
|
||||||
yield indexString(text, charset, itemID);
|
yield indexString(text, charset, itemID);
|
||||||
|
|
||||||
// Record the number of characters indexed (unless we're indexing a (PDF) cache file,
|
// Record the number of characters indexed (unless we're indexing a (PDF) cache file,
|
||||||
|
@ -567,7 +566,6 @@ Zotero.Fulltext = new function(){
|
||||||
if (!isCacheFile) {
|
if (!isCacheFile) {
|
||||||
yield setChars(itemID, { indexed: text.length, total: totalChars });
|
yield setChars(itemID, { indexed: text.length, total: totalChars });
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
@ -690,10 +688,8 @@ Zotero.Fulltext = new function(){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield Zotero.DB.executeTransaction(function* () {
|
|
||||||
yield indexFile(cacheFilePath, 'text/plain', 'utf-8', itemID, true, true);
|
yield indexFile(cacheFilePath, 'text/plain', 'utf-8', itemID, true, true);
|
||||||
yield setPages(itemID, { indexed: pagesIndexed, total: totalPages });
|
yield setPages(itemID, { indexed: pagesIndexed, total: totalPages });
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
@ -827,7 +823,9 @@ Zotero.Fulltext = new function(){
|
||||||
+ libraryKey, 2);
|
+ libraryKey, 2);
|
||||||
|
|
||||||
// Delete rows for items that weren't supposed to be indexed
|
// Delete rows for items that weren't supposed to be indexed
|
||||||
|
yield Zotero.DB.executeTransaction(function* () {
|
||||||
yield this.clearItemWords(itemID);
|
yield this.clearItemWords(itemID);
|
||||||
|
}.bind(this));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1291,16 +1289,18 @@ Zotero.Fulltext = new function(){
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @requireTransaction
|
||||||
|
*/
|
||||||
this.clearItemWords = Zotero.Promise.coroutine(function* (itemID, skipCacheClear) {
|
this.clearItemWords = Zotero.Promise.coroutine(function* (itemID, skipCacheClear) {
|
||||||
var indexed = yield Zotero.DB.executeTransaction(function* () {
|
Zotero.DB.requireTransaction();
|
||||||
|
|
||||||
var sql = "SELECT rowid FROM fulltextItems WHERE itemID=? LIMIT 1";
|
var sql = "SELECT rowid FROM fulltextItems WHERE itemID=? LIMIT 1";
|
||||||
var indexed = yield Zotero.DB.valueQueryAsync(sql, itemID);
|
var indexed = yield Zotero.DB.valueQueryAsync(sql, itemID);
|
||||||
if (indexed) {
|
if (indexed) {
|
||||||
yield Zotero.DB.queryAsync("DELETE FROM fulltextItemWords WHERE itemID=?", itemID);
|
yield Zotero.DB.queryAsync("DELETE FROM fulltextItemWords WHERE itemID=?", itemID);
|
||||||
yield Zotero.DB.queryAsync("DELETE FROM fulltextItems WHERE itemID=?", itemID);
|
yield Zotero.DB.queryAsync("DELETE FROM fulltextItems WHERE itemID=?", itemID);
|
||||||
}
|
}
|
||||||
return indexed;
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
if (indexed) {
|
if (indexed) {
|
||||||
Zotero.Prefs.set('purge.fulltext', true);
|
Zotero.Prefs.set('purge.fulltext', true);
|
||||||
|
|
|
@ -123,21 +123,19 @@ Zotero.Schema = new function(){
|
||||||
// Update custom tables if they exist so that changes are in
|
// Update custom tables if they exist so that changes are in
|
||||||
// place before user data migration
|
// place before user data migration
|
||||||
if (Zotero.DB.tableExists('customItemTypes')) {
|
if (Zotero.DB.tableExists('customItemTypes')) {
|
||||||
yield Zotero.Schema.updateCustomTables(updated);
|
yield _updateCustomTables(updated);
|
||||||
}
|
}
|
||||||
updated = yield _migrateUserDataSchema(userdata);
|
updated = yield _migrateUserDataSchema(userdata);
|
||||||
yield _updateSchema('triggers');
|
yield _updateSchema('triggers');
|
||||||
|
|
||||||
|
// Populate combined tables for custom types and fields -- this is likely temporary
|
||||||
|
//
|
||||||
|
// We do this again in case custom fields were changed during user data migration
|
||||||
|
yield _updateCustomTables()
|
||||||
|
|
||||||
return updated;
|
return updated;
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
// Populate combined tables for custom types and fields
|
|
||||||
// -- this is likely temporary
|
|
||||||
//
|
|
||||||
// We do this even if updated in case custom fields were
|
|
||||||
// changed during user data migration
|
|
||||||
yield Zotero.Schema.updateCustomTables()
|
|
||||||
|
|
||||||
if (updated) {
|
if (updated) {
|
||||||
// Upgrade seems to have been a success -- delete any previous backups
|
// Upgrade seems to have been a success -- delete any previous backups
|
||||||
var maxPrevious = userdata - 1;
|
var maxPrevious = userdata - 1;
|
||||||
|
@ -318,7 +316,7 @@ Zotero.Schema = new function(){
|
||||||
});
|
});
|
||||||
|
|
||||||
var _reloadSchema = Zotero.Promise.coroutine(function* () {
|
var _reloadSchema = Zotero.Promise.coroutine(function* () {
|
||||||
yield Zotero.Schema.updateCustomTables();
|
yield _updateCustomTables();
|
||||||
yield Zotero.ItemTypes.load();
|
yield Zotero.ItemTypes.load();
|
||||||
yield Zotero.ItemFields.load();
|
yield Zotero.ItemFields.load();
|
||||||
yield Zotero.SearchConditions.init();
|
yield Zotero.SearchConditions.init();
|
||||||
|
@ -335,10 +333,11 @@ Zotero.Schema = new function(){
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
this.updateCustomTables = function (skipDelete, skipSystem) {
|
var _updateCustomTables = Zotero.Promise.coroutine(function* (skipDelete, skipSystem) {
|
||||||
return Zotero.DB.executeTransaction(function* (conn) {
|
|
||||||
Zotero.debug("Updating custom tables");
|
Zotero.debug("Updating custom tables");
|
||||||
|
|
||||||
|
Zotero.DB.requireTransaction();
|
||||||
|
|
||||||
if (!skipDelete) {
|
if (!skipDelete) {
|
||||||
yield Zotero.DB.queryAsync("DELETE FROM itemTypesCombined");
|
yield Zotero.DB.queryAsync("DELETE FROM itemTypesCombined");
|
||||||
yield Zotero.DB.queryAsync("DELETE FROM fieldsCombined WHERE fieldID NOT IN (SELECT fieldID FROM itemData)");
|
yield Zotero.DB.queryAsync("DELETE FROM fieldsCombined WHERE fieldID NOT IN (SELECT fieldID FROM itemData)");
|
||||||
|
@ -386,7 +385,6 @@ Zotero.Schema = new function(){
|
||||||
+ "customFieldID + " + offset + " AS fieldID FROM customBaseFieldMappings"
|
+ "customFieldID + " + offset + " AS fieldID FROM customBaseFieldMappings"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1454,7 +1452,7 @@ Zotero.Schema = new function(){
|
||||||
yield _getSchemaSQL('triggers').then(function (sql) {
|
yield _getSchemaSQL('triggers').then(function (sql) {
|
||||||
return Zotero.DB.executeSQLFile(sql);
|
return Zotero.DB.executeSQLFile(sql);
|
||||||
});
|
});
|
||||||
yield Zotero.Schema.updateCustomTables(true);
|
yield _updateCustomTables(true);
|
||||||
|
|
||||||
yield _getSchemaSQLVersion('system').then(function (version) {
|
yield _getSchemaSQLVersion('system').then(function (version) {
|
||||||
return _updateDBVersion('system', version);
|
return _updateDBVersion('system', version);
|
||||||
|
@ -1918,16 +1916,17 @@ Zotero.Schema = new function(){
|
||||||
//
|
//
|
||||||
// If libraryID set, make sure no relations still use a local user key, and then remove on-error code in sync.js
|
// If libraryID set, make sure no relations still use a local user key, and then remove on-error code in sync.js
|
||||||
|
|
||||||
function _migrateUserDataSchema(fromVersion) {
|
var _migrateUserDataSchema = Zotero.Promise.coroutine(function* (fromVersion) {
|
||||||
return _getSchemaSQLVersion('userdata')
|
var toVersion = yield _getSchemaSQLVersion('userdata');
|
||||||
.then(function (toVersion) {
|
|
||||||
if (fromVersion >= toVersion) {
|
if (fromVersion >= toVersion) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Zotero.debug('Updating user data tables from version ' + fromVersion + ' to ' + toVersion);
|
Zotero.debug('Updating user data tables from version ' + fromVersion + ' to ' + toVersion);
|
||||||
|
|
||||||
return Zotero.DB.executeTransaction(function* (conn) {
|
Zotero.DB.requireTransaction();
|
||||||
|
|
||||||
// Step through version changes until we reach the current version
|
// Step through version changes until we reach the current version
|
||||||
//
|
//
|
||||||
// Each block performs the changes necessary to move from the
|
// Each block performs the changes necessary to move from the
|
||||||
|
@ -2270,11 +2269,10 @@ Zotero.Schema = new function(){
|
||||||
yield Zotero.DB.queryAsync("DROP TABLE itemsOld");
|
yield Zotero.DB.queryAsync("DROP TABLE itemsOld");
|
||||||
yield Zotero.DB.queryAsync("DROP TABLE tagsOld");
|
yield Zotero.DB.queryAsync("DROP TABLE tagsOld");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
yield _updateDBVersion('userdata', toVersion);
|
yield _updateDBVersion('userdata', toVersion);
|
||||||
})
|
|
||||||
.return(true);
|
return true;
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -947,7 +947,7 @@ Zotero.Search.idsToTempTable = function (ids) {
|
||||||
yield Zotero.DB.queryAsync(sql);
|
yield Zotero.DB.queryAsync(sql);
|
||||||
|
|
||||||
return tmpTable;
|
return tmpTable;
|
||||||
}, { exclusive: true });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -740,8 +740,6 @@ var ZoteroPane = new function()
|
||||||
*/
|
*/
|
||||||
this.newItem = Zotero.Promise.coroutine(function* (typeID, data, row, manual)
|
this.newItem = Zotero.Promise.coroutine(function* (typeID, data, row, manual)
|
||||||
{
|
{
|
||||||
yield Zotero.DB.waitForTransaction();
|
|
||||||
|
|
||||||
if ((row === undefined || row === null) && this.collectionsView.selection) {
|
if ((row === undefined || row === null) && this.collectionsView.selection) {
|
||||||
row = this.collectionsView.selection.currentIndex;
|
row = this.collectionsView.selection.currentIndex;
|
||||||
|
|
||||||
|
@ -810,8 +808,6 @@ var ZoteroPane = new function()
|
||||||
|
|
||||||
|
|
||||||
this.newCollection = Zotero.Promise.coroutine(function* (parentKey) {
|
this.newCollection = Zotero.Promise.coroutine(function* (parentKey) {
|
||||||
yield Zotero.DB.waitForTransaction();
|
|
||||||
|
|
||||||
if (!this.canEditLibrary()) {
|
if (!this.canEditLibrary()) {
|
||||||
this.displayCannotEditLibraryMessage();
|
this.displayCannotEditLibraryMessage();
|
||||||
return;
|
return;
|
||||||
|
@ -847,7 +843,7 @@ var ZoteroPane = new function()
|
||||||
collection.libraryID = libraryID;
|
collection.libraryID = libraryID;
|
||||||
collection.name = newName.value;
|
collection.name = newName.value;
|
||||||
collection.parentKey = parentKey;
|
collection.parentKey = parentKey;
|
||||||
return collection.save();
|
return collection.saveTx();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1234,6 +1230,15 @@ var ZoteroPane = new function()
|
||||||
return Zotero.spawn(function* () {
|
return Zotero.spawn(function* () {
|
||||||
yield Zotero.DB.waitForTransaction();
|
yield Zotero.DB.waitForTransaction();
|
||||||
|
|
||||||
|
// Don't select item until items list has loaded
|
||||||
|
//
|
||||||
|
// This avoids an error if New Item is used while the pane is first loading.
|
||||||
|
var deferred = Zotero.Promise.defer();
|
||||||
|
this.itemsView.addEventListener('load', function () {
|
||||||
|
deferred.resolve();
|
||||||
|
});
|
||||||
|
yield deferred.promise;
|
||||||
|
|
||||||
var selectedItems = this.itemsView.getSelectedItems();
|
var selectedItems = this.itemsView.getSelectedItems();
|
||||||
|
|
||||||
// Check if selection has actually changed. The onselect event that calls this
|
// Check if selection has actually changed. The onselect event that calls this
|
||||||
|
@ -1863,7 +1868,7 @@ var ZoteroPane = new function()
|
||||||
|
|
||||||
if (result && newName.value) {
|
if (result && newName.value) {
|
||||||
row.ref.name = newName.value;
|
row.ref.name = newName.value;
|
||||||
row.ref.save();
|
row.ref.saveTx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -3055,8 +3060,6 @@ var ZoteroPane = new function()
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
this.newNote = Zotero.Promise.coroutine(function* (popup, parentKey, text, citeURI) {
|
this.newNote = Zotero.Promise.coroutine(function* (popup, parentKey, text, citeURI) {
|
||||||
yield Zotero.DB.waitForTransaction();
|
|
||||||
|
|
||||||
if (!this.canEdit()) {
|
if (!this.canEdit()) {
|
||||||
this.displayCannotEditLibraryMessage();
|
this.displayCannotEditLibraryMessage();
|
||||||
return;
|
return;
|
||||||
|
@ -3081,7 +3084,7 @@ var ZoteroPane = new function()
|
||||||
if (parentKey) {
|
if (parentKey) {
|
||||||
item.parentKey = parentKey;
|
item.parentKey = parentKey;
|
||||||
}
|
}
|
||||||
var itemID = yield item.save();
|
var itemID = yield item.saveTx();
|
||||||
|
|
||||||
if (!parentKey && this.itemsView && this.collectionsView.selectedTreeRow.isCollection()) {
|
if (!parentKey && this.itemsView && this.collectionsView.selectedTreeRow.isCollection()) {
|
||||||
yield this.collectionsView.selectedTreeRow.ref.addItem(itemID);
|
yield this.collectionsView.selectedTreeRow.ref.addItem(itemID);
|
||||||
|
@ -3146,7 +3149,7 @@ var ZoteroPane = new function()
|
||||||
var note = items[0].getNote()
|
var note = items[0].getNote()
|
||||||
|
|
||||||
items[0].setNote(note + text);
|
items[0].setNote(note + text);
|
||||||
yield items[0].save();
|
yield items[0].saveTx();
|
||||||
|
|
||||||
var noteElem = document.getElementById('zotero-note-editor')
|
var noteElem = document.getElementById('zotero-note-editor')
|
||||||
noteElem.focus();
|
noteElem.focus();
|
||||||
|
@ -3537,7 +3540,7 @@ var ZoteroPane = new function()
|
||||||
item.setField('title', attachmentItem.getField('title'));
|
item.setField('title', attachmentItem.getField('title'));
|
||||||
item.setField('url', attachmentItem.getField('url'));
|
item.setField('url', attachmentItem.getField('url'));
|
||||||
item.setField('accessDate', attachmentItem.getField('accessDate'));
|
item.setField('accessDate', attachmentItem.getField('accessDate'));
|
||||||
yield item.save();
|
yield item.saveTx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4106,7 +4109,7 @@ var ZoteroPane = new function()
|
||||||
}
|
}
|
||||||
|
|
||||||
item.setField('title', newName);
|
item.setField('title', newName);
|
||||||
yield item.save();
|
yield item.saveTx();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -24,7 +24,7 @@ describe("Zotero.Attachments", function() {
|
||||||
|
|
||||||
// Create parent item
|
// Create parent item
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
var parentItemID = yield item.save();
|
var parentItemID = yield item.saveTx();
|
||||||
|
|
||||||
// Create attachment and compare content
|
// Create attachment and compare content
|
||||||
var itemID = yield Zotero.Attachments.importFromFile(tmpFile, parentItemID);
|
var itemID = yield Zotero.Attachments.importFromFile(tmpFile, parentItemID);
|
||||||
|
@ -43,7 +43,7 @@ describe("Zotero.Attachments", function() {
|
||||||
|
|
||||||
// Create parent item
|
// Create parent item
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
var parentItemID = yield item.save();
|
var parentItemID = yield item.saveTx();
|
||||||
|
|
||||||
// Create attachment and compare content
|
// Create attachment and compare content
|
||||||
var itemID = yield Zotero.Attachments.importFromFile(file, parentItemID);
|
var itemID = yield Zotero.Attachments.importFromFile(file, parentItemID);
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe("Zotero.Collection", function() {
|
||||||
var name = "Test";
|
var name = "Test";
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = name;
|
collection.name = name;
|
||||||
var id = yield collection.save();
|
var id = yield collection.saveTx();
|
||||||
collection = yield Zotero.Collections.getAsync(id);
|
collection = yield Zotero.Collections.getAsync(id);
|
||||||
assert.equal(collection.name, name);
|
assert.equal(collection.name, name);
|
||||||
});
|
});
|
||||||
|
@ -18,7 +18,7 @@ describe("Zotero.Collection", function() {
|
||||||
var collection = new Zotero.Collection
|
var collection = new Zotero.Collection
|
||||||
collection.version = version;
|
collection.version = version;
|
||||||
collection.name = "Test";
|
collection.name = "Test";
|
||||||
var id = yield collection.save();
|
var id = yield collection.saveTx();
|
||||||
collection = yield Zotero.Collections.getAsync(id);
|
collection = yield Zotero.Collections.getAsync(id);
|
||||||
assert.equal(collection.version, version);
|
assert.equal(collection.version, version);
|
||||||
});
|
});
|
||||||
|
@ -28,13 +28,13 @@ describe("Zotero.Collection", function() {
|
||||||
it("should set parent collection for new collections", function* () {
|
it("should set parent collection for new collections", function* () {
|
||||||
var parentCol = new Zotero.Collection
|
var parentCol = new Zotero.Collection
|
||||||
parentCol.name = "Parent";
|
parentCol.name = "Parent";
|
||||||
var parentID = yield parentCol.save();
|
var parentID = yield parentCol.saveTx();
|
||||||
var {libraryID, key: parentKey} = Zotero.Collections.getLibraryAndKeyFromID(parentID);
|
var {libraryID, key: parentKey} = Zotero.Collections.getLibraryAndKeyFromID(parentID);
|
||||||
|
|
||||||
var col = new Zotero.Collection
|
var col = new Zotero.Collection
|
||||||
col.name = "Child";
|
col.name = "Child";
|
||||||
col.parentKey = parentKey;
|
col.parentKey = parentKey;
|
||||||
var id = yield col.save();
|
var id = yield col.saveTx();
|
||||||
col = yield Zotero.Collections.getAsync(id);
|
col = yield Zotero.Collections.getAsync(id);
|
||||||
assert.equal(col.parentKey, parentKey);
|
assert.equal(col.parentKey, parentKey);
|
||||||
});
|
});
|
||||||
|
@ -43,25 +43,25 @@ describe("Zotero.Collection", function() {
|
||||||
// Create initial parent collection
|
// Create initial parent collection
|
||||||
var parentCol = new Zotero.Collection
|
var parentCol = new Zotero.Collection
|
||||||
parentCol.name = "Parent";
|
parentCol.name = "Parent";
|
||||||
var parentID = yield parentCol.save();
|
var parentID = yield parentCol.saveTx();
|
||||||
var {libraryID, key: parentKey} = Zotero.Collections.getLibraryAndKeyFromID(parentID);
|
var {libraryID, key: parentKey} = Zotero.Collections.getLibraryAndKeyFromID(parentID);
|
||||||
|
|
||||||
// Create subcollection
|
// Create subcollection
|
||||||
var col = new Zotero.Collection
|
var col = new Zotero.Collection
|
||||||
col.name = "Child";
|
col.name = "Child";
|
||||||
col.parentKey = parentKey;
|
col.parentKey = parentKey;
|
||||||
var id = yield col.save();
|
var id = yield col.saveTx();
|
||||||
col = yield Zotero.Collections.getAsync(id);
|
col = yield Zotero.Collections.getAsync(id);
|
||||||
|
|
||||||
// Create new parent collection
|
// Create new parent collection
|
||||||
var newParentCol = new Zotero.Collection
|
var newParentCol = new Zotero.Collection
|
||||||
newParentCol.name = "New Parent";
|
newParentCol.name = "New Parent";
|
||||||
var newParentID = yield newParentCol.save();
|
var newParentID = yield newParentCol.saveTx();
|
||||||
var {libraryID, key: newParentKey} = Zotero.Collections.getLibraryAndKeyFromID(newParentID);
|
var {libraryID, key: newParentKey} = Zotero.Collections.getLibraryAndKeyFromID(newParentID);
|
||||||
|
|
||||||
// Change parent collection
|
// Change parent collection
|
||||||
col.parentKey = newParentKey;
|
col.parentKey = newParentKey;
|
||||||
yield col.save();
|
yield col.saveTx();
|
||||||
col = yield Zotero.Collections.getAsync(id);
|
col = yield Zotero.Collections.getAsync(id);
|
||||||
assert.equal(col.parentKey, newParentKey);
|
assert.equal(col.parentKey, newParentKey);
|
||||||
});
|
});
|
||||||
|
@ -70,14 +70,14 @@ describe("Zotero.Collection", function() {
|
||||||
// Create initial parent collection
|
// Create initial parent collection
|
||||||
var parentCol = new Zotero.Collection
|
var parentCol = new Zotero.Collection
|
||||||
parentCol.name = "Parent";
|
parentCol.name = "Parent";
|
||||||
var parentID = yield parentCol.save();
|
var parentID = yield parentCol.saveTx();
|
||||||
var {libraryID, key: parentKey} = Zotero.Collections.getLibraryAndKeyFromID(parentID);
|
var {libraryID, key: parentKey} = Zotero.Collections.getLibraryAndKeyFromID(parentID);
|
||||||
|
|
||||||
// Create subcollection
|
// Create subcollection
|
||||||
var col = new Zotero.Collection
|
var col = new Zotero.Collection
|
||||||
col.name = "Child";
|
col.name = "Child";
|
||||||
col.parentKey = parentKey;
|
col.parentKey = parentKey;
|
||||||
var id = yield col.save();
|
var id = yield col.saveTx();
|
||||||
col = yield Zotero.Collections.getAsync(id);
|
col = yield Zotero.Collections.getAsync(id);
|
||||||
|
|
||||||
// Set to existing parent
|
// Set to existing parent
|
||||||
|
@ -88,11 +88,11 @@ describe("Zotero.Collection", function() {
|
||||||
it("should not resave a collection with no parent if set to false", function* () {
|
it("should not resave a collection with no parent if set to false", function* () {
|
||||||
var col = new Zotero.Collection
|
var col = new Zotero.Collection
|
||||||
col.name = "Test";
|
col.name = "Test";
|
||||||
var id = yield col.save();
|
var id = yield col.saveTx();
|
||||||
col = yield Zotero.Collections.getAsync(id);
|
col = yield Zotero.Collections.getAsync(id);
|
||||||
|
|
||||||
col.parentKey = false;
|
col.parentKey = false;
|
||||||
var ret = yield col.save();
|
var ret = yield col.saveTx();
|
||||||
assert.isFalse(ret);
|
assert.isFalse(ret);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
|
@ -26,7 +26,7 @@ describe("Zotero.CollectionTreeView", function() {
|
||||||
// Create collection
|
// Create collection
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = "Select new collection";
|
collection.name = "Select new collection";
|
||||||
var id = yield collection.save();
|
var id = yield collection.saveTx();
|
||||||
|
|
||||||
// New collection should be selected
|
// New collection should be selected
|
||||||
var selected = collectionsView.getSelectedCollection(true);
|
var selected = collectionsView.getSelectedCollection(true);
|
||||||
|
@ -39,7 +39,7 @@ describe("Zotero.CollectionTreeView", function() {
|
||||||
// Create collection with skipNotifier flag
|
// Create collection with skipNotifier flag
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = "No select on skipNotifier";
|
collection.name = "No select on skipNotifier";
|
||||||
var id = yield collection.save({
|
var id = yield collection.saveTx({
|
||||||
skipNotifier: true
|
skipNotifier: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ describe("Zotero.CollectionTreeView", function() {
|
||||||
// Create collection with skipSelect flag
|
// Create collection with skipSelect flag
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = "No select on skipSelect";
|
collection.name = "No select on skipSelect";
|
||||||
var id = yield collection.save({
|
var id = yield collection.saveTx({
|
||||||
skipSelect: true
|
skipSelect: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -65,13 +65,13 @@ describe("Zotero.CollectionTreeView", function() {
|
||||||
// Create collection
|
// Create collection
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = "No select on modify";
|
collection.name = "No select on modify";
|
||||||
var id = yield collection.save();
|
var id = yield collection.saveTx();
|
||||||
collection = yield Zotero.Collections.getAsync(id);
|
collection = yield Zotero.Collections.getAsync(id);
|
||||||
|
|
||||||
resetSelection();
|
resetSelection();
|
||||||
|
|
||||||
collection.name = "No select on modify 2";
|
collection.name = "No select on modify 2";
|
||||||
yield collection.save();
|
yield collection.saveTx();
|
||||||
|
|
||||||
// Modified collection should not be selected
|
// Modified collection should not be selected
|
||||||
assert.equal(collectionsView.getSelectedLibraryID(), Zotero.Libraries.userLibraryID);
|
assert.equal(collectionsView.getSelectedLibraryID(), Zotero.Libraries.userLibraryID);
|
||||||
|
@ -81,14 +81,14 @@ describe("Zotero.CollectionTreeView", function() {
|
||||||
// Create collection
|
// Create collection
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = "Reselect on modify";
|
collection.name = "Reselect on modify";
|
||||||
var id = yield collection.save();
|
var id = yield collection.saveTx();
|
||||||
collection = yield Zotero.Collections.getAsync(id);
|
collection = yield Zotero.Collections.getAsync(id);
|
||||||
|
|
||||||
var selected = collectionsView.getSelectedCollection(true);
|
var selected = collectionsView.getSelectedCollection(true);
|
||||||
assert.equal(selected, id);
|
assert.equal(selected, id);
|
||||||
|
|
||||||
collection.name = "Reselect on modify 2";
|
collection.name = "Reselect on modify 2";
|
||||||
yield collection.save();
|
yield collection.saveTx();
|
||||||
|
|
||||||
// Modified collection should still be selected
|
// Modified collection should still be selected
|
||||||
selected = collectionsView.getSelectedCollection(true);
|
selected = collectionsView.getSelectedCollection(true);
|
||||||
|
@ -98,13 +98,13 @@ describe("Zotero.CollectionTreeView", function() {
|
||||||
it("should add a saved search after collections", function* () {
|
it("should add a saved search after collections", function* () {
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = "Test";
|
collection.name = "Test";
|
||||||
var collectionID = yield collection.save();
|
var collectionID = yield collection.saveTx();
|
||||||
var cv = win.ZoteroPane.collectionsView;
|
var cv = win.ZoteroPane.collectionsView;
|
||||||
|
|
||||||
var search = new Zotero.Search;
|
var search = new Zotero.Search;
|
||||||
search.name = "A Test Search";
|
search.name = "A Test Search";
|
||||||
search.addCondition('title', 'contains', 'test');
|
search.addCondition('title', 'contains', 'test');
|
||||||
var searchID = yield search.save();
|
var searchID = yield search.saveTx();
|
||||||
|
|
||||||
var collectionRow = cv._rowMap["C" + collectionID];
|
var collectionRow = cv._rowMap["C" + collectionID];
|
||||||
var searchRow = cv._rowMap["S" + searchID];
|
var searchRow = cv._rowMap["S" + searchID];
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe("Zotero.DataObject", function() {
|
||||||
describe("#loadAllData()", function () {
|
describe("#loadAllData()", function () {
|
||||||
it("should load data on a regular item", function* () {
|
it("should load data on a regular item", function* () {
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
yield item.loadAllData();
|
yield item.loadAllData();
|
||||||
assert.throws(item.getNote.bind(item), 'getNote() can only be called on notes and attachments');
|
assert.throws(item.getNote.bind(item), 'getNote() can only be called on notes and attachments');
|
||||||
|
@ -14,7 +14,7 @@ describe("Zotero.DataObject", function() {
|
||||||
|
|
||||||
it("should load data on an attachment item", function* () {
|
it("should load data on an attachment item", function* () {
|
||||||
var item = new Zotero.Item('attachment');
|
var item = new Zotero.Item('attachment');
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
yield item.loadAllData();
|
yield item.loadAllData();
|
||||||
assert.equal(item.getNote(), '');
|
assert.equal(item.getNote(), '');
|
||||||
|
@ -22,7 +22,7 @@ describe("Zotero.DataObject", function() {
|
||||||
|
|
||||||
it("should load data on a note item", function* () {
|
it("should load data on a note item", function* () {
|
||||||
var item = new Zotero.Item('note');
|
var item = new Zotero.Item('note');
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
yield item.loadAllData();
|
yield item.loadAllData();
|
||||||
assert.equal(item.getNote(), '');
|
assert.equal(item.getNote(), '');
|
||||||
|
@ -35,7 +35,7 @@ describe("Zotero.DataObject", function() {
|
||||||
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType('collection');
|
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType('collection');
|
||||||
var obj = new Zotero.Collection;
|
var obj = new Zotero.Collection;
|
||||||
obj.name = "Test";
|
obj.name = "Test";
|
||||||
var id = yield obj.save();
|
var id = yield obj.saveTx();
|
||||||
var { libraryID, key } = objectsClass.getLibraryAndKeyFromID(id);
|
var { libraryID, key } = objectsClass.getLibraryAndKeyFromID(id);
|
||||||
assert.typeOf(key, 'string');
|
assert.typeOf(key, 'string');
|
||||||
assert.equal(objectsClass.getIDFromLibraryAndKey(libraryID, key), id);
|
assert.equal(objectsClass.getIDFromLibraryAndKey(libraryID, key), id);
|
||||||
|
@ -44,7 +44,7 @@ describe("Zotero.DataObject", function() {
|
||||||
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType('search');
|
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType('search');
|
||||||
var obj = new Zotero.Search;
|
var obj = new Zotero.Search;
|
||||||
obj.name = "Test";
|
obj.name = "Test";
|
||||||
var id = yield obj.save();
|
var id = yield obj.saveTx();
|
||||||
var { libraryID, key } = objectsClass.getLibraryAndKeyFromID(id);
|
var { libraryID, key } = objectsClass.getLibraryAndKeyFromID(id);
|
||||||
assert.typeOf(key, 'string');
|
assert.typeOf(key, 'string');
|
||||||
assert.equal(objectsClass.getIDFromLibraryAndKey(libraryID, key), id);
|
assert.equal(objectsClass.getIDFromLibraryAndKey(libraryID, key), id);
|
||||||
|
@ -52,7 +52,7 @@ describe("Zotero.DataObject", function() {
|
||||||
// Item
|
// Item
|
||||||
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType('item');
|
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType('item');
|
||||||
var obj = new Zotero.Item('book');
|
var obj = new Zotero.Item('book');
|
||||||
var id = yield obj.save();
|
var id = yield obj.saveTx();
|
||||||
var { libraryID, key } = objectsClass.getLibraryAndKeyFromID(id);
|
var { libraryID, key } = objectsClass.getLibraryAndKeyFromID(id);
|
||||||
assert.typeOf(key, 'string');
|
assert.typeOf(key, 'string');
|
||||||
assert.equal(objectsClass.getIDFromLibraryAndKey(libraryID, key), id);
|
assert.equal(objectsClass.getIDFromLibraryAndKey(libraryID, key), id);
|
||||||
|
|
|
@ -9,14 +9,15 @@ describe("Zotero.DB", function() {
|
||||||
});
|
});
|
||||||
beforeEach(function* () {
|
beforeEach(function* () {
|
||||||
yield Zotero.DB.queryAsync("DROP TABLE IF EXISTS " + tmpTable);
|
yield Zotero.DB.queryAsync("DROP TABLE IF EXISTS " + tmpTable);
|
||||||
|
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
||||||
});
|
});
|
||||||
after(function* () {
|
after(function* () {
|
||||||
yield Zotero.DB.queryAsync("DROP TABLE IF EXISTS " + tmpTable);
|
yield Zotero.DB.queryAsync("DROP TABLE IF EXISTS " + tmpTable);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#executeTransaction()", function () {
|
describe("#executeTransaction()", function () {
|
||||||
it("should nest concurrent transactions", Zotero.Promise.coroutine(function* () {
|
it("should serialize concurrent transactions", Zotero.Promise.coroutine(function* () {
|
||||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
this.timeout(1000);
|
||||||
|
|
||||||
var resolve1, resolve2, reject1, reject2;
|
var resolve1, resolve2, reject1, reject2;
|
||||||
var promise1 = new Promise(function (resolve, reject) {
|
var promise1 = new Promise(function (resolve, reject) {
|
||||||
|
@ -29,18 +30,21 @@ describe("Zotero.DB", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
Zotero.DB.executeTransaction(function* () {
|
Zotero.DB.executeTransaction(function* () {
|
||||||
yield Zotero.Promise.delay(100);
|
yield Zotero.Promise.delay(250);
|
||||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 0);
|
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
assert.equal(num, 0);
|
||||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
||||||
|
assert.ok(Zotero.DB.inTransaction());
|
||||||
})
|
})
|
||||||
.then(resolve1)
|
.then(resolve1)
|
||||||
.catch(reject1);
|
.catch(reject1);
|
||||||
|
|
||||||
Zotero.DB.executeTransaction(function* () {
|
Zotero.DB.executeTransaction(function* () {
|
||||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 1);
|
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
assert.equal(num, 1);
|
||||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
yield Zotero.Promise.delay(500);
|
||||||
|
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
||||||
|
assert.ok(Zotero.DB.inTransaction());
|
||||||
})
|
})
|
||||||
.then(resolve2)
|
.then(resolve2)
|
||||||
.catch(reject2);
|
.catch(reject2);
|
||||||
|
@ -48,10 +52,8 @@ describe("Zotero.DB", function() {
|
||||||
yield Zotero.Promise.all([promise1, promise2]);
|
yield Zotero.Promise.all([promise1, promise2]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("shouldn't nest transactions if an exclusive transaction is open", Zotero.Promise.coroutine(function* () {
|
it("should serialize queued transactions", function* () {
|
||||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
var resolve1, resolve2, reject1, reject2, resolve3, reject3;
|
||||||
|
|
||||||
var resolve1, resolve2, reject1, reject2;
|
|
||||||
var promise1 = new Promise(function (resolve, reject) {
|
var promise1 = new Promise(function (resolve, reject) {
|
||||||
resolve1 = resolve;
|
resolve1 = resolve;
|
||||||
reject1 = reject;
|
reject1 = reject;
|
||||||
|
@ -60,66 +62,48 @@ describe("Zotero.DB", function() {
|
||||||
resolve2 = resolve;
|
resolve2 = resolve;
|
||||||
reject2 = reject;
|
reject2 = reject;
|
||||||
});
|
});
|
||||||
|
var promise3 = new Promise(function (resolve, reject) {
|
||||||
|
resolve3 = resolve;
|
||||||
|
reject3 = reject;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start a transaction and have it delay
|
||||||
Zotero.DB.executeTransaction(function* () {
|
Zotero.DB.executeTransaction(function* () {
|
||||||
yield Zotero.Promise.delay(100);
|
yield Zotero.Promise.delay(100);
|
||||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 0);
|
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
||||||
|
assert.equal(num, 0);
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
||||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
assert.ok(Zotero.DB.inTransaction());
|
||||||
}, { exclusive: true })
|
})
|
||||||
.then(resolve1)
|
.then(resolve1)
|
||||||
.catch(reject1);
|
.catch(reject1);
|
||||||
|
|
||||||
|
// Start two more transactions, which should wait on the first
|
||||||
Zotero.DB.executeTransaction(function* () {
|
Zotero.DB.executeTransaction(function* () {
|
||||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 0);
|
|
||||||
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
||||||
assert.equal(num, 1);
|
assert.equal(num, 1);
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
||||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
assert.ok(Zotero.DB.inTransaction());
|
||||||
})
|
})
|
||||||
.then(resolve2)
|
.then(resolve2)
|
||||||
.catch(reject2);
|
.catch(reject2);
|
||||||
|
|
||||||
yield Zotero.Promise.all([promise1, promise2]);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("shouldn't nest an exclusive transaction if another transaction is open", Zotero.Promise.coroutine(function* () {
|
|
||||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
|
||||||
|
|
||||||
var resolve1, resolve2, reject1, reject2;
|
|
||||||
var promise1 = new Promise(function (resolve, reject) {
|
|
||||||
resolve1 = resolve;
|
|
||||||
reject1 = reject;
|
|
||||||
});
|
|
||||||
var promise2 = new Promise(function (resolve, reject) {
|
|
||||||
resolve2 = resolve;
|
|
||||||
reject2 = reject;
|
|
||||||
});
|
|
||||||
|
|
||||||
Zotero.DB.executeTransaction(function* () {
|
Zotero.DB.executeTransaction(function* () {
|
||||||
yield Zotero.Promise.delay(100);
|
|
||||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 0);
|
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
|
||||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
|
||||||
})
|
|
||||||
.then(resolve1)
|
|
||||||
.catch(reject1);
|
|
||||||
|
|
||||||
Zotero.DB.executeTransaction(function* () {
|
|
||||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 0);
|
|
||||||
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
||||||
assert.equal(num, 1);
|
assert.equal(num, 2);
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (3)");
|
||||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
// But make sure the second queued transaction doesn't start at the same time,
|
||||||
}, { exclusive: true })
|
// such that the first queued transaction gets closed while the second is still
|
||||||
.then(resolve2)
|
// running
|
||||||
.catch(reject2);
|
assert.ok(Zotero.DB.inTransaction());
|
||||||
|
})
|
||||||
|
.then(resolve3)
|
||||||
|
.catch(reject3);
|
||||||
|
|
||||||
yield Zotero.Promise.all([promise1, promise2]);
|
yield Zotero.Promise.all([promise1, promise2, promise3]);
|
||||||
}));
|
})
|
||||||
|
|
||||||
it("should roll back on error", function* () {
|
it("should roll back on error", function* () {
|
||||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
||||||
try {
|
try {
|
||||||
yield Zotero.DB.executeTransaction(function* () {
|
yield Zotero.DB.executeTransaction(function* () {
|
||||||
|
@ -141,7 +125,6 @@ describe("Zotero.DB", function() {
|
||||||
|
|
||||||
it("should run onRollback callbacks", function* () {
|
it("should run onRollback callbacks", function* () {
|
||||||
var callbackRan = false;
|
var callbackRan = false;
|
||||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
|
||||||
try {
|
try {
|
||||||
yield Zotero.DB.executeTransaction(
|
yield Zotero.DB.executeTransaction(
|
||||||
function* () {
|
function* () {
|
||||||
|
@ -163,25 +146,31 @@ describe("Zotero.DB", function() {
|
||||||
yield Zotero.DB.queryAsync("DROP TABLE " + tmpTable);
|
yield Zotero.DB.queryAsync("DROP TABLE " + tmpTable);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should run onRollback callbacks for nested transactions", function* () {
|
it("should time out on nested transactions", function* () {
|
||||||
|
var e;
|
||||||
|
yield Zotero.DB.executeTransaction(function* () {
|
||||||
|
e = yield getPromiseError(
|
||||||
|
Zotero.DB.executeTransaction(function* () {}).timeout(250)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
assert.ok(e);
|
||||||
|
assert.equal(e.name, "TimeoutError");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should run onRollback callbacks for timed-out nested transactions", function* () {
|
||||||
var callback1Ran = false;
|
var callback1Ran = false;
|
||||||
var callback2Ran = false;
|
var callback2Ran = false;
|
||||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
|
||||||
try {
|
try {
|
||||||
yield Zotero.DB.executeTransaction(function* () {
|
yield Zotero.DB.executeTransaction(function* () {
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
|
||||||
yield Zotero.DB.executeTransaction(
|
yield Zotero.DB.executeTransaction(
|
||||||
function* () {
|
function* () {},
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
|
||||||
|
|
||||||
throw 'Aborting transaction -- ignore';
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
|
waitTimeout: 100,
|
||||||
onRollback: function () {
|
onRollback: function () {
|
||||||
callback1Ran = true;
|
callback1Ran = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onRollback: function () {
|
onRollback: function () {
|
||||||
|
@ -190,32 +179,10 @@ describe("Zotero.DB", function() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if (typeof e != 'string' || !e.startsWith('Aborting transaction')) throw e;
|
if (e.name != "TimeoutError") throw e;
|
||||||
}
|
}
|
||||||
assert.ok(callback1Ran);
|
assert.ok(callback1Ran);
|
||||||
assert.ok(callback2Ran);
|
assert.ok(callback2Ran);
|
||||||
|
|
||||||
yield Zotero.DB.queryAsync("DROP TABLE " + tmpTable);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not commit nested transactions", function* () {
|
|
||||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
|
||||||
try {
|
|
||||||
yield Zotero.DB.executeTransaction(function* () {
|
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
|
||||||
yield Zotero.DB.executeTransaction(function* () {
|
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
|
||||||
throw 'Aborting transaction -- ignore';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
if (typeof e != 'string' || !e.startsWith('Aborting transaction')) throw e;
|
|
||||||
}
|
|
||||||
var count = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
|
||||||
assert.equal(count, 0);
|
|
||||||
|
|
||||||
yield Zotero.DB.queryAsync("DROP TABLE " + tmpTable);
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -36,7 +36,7 @@ describe("Zotero.Item", function () {
|
||||||
var fieldID = Zotero.ItemFields.getID(field);
|
var fieldID = Zotero.ItemFields.getID(field);
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
item.setField(field, 'Foo');
|
item.setField(field, 'Foo');
|
||||||
id = yield item.save();
|
id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
|
|
||||||
item.setField(field, "");
|
item.setField(field, "");
|
||||||
|
@ -57,7 +57,7 @@ describe("Zotero.Item", function () {
|
||||||
assert.ok(item._changed.itemData[fieldID]);
|
assert.ok(item._changed.itemData[fieldID]);
|
||||||
assert.ok(item.hasChanged());
|
assert.ok(item.hasChanged());
|
||||||
|
|
||||||
yield item.save();
|
yield item.saveTx();
|
||||||
assert.isFalse(item.getField(fieldID));
|
assert.isFalse(item.getField(fieldID));
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ describe("Zotero.Item", function () {
|
||||||
it("should save version as object version", function* () {
|
it("should save version as object version", function* () {
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
item.setField("version", 1);
|
item.setField("version", 1);
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
assert.equal(item.getField("version"), 1);
|
assert.equal(item.getField("version"), 1);
|
||||||
});
|
});
|
||||||
|
@ -78,7 +78,7 @@ describe("Zotero.Item", function () {
|
||||||
it("should save versionNumber for computerProgram", function () {
|
it("should save versionNumber for computerProgram", function () {
|
||||||
var item = new Zotero.Item('computerProgram');
|
var item = new Zotero.Item('computerProgram');
|
||||||
item.setField("versionNumber", "1.0");
|
item.setField("versionNumber", "1.0");
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
assert.equal(item.getField("versionNumber"), "1.0");
|
assert.equal(item.getField("versionNumber"), "1.0");
|
||||||
});
|
});
|
||||||
|
@ -89,7 +89,7 @@ describe("Zotero.Item", function () {
|
||||||
var dateModified = "2015-05-05 17:18:12";
|
var dateModified = "2015-05-05 17:18:12";
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
item.dateModified = dateModified;
|
item.dateModified = dateModified;
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
assert.equal(item.dateModified, dateModified);
|
assert.equal(item.dateModified, dateModified);
|
||||||
})
|
})
|
||||||
|
@ -98,7 +98,7 @@ describe("Zotero.Item", function () {
|
||||||
var dateModified = "2015-05-05 17:18:12";
|
var dateModified = "2015-05-05 17:18:12";
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
item.dateModified = dateModified;
|
item.dateModified = dateModified;
|
||||||
var id = yield item.save({
|
var id = yield item.saveTx({
|
||||||
skipDateModifiedUpdate: true
|
skipDateModifiedUpdate: true
|
||||||
});
|
});
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
|
@ -109,13 +109,13 @@ describe("Zotero.Item", function () {
|
||||||
var dateModified = "2015-05-05 17:18:12";
|
var dateModified = "2015-05-05 17:18:12";
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
item.dateModified = dateModified;
|
item.dateModified = dateModified;
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
|
|
||||||
// Save again without changing Date Modified
|
// Save again without changing Date Modified
|
||||||
yield item.loadItemData();
|
yield item.loadItemData();
|
||||||
item.setField('title', 'Test');
|
item.setField('title', 'Test');
|
||||||
yield item.save()
|
yield item.saveTx()
|
||||||
|
|
||||||
assert.closeTo(Zotero.Date.sqlToDate(item.dateModified, true).getTime(), Date.now(), 1000);
|
assert.closeTo(Zotero.Date.sqlToDate(item.dateModified, true).getTime(), Date.now(), 1000);
|
||||||
})
|
})
|
||||||
|
@ -124,20 +124,20 @@ describe("Zotero.Item", function () {
|
||||||
var dateModified = "2015-05-05 17:18:12";
|
var dateModified = "2015-05-05 17:18:12";
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
item.dateModified = dateModified;
|
item.dateModified = dateModified;
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
|
|
||||||
// Set Date Modified to existing value
|
// Set Date Modified to existing value
|
||||||
yield item.loadItemData();
|
yield item.loadItemData();
|
||||||
item.setField('title', 'Test');
|
item.setField('title', 'Test');
|
||||||
item.dateModified = dateModified;
|
item.dateModified = dateModified;
|
||||||
yield item.save()
|
yield item.saveTx()
|
||||||
assert.closeTo(Zotero.Date.sqlToDate(item.dateModified, true).getTime(), Date.now(), 1000);
|
assert.closeTo(Zotero.Date.sqlToDate(item.dateModified, true).getTime(), Date.now(), 1000);
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should use current time if Date Modified is not given when skipDateModifiedUpdate is set for a new item", function* () {
|
it("should use current time if Date Modified is not given when skipDateModifiedUpdate is set for a new item", function* () {
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
var id = yield item.save({
|
var id = yield item.saveTx({
|
||||||
skipDateModifiedUpdate: true
|
skipDateModifiedUpdate: true
|
||||||
});
|
});
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
|
@ -148,13 +148,13 @@ describe("Zotero.Item", function () {
|
||||||
var dateModified = "2015-05-05 17:18:12";
|
var dateModified = "2015-05-05 17:18:12";
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
item.dateModified = dateModified;
|
item.dateModified = dateModified;
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
|
|
||||||
// Resave with skipDateModifiedUpdate
|
// Resave with skipDateModifiedUpdate
|
||||||
yield item.loadItemData();
|
yield item.loadItemData();
|
||||||
item.setField('title', 'Test');
|
item.setField('title', 'Test');
|
||||||
yield item.save({
|
yield item.saveTx({
|
||||||
skipDateModifiedUpdate: true
|
skipDateModifiedUpdate: true
|
||||||
})
|
})
|
||||||
assert.equal(item.dateModified, dateModified);
|
assert.equal(item.dateModified, dateModified);
|
||||||
|
@ -164,11 +164,11 @@ describe("Zotero.Item", function () {
|
||||||
describe("#parentID", function () {
|
describe("#parentID", function () {
|
||||||
it("should create a child note", function* () {
|
it("should create a child note", function* () {
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
var parentItemID = yield item.save();
|
var parentItemID = yield item.saveTx();
|
||||||
|
|
||||||
item = new Zotero.Item('note');
|
item = new Zotero.Item('note');
|
||||||
item.parentID = parentItemID;
|
item.parentID = parentItemID;
|
||||||
var childItemID = yield item.save();
|
var childItemID = yield item.saveTx();
|
||||||
|
|
||||||
item = yield Zotero.Items.getAsync(childItemID);
|
item = yield Zotero.Items.getAsync(childItemID);
|
||||||
assert.ok(item.parentID);
|
assert.ok(item.parentID);
|
||||||
|
@ -198,7 +198,7 @@ describe("Zotero.Item", function () {
|
||||||
var item = new Zotero.Item('attachment');
|
var item = new Zotero.Item('attachment');
|
||||||
item.attachmentLinkMode = 'linked_url';
|
item.attachmentLinkMode = 'linked_url';
|
||||||
item.url = "https://www.zotero.org/";
|
item.url = "https://www.zotero.org/";
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
|
|
||||||
item.parentKey = false;
|
item.parentKey = false;
|
||||||
|
@ -207,15 +207,15 @@ describe("Zotero.Item", function () {
|
||||||
|
|
||||||
it("should move a top-level note under another item", function* () {
|
it("should move a top-level note under another item", function* () {
|
||||||
var noteItem = new Zotero.Item('note');
|
var noteItem = new Zotero.Item('note');
|
||||||
var id = yield noteItem.save()
|
var id = yield noteItem.saveTx()
|
||||||
noteItem = yield Zotero.Items.getAsync(id);
|
noteItem = yield Zotero.Items.getAsync(id);
|
||||||
|
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
id = yield item.save();
|
id = yield item.saveTx();
|
||||||
var { libraryID, key } = Zotero.Items.getLibraryAndKeyFromID(id);
|
var { libraryID, key } = Zotero.Items.getLibraryAndKeyFromID(id);
|
||||||
|
|
||||||
noteItem.parentKey = key;
|
noteItem.parentKey = key;
|
||||||
yield noteItem.save();
|
yield noteItem.saveTx();
|
||||||
|
|
||||||
assert.isFalse(noteItem.isTopLevelItem());
|
assert.isFalse(noteItem.isTopLevelItem());
|
||||||
})
|
})
|
||||||
|
@ -224,19 +224,19 @@ describe("Zotero.Item", function () {
|
||||||
// Create a collection
|
// Create a collection
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = "Test";
|
collection.name = "Test";
|
||||||
var collectionID = yield collection.save();
|
var collectionID = yield collection.saveTx();
|
||||||
|
|
||||||
// Create a top-level note and add it to a collection
|
// Create a top-level note and add it to a collection
|
||||||
var noteItem = new Zotero.Item('note');
|
var noteItem = new Zotero.Item('note');
|
||||||
noteItem.addToCollection(collectionID);
|
noteItem.addToCollection(collectionID);
|
||||||
var id = yield noteItem.save()
|
var id = yield noteItem.saveTx()
|
||||||
noteItem = yield Zotero.Items.getAsync(id);
|
noteItem = yield Zotero.Items.getAsync(id);
|
||||||
|
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
id = yield item.save();
|
id = yield item.saveTx();
|
||||||
var { libraryID, key } = Zotero.Items.getLibraryAndKeyFromID(id);
|
var { libraryID, key } = Zotero.Items.getLibraryAndKeyFromID(id);
|
||||||
noteItem.parentKey = key;
|
noteItem.parentKey = key;
|
||||||
yield noteItem.save();
|
yield noteItem.saveTx();
|
||||||
|
|
||||||
assert.isFalse(noteItem.isTopLevelItem());
|
assert.isFalse(noteItem.isTopLevelItem());
|
||||||
})
|
})
|
||||||
|
@ -258,7 +258,7 @@ describe("Zotero.Item", function () {
|
||||||
|
|
||||||
var item = new Zotero.Item("journalArticle");
|
var item = new Zotero.Item("journalArticle");
|
||||||
item.setCreators(creators);
|
item.setCreators(creators);
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
yield item.loadCreators();
|
yield item.loadCreators();
|
||||||
assert.sameDeepMembers(item.getCreatorsJSON(), creators);
|
assert.sameDeepMembers(item.getCreatorsJSON(), creators);
|
||||||
|
@ -282,7 +282,7 @@ describe("Zotero.Item", function () {
|
||||||
|
|
||||||
var item = new Zotero.Item("journalArticle");
|
var item = new Zotero.Item("journalArticle");
|
||||||
item.setCreators(creators);
|
item.setCreators(creators);
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
yield item.loadCreators();
|
yield item.loadCreators();
|
||||||
assert.sameDeepMembers(item.getCreators(), creators);
|
assert.sameDeepMembers(item.getCreators(), creators);
|
||||||
|
@ -295,7 +295,7 @@ describe("Zotero.Item", function () {
|
||||||
var item = new Zotero.Item("attachment");
|
var item = new Zotero.Item("attachment");
|
||||||
item.attachmentLinkMode = Zotero.Attachments.LINK_MODE_IMPORTED_FILE;
|
item.attachmentLinkMode = Zotero.Attachments.LINK_MODE_IMPORTED_FILE;
|
||||||
item.attachmentCharset = charset;
|
item.attachmentCharset = charset;
|
||||||
var itemID = yield item.save();
|
var itemID = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(itemID);
|
item = yield Zotero.Items.getAsync(itemID);
|
||||||
assert.equal(item.attachmentCharset, charset);
|
assert.equal(item.attachmentCharset, charset);
|
||||||
})
|
})
|
||||||
|
@ -305,7 +305,7 @@ describe("Zotero.Item", function () {
|
||||||
var item = new Zotero.Item("attachment");
|
var item = new Zotero.Item("attachment");
|
||||||
item.attachmentLinkMode = Zotero.Attachments.LINK_MODE_IMPORTED_FILE;
|
item.attachmentLinkMode = Zotero.Attachments.LINK_MODE_IMPORTED_FILE;
|
||||||
item.attachmentCharset = charset;
|
item.attachmentCharset = charset;
|
||||||
var itemID = yield item.save();
|
var itemID = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(itemID);
|
item = yield Zotero.Items.getAsync(itemID);
|
||||||
|
|
||||||
// Set charset to same value
|
// Set charset to same value
|
||||||
|
@ -320,20 +320,20 @@ describe("Zotero.Item", function () {
|
||||||
|
|
||||||
// Create parent item
|
// Create parent item
|
||||||
var item = new Zotero.Item("book");
|
var item = new Zotero.Item("book");
|
||||||
var parentItemID = yield item.save();
|
var parentItemID = yield item.saveTx();
|
||||||
|
|
||||||
// Create attachment item
|
// Create attachment item
|
||||||
var item = new Zotero.Item("attachment");
|
var item = new Zotero.Item("attachment");
|
||||||
item.attachmentLinkMode = Zotero.Attachments.LINK_MODE_IMPORTED_FILE;
|
item.attachmentLinkMode = Zotero.Attachments.LINK_MODE_IMPORTED_FILE;
|
||||||
item.parentID = parentItemID;
|
item.parentID = parentItemID;
|
||||||
var itemID = yield item.save();
|
var itemID = yield item.saveTx();
|
||||||
|
|
||||||
// Should be empty when unset
|
// Should be empty when unset
|
||||||
assert.equal(item.attachmentFilename, '');
|
assert.equal(item.attachmentFilename, '');
|
||||||
|
|
||||||
// Set filename
|
// Set filename
|
||||||
item.attachmentFilename = filename;
|
item.attachmentFilename = filename;
|
||||||
yield item.save();
|
yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(itemID);
|
item = yield Zotero.Items.getAsync(itemID);
|
||||||
|
|
||||||
// Check filename
|
// Check filename
|
||||||
|
@ -358,7 +358,7 @@ describe("Zotero.Item", function () {
|
||||||
];
|
];
|
||||||
var item = new Zotero.Item('journalArticle');
|
var item = new Zotero.Item('journalArticle');
|
||||||
item.setTags(tags);
|
item.setTags(tags);
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
yield item.loadTags();
|
yield item.loadTags();
|
||||||
assert.sameDeepMembers(item.getTags(tags), tags);
|
assert.sameDeepMembers(item.getTags(tags), tags);
|
||||||
|
@ -375,7 +375,7 @@ describe("Zotero.Item", function () {
|
||||||
];
|
];
|
||||||
var item = new Zotero.Item('journalArticle');
|
var item = new Zotero.Item('journalArticle');
|
||||||
item.setTags(tags);
|
item.setTags(tags);
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
yield item.loadTags();
|
yield item.loadTags();
|
||||||
item.setTags(tags);
|
item.setTags(tags);
|
||||||
|
@ -393,11 +393,11 @@ describe("Zotero.Item", function () {
|
||||||
];
|
];
|
||||||
var item = new Zotero.Item('journalArticle');
|
var item = new Zotero.Item('journalArticle');
|
||||||
item.setTags(tags);
|
item.setTags(tags);
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
yield item.loadTags();
|
yield item.loadTags();
|
||||||
item.setTags(tags.slice(0));
|
item.setTags(tags.slice(0));
|
||||||
yield item.save();
|
yield item.saveTx();
|
||||||
assert.sameDeepMembers(item.getTags(tags), tags.slice(0));
|
assert.sameDeepMembers(item.getTags(tags), tags.slice(0));
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe("Zotero.ItemTreeView", function() {
|
||||||
itemsView = win.ZoteroPane.itemsView;
|
itemsView = win.ZoteroPane.itemsView;
|
||||||
|
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
existingItemID = yield item.save();
|
existingItemID = yield item.saveTx();
|
||||||
});
|
});
|
||||||
after(function () {
|
after(function () {
|
||||||
win.close();
|
win.close();
|
||||||
|
@ -47,7 +47,7 @@ describe("Zotero.ItemTreeView", function() {
|
||||||
|
|
||||||
// Create item
|
// Create item
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
|
|
||||||
// New item should be selected
|
// New item should be selected
|
||||||
var selected = itemsView.getSelectedItems();
|
var selected = itemsView.getSelectedItems();
|
||||||
|
@ -71,7 +71,7 @@ describe("Zotero.ItemTreeView", function() {
|
||||||
|
|
||||||
// Create item with skipNotifier flag
|
// Create item with skipNotifier flag
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
var id = yield item.save({
|
var id = yield item.saveTx({
|
||||||
skipNotifier: true
|
skipNotifier: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ describe("Zotero.ItemTreeView", function() {
|
||||||
|
|
||||||
// Create item with skipSelect flag
|
// Create item with skipSelect flag
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
var id = yield item.save({
|
var id = yield item.saveTx({
|
||||||
skipSelect: true
|
skipSelect: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ describe("Zotero.ItemTreeView", function() {
|
||||||
it("shouldn't select a modified item", function* () {
|
it("shouldn't select a modified item", function* () {
|
||||||
// Create item
|
// Create item
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
|
|
||||||
itemsView.selection.clearSelection();
|
itemsView.selection.clearSelection();
|
||||||
|
@ -124,7 +124,7 @@ describe("Zotero.ItemTreeView", function() {
|
||||||
|
|
||||||
// Modify item
|
// Modify item
|
||||||
item.setField('title', 'no select on modify');
|
item.setField('title', 'no select on modify');
|
||||||
yield item.save();
|
yield item.saveTx();
|
||||||
|
|
||||||
// itemSelected should have been called once (from 'selectEventsSuppressed = false'
|
// itemSelected should have been called once (from 'selectEventsSuppressed = false'
|
||||||
// in notify()) as a no-op
|
// in notify()) as a no-op
|
||||||
|
@ -138,7 +138,7 @@ describe("Zotero.ItemTreeView", function() {
|
||||||
it("should maintain selection on a selected modified item", function* () {
|
it("should maintain selection on a selected modified item", function* () {
|
||||||
// Create item
|
// Create item
|
||||||
var item = new Zotero.Item('book');
|
var item = new Zotero.Item('book');
|
||||||
var id = yield item.save();
|
var id = yield item.saveTx();
|
||||||
item = yield Zotero.Items.getAsync(id);
|
item = yield Zotero.Items.getAsync(id);
|
||||||
|
|
||||||
yield itemsView.selectItem(id);
|
yield itemsView.selectItem(id);
|
||||||
|
@ -151,7 +151,7 @@ describe("Zotero.ItemTreeView", function() {
|
||||||
|
|
||||||
// Modify item
|
// Modify item
|
||||||
item.setField('title', 'maintain selection on modify');
|
item.setField('title', 'maintain selection on modify');
|
||||||
yield item.save();
|
yield item.saveTx();
|
||||||
|
|
||||||
// itemSelected should have been called once (from 'selectEventsSuppressed = false'
|
// itemSelected should have been called once (from 'selectEventsSuppressed = false'
|
||||||
// in notify()) as a no-op
|
// in notify()) as a no-op
|
||||||
|
|
|
@ -3,7 +3,7 @@ describe("Zotero.Search", function() {
|
||||||
it("should fail without a name", function* () {
|
it("should fail without a name", function* () {
|
||||||
var s = new Zotero.Search;
|
var s = new Zotero.Search;
|
||||||
s.addCondition('title', 'is', 'test');
|
s.addCondition('title', 'is', 'test');
|
||||||
var e = yield getPromiseError(s.save());
|
var e = yield getPromiseError(s.saveTx());
|
||||||
assert.ok(e);
|
assert.ok(e);
|
||||||
assert.equal(e.constructor.name, Error.prototype.constructor.name); // TEMP: Error mismatch
|
assert.equal(e.constructor.name, Error.prototype.constructor.name); // TEMP: Error mismatch
|
||||||
assert.equal(e.message, "Name not provided for saved search");
|
assert.equal(e.message, "Name not provided for saved search");
|
||||||
|
@ -14,7 +14,7 @@ describe("Zotero.Search", function() {
|
||||||
var s = new Zotero.Search;
|
var s = new Zotero.Search;
|
||||||
s.name = "Test";
|
s.name = "Test";
|
||||||
s.addCondition('title', 'is', 'test');
|
s.addCondition('title', 'is', 'test');
|
||||||
var id = yield s.save();
|
var id = yield s.saveTx();
|
||||||
assert.typeOf(id, 'number');
|
assert.typeOf(id, 'number');
|
||||||
|
|
||||||
// Check saved search
|
// Check saved search
|
||||||
|
@ -40,14 +40,14 @@ describe("Zotero.Search", function() {
|
||||||
s.libraryID = Zotero.Libraries.userLibraryID;
|
s.libraryID = Zotero.Libraries.userLibraryID;
|
||||||
s.name = "Test";
|
s.name = "Test";
|
||||||
s.addCondition('title', 'is', 'test');
|
s.addCondition('title', 'is', 'test');
|
||||||
var id = yield s.save();
|
var id = yield s.saveTx();
|
||||||
assert.typeOf(id, 'number');
|
assert.typeOf(id, 'number');
|
||||||
|
|
||||||
// Add condition
|
// Add condition
|
||||||
s = yield Zotero.Searches.getAsync(id);
|
s = yield Zotero.Searches.getAsync(id);
|
||||||
yield s.loadConditions();
|
yield s.loadConditions();
|
||||||
s.addCondition('title', 'contains', 'foo');
|
s.addCondition('title', 'contains', 'foo');
|
||||||
var saved = yield s.save();
|
var saved = yield s.saveTx();
|
||||||
assert.isTrue(saved);
|
assert.isTrue(saved);
|
||||||
|
|
||||||
// Check saved search
|
// Check saved search
|
||||||
|
@ -64,14 +64,14 @@ describe("Zotero.Search", function() {
|
||||||
s.name = "Test";
|
s.name = "Test";
|
||||||
s.addCondition('title', 'is', 'test');
|
s.addCondition('title', 'is', 'test');
|
||||||
s.addCondition('title', 'contains', 'foo');
|
s.addCondition('title', 'contains', 'foo');
|
||||||
var id = yield s.save();
|
var id = yield s.saveTx();
|
||||||
assert.typeOf(id, 'number');
|
assert.typeOf(id, 'number');
|
||||||
|
|
||||||
// Remove condition
|
// Remove condition
|
||||||
s = yield Zotero.Searches.getAsync(id);
|
s = yield Zotero.Searches.getAsync(id);
|
||||||
yield s.loadConditions();
|
yield s.loadConditions();
|
||||||
s.removeCondition(0);
|
s.removeCondition(0);
|
||||||
var saved = yield s.save();
|
var saved = yield s.saveTx();
|
||||||
assert.isTrue(saved);
|
assert.isTrue(saved);
|
||||||
|
|
||||||
// Check saved search
|
// Check saved search
|
||||||
|
|
|
@ -39,7 +39,7 @@ describe("ZoteroPane", function() {
|
||||||
it("should update the item count", function* () {
|
it("should update the item count", function* () {
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = "Count Test";
|
collection.name = "Count Test";
|
||||||
var id = yield collection.save();
|
var id = yield collection.saveTx();
|
||||||
yield waitForItemsLoad(win);
|
yield waitForItemsLoad(win);
|
||||||
|
|
||||||
// Unselected, with no items in view
|
// Unselected, with no items in view
|
||||||
|
@ -51,7 +51,7 @@ describe("ZoteroPane", function() {
|
||||||
// Unselected, with one item in view
|
// Unselected, with one item in view
|
||||||
var item = new Zotero.Item('newspaperArticle');
|
var item = new Zotero.Item('newspaperArticle');
|
||||||
item.setCollections([id]);
|
item.setCollections([id]);
|
||||||
var itemID1 = yield item.save({
|
var itemID1 = yield item.saveTx({
|
||||||
skipSelect: true
|
skipSelect: true
|
||||||
});
|
});
|
||||||
assert.equal(
|
assert.equal(
|
||||||
|
@ -62,7 +62,7 @@ describe("ZoteroPane", function() {
|
||||||
// Unselected, with multiple items in view
|
// Unselected, with multiple items in view
|
||||||
var item = new Zotero.Item('audioRecording');
|
var item = new Zotero.Item('audioRecording');
|
||||||
item.setCollections([id]);
|
item.setCollections([id]);
|
||||||
var itemID2 = yield item.save({
|
var itemID2 = yield item.saveTx({
|
||||||
skipSelect: true
|
skipSelect: true
|
||||||
});
|
});
|
||||||
assert.equal(
|
assert.equal(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue