commit e2cbfbd0fecfa2afee127f9e85382a03f0edd45a
parent bf416e56c2d49896739b4ddbf235abff294d4b87
Author: Dan Stillman <dstillman@zotero.org>
Date: Thu, 21 Apr 2016 11:07:16 -0400
Deasyncify Zotero.Tags.getID()/getAsync(), and add Zotero.Tags.create()
Diffstat:
8 files changed, 89 insertions(+), 31 deletions(-)
diff --git a/chrome/content/zotero/bindings/tagselector.xml b/chrome/content/zotero/bindings/tagselector.xml
@@ -669,7 +669,7 @@
this.selection.delete(oldName);
}
- if (yield Zotero.Tags.getID(oldName)) {
+ if (Zotero.Tags.getID(oldName)) {
yield Zotero.Tags.rename(this.libraryID, oldName, newName.value);
}
// Colored tags don't need to exist, so in that case
@@ -707,7 +707,7 @@
return;
}
- var tagID = yield Zotero.Tags.getID(name);
+ var tagID = Zotero.Tags.getID(name);
if (tagID) {
yield Zotero.Tags.removeFromLibrary(this.libraryID, tagID);
}
diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js
@@ -1621,7 +1621,7 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
for (let i=0; i<toAdd.length; i++) {
let tag = toAdd[i];
- let tagID = yield Zotero.Tags.getID(tag.tag, true);
+ let tagID = yield Zotero.Tags.create(tag.tag);
let tagType = tag.type ? tag.type : 0;
// "OR REPLACE" allows changing type
let sql = "INSERT OR REPLACE INTO itemTags (itemID, tagID, type) VALUES (?, ?, ?)";
@@ -1639,7 +1639,7 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
if (toRemove.length) {
for (let i=0; i<toRemove.length; i++) {
let tag = toRemove[i];
- let tagID = yield Zotero.Tags.getID(tag.tag);
+ let tagID = Zotero.Tags.getID(tag.tag);
let sql = "DELETE FROM itemTags WHERE itemID=? AND tagID=? AND type=?";
yield Zotero.DB.queryAsync(sql, [this.id, tagID, tag.type ? tag.type : 0]);
let notifierData = {};
@@ -3319,6 +3319,8 @@ Zotero.Item.prototype.addTag = function (name, type) {
/**
* Replace an existing tag with a new manual tag
*
+ * A separate save() is required to update the database.
+ *
* @param {String} oldTag
* @param {String} newTag
*/
@@ -3358,13 +3360,11 @@ Zotero.Item.prototype.replaceTag = function (oldTag, newTag) {
*/
Zotero.Item.prototype.removeTag = function(tagName) {
this._requireData('tags');
- Zotero.debug(this._tags);
var newTags = this._tags.filter(function (tagData) tagData.tag !== tagName);
if (newTags.length == this._tags.length) {
Zotero.debug('Cannot remove missing tag ' + tagName + ' from item ' + this.libraryKey);
return;
}
- Zotero.debug(newTags);
this.setTags(newTags);
}
diff --git a/chrome/content/zotero/xpcom/data/tags.js b/chrome/content/zotero/xpcom/data/tags.js
@@ -30,12 +30,32 @@
Zotero.Tags = new function() {
this.MAX_COLORED_TAGS = 6;
+ var _initialized = false;
+ var _tagsByID = new Map();
+ var _idsByTag = new Map();
var _libraryColors = {};
var _libraryColorsByName = {};
var _itemsListImagePromises = {};
var _itemsListExtraImagePromises = {};
+ this.init = Zotero.Promise.coroutine(function* () {
+ yield Zotero.DB.queryAsync(
+ "SELECT tagID, name FROM tags",
+ false,
+ {
+ onRow: function (row) {
+ var tagID = row.getResultByIndex(0);
+ var name = row.getResultByIndex(1);
+ _tagsByID.set(tagID, name);
+ _idsByTag.set(name, tagID);
+ }
+ }
+ );
+ _initialized = true;
+ });
+
+
/**
* Returns a tag for a given tagID
*
@@ -43,31 +63,61 @@ Zotero.Tags = new function() {
* @return {Promise<String|false>} - A tag name, or false if tag with id not found
*/
this.getName = function (tagID) {
- return Zotero.DB.valueQueryAsync("SELECT name FROM tags WHERE tagID=?", tagID);
- }
+ if (!_initialized) {
+ throw new Zotero.Exception.UnloadedDataException("Tags not yet loaded");
+ }
+
+ var name = _tagsByID.get(tagID);
+ return name !== undefined ? name : false;
+ };
/**
- * Returns the tagID matching given fields, or creates a new tag and returns its id
+ * Returns the tagID matching given fields, or false if none
+ *
+ * @param {String} name - Tag data in API JSON format
+ * @return {Integer} tagID
+ */
+ this.getID = function (name) {
+ if (!_initialized) {
+ throw new Zotero.Exception.UnloadedDataException("Tags not yet loaded");
+ }
+ if (arguments.length > 1) {
+ throw new Error("Zotero.Tags.getID() no longer takes a second parameter -- use Zotero.Tags.create()");
+ }
+
+ data = this.cleanData({
+ tag: name
+ });
+ var id = _idsByTag.get(data.tag);
+ return id !== undefined ? id : false;
+ };
+
+
+ /**
+ * Returns the tagID matching given fields, or creates one and returns its id
+ *
+ * Requires a wrapping transaction
*
* @param {String} name - Tag data in API JSON format
- * @param {Boolean} [create=false] - If no matching tag, create one;
- * requires a wrapping transaction
* @return {Promise<Integer>} tagID
*/
- this.getID = Zotero.Promise.coroutine(function* (name, create) {
- if (create) {
- Zotero.DB.requireTransaction();
+ this.create = Zotero.Promise.coroutine(function* (name) {
+ if (!_initialized) {
+ throw new Zotero.Exception.UnloadedDataException("Tags not yet loaded");
}
+
+ Zotero.DB.requireTransaction();
data = this.cleanData({
tag: name
});
- var sql = "SELECT tagID FROM tags WHERE name=?";
- var id = yield Zotero.DB.valueQueryAsync(sql, data.tag);
- if (!id && create) {
+ var id = this.getID(data.tag);
+ if (!id) {
id = Zotero.ID.get('tags');
let sql = "INSERT INTO tags (tagID, name) VALUES (?, ?)";
yield Zotero.DB.queryAsync(sql, [id, data.tag]);
+ _tagsByID.set(id, data.tag);
+ _idsByTag.set(data.tag, id);
}
return id;
});
@@ -252,7 +302,7 @@ Zotero.Tags = new function() {
var notifierData = {};
for (let i=0; i<tagIDs.length; i++) {
let tagID = tagIDs[i];
- let name = yield this.getName(tagID);
+ let name = this.getName(tagID);
if (name === false) {
continue;
}
@@ -314,11 +364,14 @@ Zotero.Tags = new function() {
/**
* Delete obsolete tags from database
*
- * @param {Number} libraryID
* @param {Number|Number[]} [tagIDs] - tagID or array of tagIDs to purge
* @return {Promise}
*/
this.purge = Zotero.Promise.coroutine(function* (tagIDs) {
+ if (!_initialized) {
+ throw new Zotero.Exception.UnloadedDataException("Tags not yet loaded");
+ }
+
if (!tagIDs && !Zotero.Prefs.get('purge.tags')) {
return;
}
@@ -363,6 +416,12 @@ Zotero.Tags = new function() {
notifierData = {};
for (let i=0; i<toDelete.length; i++) {
let row = toDelete[i];
+
+ Zotero.DB.addCurrentCallback('commit', () => {
+ _tagsByID.delete(row.id);
+ _idsByTag.delete(row.name);
+ });
+
ids.push(row.id);
notifierData[row.id] = {
old: {
diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js
@@ -625,6 +625,7 @@ Components.utils.import("resource://gre/modules/osfile.jsm");
yield Zotero.Collections.init();
yield Zotero.Items.init();
yield Zotero.Searches.init();
+ yield Zotero.Tags.init();
yield Zotero.Creators.init();
yield Zotero.Groups.init();
yield Zotero.Relations.init();
diff --git a/test/tests/supportTest.js b/test/tests/supportTest.js
@@ -72,7 +72,7 @@ describe("Support Functions for Unit Testing", function() {
let tags = data.itemWithTags.tags;
for (let i=0; i<tags.length; i++) {
- let tagID = yield Zotero.Tags.getID(tags[i].tag);
+ let tagID = Zotero.Tags.getID(tags[i].tag);
assert.ok(tagID, '"' + tags[i].tag + '" tag was inserted into the database');
assert.ok(zItem.hasTag(tags[i].tag), '"' + tags[i].tag + '" tag was assigned to item');
}
diff --git a/test/tests/tagSelectorTest.js b/test/tests/tagSelectorTest.js
@@ -173,7 +173,7 @@ describe("Tag Selector", function () {
/*// Remove all tags in library
var tags = yield Zotero.Tags.getAll(libraryID);
tags.forEach(function (tag) {
- var tagID = yield Zotero.Tags.getID(tag);
+ var tagID = Zotero.Tags.getID(tag);
yield Zotero.Tags.removeFromLibrary(libraryID, tagID);
});*/
diff --git a/test/tests/tagsTest.js b/test/tests/tagsTest.js
@@ -8,7 +8,7 @@ describe("Zotero.Tags", function () {
item.addTag(tagName);
yield item.saveTx();
- assert.typeOf((yield Zotero.Tags.getID(tagName)), "number");
+ assert.typeOf(Zotero.Tags.getID(tagName), "number");
})
})
@@ -20,8 +20,8 @@ describe("Zotero.Tags", function () {
yield item.saveTx();
var libraryID = Zotero.Libraries.userLibraryID;
- var tagID = yield Zotero.Tags.getID(tagName);
- assert.equal((yield Zotero.Tags.getName(tagID)), tagName);
+ var tagID = Zotero.Tags.getID(tagName);
+ assert.equal(Zotero.Tags.getName(tagID), tagName);
})
})
@@ -35,7 +35,7 @@ describe("Zotero.Tags", function () {
yield item.saveTx();
assert.lengthOf(item.getTags(), 1);
- var tagID = yield Zotero.Tags.getID(tagName);
+ var tagID = Zotero.Tags.getID(tagName);
yield Zotero.Tags.removeFromLibrary(libraryID, tagID);
assert.lengthOf(item.getTags(), 0);
})
@@ -50,18 +50,18 @@ describe("Zotero.Tags", function () {
item.addTag(tagName);
yield item.saveTx();
- var tagID = yield Zotero.Tags.getID(tagName);
+ var tagID = Zotero.Tags.getID(tagName);
assert.typeOf(tagID, "number");
yield item.eraseTx();
- assert.equal((yield Zotero.Tags.getName(tagID)), tagName);
+ assert.equal(Zotero.Tags.getName(tagID), tagName);
yield Zotero.DB.executeTransaction(function* () {
yield Zotero.Tags.purge();
});
- assert.isFalse(yield Zotero.Tags.getName(tagID));
+ assert.isFalse(Zotero.Tags.getName(tagID));
})
})
diff --git a/test/tests/tagsboxTest.js b/test/tests/tagsboxTest.js
@@ -100,9 +100,7 @@ describe("Item Tags Box", function () {
assert.equal(rows.length, 1);
assert.equal(rows[0].textContent, tag);
- yield Zotero.Tags.removeFromLibrary(
- Zotero.Libraries.userLibraryID, (yield Zotero.Tags.getID(tag))
- );
+ yield Zotero.Tags.removeFromLibrary(Zotero.Libraries.userLibraryID, Zotero.Tags.getID(tag));
var rows = tagsbox.id('tagRows').getElementsByTagName('row');
assert.equal(rows.length, 0);