Deasyncify Zotero.Tags.getID()/getAsync(), and add Zotero.Tags.create()

This commit is contained in:
Dan Stillman 2016-04-21 11:07:16 -04:00
parent bf416e56c2
commit e2cbfbd0fe
8 changed files with 90 additions and 32 deletions

View file

@ -669,7 +669,7 @@
this.selection.delete(oldName); this.selection.delete(oldName);
} }
if (yield Zotero.Tags.getID(oldName)) { if (Zotero.Tags.getID(oldName)) {
yield Zotero.Tags.rename(this.libraryID, oldName, newName.value); yield Zotero.Tags.rename(this.libraryID, oldName, newName.value);
} }
// Colored tags don't need to exist, so in that case // Colored tags don't need to exist, so in that case
@ -707,7 +707,7 @@
return; return;
} }
var tagID = yield Zotero.Tags.getID(name); var tagID = Zotero.Tags.getID(name);
if (tagID) { if (tagID) {
yield Zotero.Tags.removeFromLibrary(this.libraryID, tagID); yield Zotero.Tags.removeFromLibrary(this.libraryID, tagID);
} }

View file

@ -1621,7 +1621,7 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
for (let i=0; i<toAdd.length; i++) { for (let i=0; i<toAdd.length; i++) {
let tag = toAdd[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; let tagType = tag.type ? tag.type : 0;
// "OR REPLACE" allows changing type // "OR REPLACE" allows changing type
let sql = "INSERT OR REPLACE INTO itemTags (itemID, tagID, type) VALUES (?, ?, ?)"; 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) { if (toRemove.length) {
for (let i=0; i<toRemove.length; i++) { for (let i=0; i<toRemove.length; i++) {
let tag = toRemove[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=?"; let sql = "DELETE FROM itemTags WHERE itemID=? AND tagID=? AND type=?";
yield Zotero.DB.queryAsync(sql, [this.id, tagID, tag.type ? tag.type : 0]); yield Zotero.DB.queryAsync(sql, [this.id, tagID, tag.type ? tag.type : 0]);
let notifierData = {}; let notifierData = {};
@ -3319,6 +3319,8 @@ Zotero.Item.prototype.addTag = function (name, type) {
/** /**
* Replace an existing tag with a new manual tag * Replace an existing tag with a new manual tag
* *
* A separate save() is required to update the database.
*
* @param {String} oldTag * @param {String} oldTag
* @param {String} newTag * @param {String} newTag
*/ */
@ -3358,13 +3360,11 @@ Zotero.Item.prototype.replaceTag = function (oldTag, newTag) {
*/ */
Zotero.Item.prototype.removeTag = function(tagName) { Zotero.Item.prototype.removeTag = function(tagName) {
this._requireData('tags'); this._requireData('tags');
Zotero.debug(this._tags);
var newTags = this._tags.filter(function (tagData) tagData.tag !== tagName); var newTags = this._tags.filter(function (tagData) tagData.tag !== tagName);
if (newTags.length == this._tags.length) { if (newTags.length == this._tags.length) {
Zotero.debug('Cannot remove missing tag ' + tagName + ' from item ' + this.libraryKey); Zotero.debug('Cannot remove missing tag ' + tagName + ' from item ' + this.libraryKey);
return; return;
} }
Zotero.debug(newTags);
this.setTags(newTags); this.setTags(newTags);
} }

View file

@ -30,12 +30,32 @@
Zotero.Tags = new function() { Zotero.Tags = new function() {
this.MAX_COLORED_TAGS = 6; this.MAX_COLORED_TAGS = 6;
var _initialized = false;
var _tagsByID = new Map();
var _idsByTag = new Map();
var _libraryColors = {}; var _libraryColors = {};
var _libraryColorsByName = {}; var _libraryColorsByName = {};
var _itemsListImagePromises = {}; var _itemsListImagePromises = {};
var _itemsListExtraImagePromises = {}; 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 * 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 * @return {Promise<String|false>} - A tag name, or false if tag with id not found
*/ */
this.getName = function (tagID) { 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 * @param {String} name - Tag data in API JSON format
* @param {Boolean} [create=false] - If no matching tag, create one; * @return {Integer} tagID
* requires a wrapping transaction
* @return {Promise<Integer>} tagID
*/ */
this.getID = Zotero.Promise.coroutine(function* (name, create) { this.getID = function (name) {
if (create) { if (!_initialized) {
Zotero.DB.requireTransaction(); 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({ data = this.cleanData({
tag: name tag: name
}); });
var sql = "SELECT tagID FROM tags WHERE name=?"; var id = _idsByTag.get(data.tag);
var id = yield Zotero.DB.valueQueryAsync(sql, data.tag); return id !== undefined ? id : false;
if (!id && create) { };
/**
* 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
* @return {Promise<Integer>} tagID
*/
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 id = this.getID(data.tag);
if (!id) {
id = Zotero.ID.get('tags'); id = Zotero.ID.get('tags');
let sql = "INSERT INTO tags (tagID, name) VALUES (?, ?)"; let sql = "INSERT INTO tags (tagID, name) VALUES (?, ?)";
yield Zotero.DB.queryAsync(sql, [id, data.tag]); yield Zotero.DB.queryAsync(sql, [id, data.tag]);
_tagsByID.set(id, data.tag);
_idsByTag.set(data.tag, id);
} }
return id; return id;
}); });
@ -252,7 +302,7 @@ Zotero.Tags = new function() {
var notifierData = {}; var notifierData = {};
for (let i=0; i<tagIDs.length; i++) { for (let i=0; i<tagIDs.length; i++) {
let tagID = tagIDs[i]; let tagID = tagIDs[i];
let name = yield this.getName(tagID); let name = this.getName(tagID);
if (name === false) { if (name === false) {
continue; continue;
} }
@ -314,11 +364,14 @@ Zotero.Tags = new function() {
/** /**
* Delete obsolete tags from database * Delete obsolete tags from database
* *
* @param {Number} libraryID
* @param {Number|Number[]} [tagIDs] - tagID or array of tagIDs to purge * @param {Number|Number[]} [tagIDs] - tagID or array of tagIDs to purge
* @return {Promise} * @return {Promise}
*/ */
this.purge = Zotero.Promise.coroutine(function* (tagIDs) { 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')) { if (!tagIDs && !Zotero.Prefs.get('purge.tags')) {
return; return;
} }
@ -363,6 +416,12 @@ Zotero.Tags = new function() {
notifierData = {}; notifierData = {};
for (let i=0; i<toDelete.length; i++) { for (let i=0; i<toDelete.length; i++) {
let row = toDelete[i]; let row = toDelete[i];
Zotero.DB.addCurrentCallback('commit', () => {
_tagsByID.delete(row.id);
_idsByTag.delete(row.name);
});
ids.push(row.id); ids.push(row.id);
notifierData[row.id] = { notifierData[row.id] = {
old: { old: {

View file

@ -625,6 +625,7 @@ Components.utils.import("resource://gre/modules/osfile.jsm");
yield Zotero.Collections.init(); yield Zotero.Collections.init();
yield Zotero.Items.init(); yield Zotero.Items.init();
yield Zotero.Searches.init(); yield Zotero.Searches.init();
yield Zotero.Tags.init();
yield Zotero.Creators.init(); yield Zotero.Creators.init();
yield Zotero.Groups.init(); yield Zotero.Groups.init();
yield Zotero.Relations.init(); yield Zotero.Relations.init();

View file

@ -72,7 +72,7 @@ describe("Support Functions for Unit Testing", function() {
let tags = data.itemWithTags.tags; let tags = data.itemWithTags.tags;
for (let i=0; i<tags.length; i++) { 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(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'); assert.ok(zItem.hasTag(tags[i].tag), '"' + tags[i].tag + '" tag was assigned to item');
} }

View file

@ -173,7 +173,7 @@ describe("Tag Selector", function () {
/*// Remove all tags in library /*// Remove all tags in library
var tags = yield Zotero.Tags.getAll(libraryID); var tags = yield Zotero.Tags.getAll(libraryID);
tags.forEach(function (tag) { tags.forEach(function (tag) {
var tagID = yield Zotero.Tags.getID(tag); var tagID = Zotero.Tags.getID(tag);
yield Zotero.Tags.removeFromLibrary(libraryID, tagID); yield Zotero.Tags.removeFromLibrary(libraryID, tagID);
});*/ });*/

View file

@ -8,7 +8,7 @@ describe("Zotero.Tags", function () {
item.addTag(tagName); item.addTag(tagName);
yield item.saveTx(); 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(); yield item.saveTx();
var libraryID = Zotero.Libraries.userLibraryID; var libraryID = Zotero.Libraries.userLibraryID;
var tagID = yield Zotero.Tags.getID(tagName); var tagID = Zotero.Tags.getID(tagName);
assert.equal((yield Zotero.Tags.getName(tagID)), tagName); assert.equal(Zotero.Tags.getName(tagID), tagName);
}) })
}) })
@ -35,7 +35,7 @@ describe("Zotero.Tags", function () {
yield item.saveTx(); yield item.saveTx();
assert.lengthOf(item.getTags(), 1); assert.lengthOf(item.getTags(), 1);
var tagID = yield Zotero.Tags.getID(tagName); var tagID = Zotero.Tags.getID(tagName);
yield Zotero.Tags.removeFromLibrary(libraryID, tagID); yield Zotero.Tags.removeFromLibrary(libraryID, tagID);
assert.lengthOf(item.getTags(), 0); assert.lengthOf(item.getTags(), 0);
}) })
@ -50,18 +50,18 @@ describe("Zotero.Tags", function () {
item.addTag(tagName); item.addTag(tagName);
yield item.saveTx(); yield item.saveTx();
var tagID = yield Zotero.Tags.getID(tagName); var tagID = Zotero.Tags.getID(tagName);
assert.typeOf(tagID, "number"); assert.typeOf(tagID, "number");
yield item.eraseTx(); 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.DB.executeTransaction(function* () {
yield Zotero.Tags.purge(); yield Zotero.Tags.purge();
}); });
assert.isFalse(yield Zotero.Tags.getName(tagID)); assert.isFalse(Zotero.Tags.getName(tagID));
}) })
}) })

View file

@ -100,9 +100,7 @@ describe("Item Tags Box", function () {
assert.equal(rows.length, 1); assert.equal(rows.length, 1);
assert.equal(rows[0].textContent, tag); assert.equal(rows[0].textContent, tag);
yield Zotero.Tags.removeFromLibrary( yield Zotero.Tags.removeFromLibrary(Zotero.Libraries.userLibraryID, Zotero.Tags.getID(tag));
Zotero.Libraries.userLibraryID, (yield Zotero.Tags.getID(tag))
);
var rows = tagsbox.id('tagRows').getElementsByTagName('row'); var rows = tagsbox.id('tagRows').getElementsByTagName('row');
assert.equal(rows.length, 0); assert.equal(rows.length, 0);