- Fixed tag selector still displaying all tags for collections and saved searches

- Added asTempTable parameter to Zotero.Search.search() to save results to a temporary table -- avoids large inserts with post-search filters
- Added proper collation sort support for tags
This commit is contained in:
Dan Stillman 2007-04-16 22:06:49 +00:00
parent a61afc89cc
commit fe31d4c789
4 changed files with 127 additions and 90 deletions

View File

@ -1780,9 +1780,18 @@ Zotero.Item.prototype.getTags = function(){
return false; return false;
} }
var sql = "SELECT tagID AS id, tag, tagType AS type FROM tags WHERE tagID IN " var sql = "SELECT tagID AS id, tag, tagType AS type FROM tags WHERE tagID IN "
+ "(SELECT tagID FROM itemTags WHERE itemID=" + this.getID() + ") " + "(SELECT tagID FROM itemTags WHERE itemID=" + this.getID() + ")";
+ "ORDER BY tag COLLATE NOCASE";
return Zotero.DB.query(sql); var tags = Zotero.DB.query(sql);
if (!tags) {
return false;
}
var collation = Zotero.getLocaleCollation();
tags.sort(function(a, b) {
return collation.compareString(0, a.tag, b.tag);
});
return tags;
} }
Zotero.Item.prototype.getTagIDs = function(){ Zotero.Item.prototype.getTagIDs = function(){
@ -3635,13 +3644,21 @@ Zotero.Tags = new function(){
if (types) { if (types) {
sql += "WHERE tagType IN (" + types.join() + ") "; sql += "WHERE tagType IN (" + types.join() + ") ";
} }
sql += "ORDER BY tag COLLATE NOCASE";
var tags = Zotero.DB.query(sql); var tags = Zotero.DB.query(sql);
if (!tags) {
return {};
}
var collation = Zotero.getLocaleCollation();
tags.sort(function(a, b) {
return collation.compareString(0, a.tag, b.tag);
});
var indexed = {}; var indexed = {};
for each(var tag in tags) { for (var i=0; i<tags.length; i++) {
indexed[tag.tagID] = { indexed[tags[i].tagID] = {
tag: tag.tag, tag: tags[i].tag,
type: tag.tagType type: tags[i].tagType
}; };
} }
return indexed; return indexed;
@ -3654,49 +3671,36 @@ Zotero.Tags = new function(){
* _types_ is an optional array of tagTypes to fetch * _types_ is an optional array of tagTypes to fetch
*/ */
function getAllWithinSearch(search, types) { function getAllWithinSearch(search, types) {
// If search has post-search filters (e.g. fulltext content), run it // Save search results to temporary table
// and just include the ids var tmpTable = search.search(true);
// if (!tmpTable) {
// DEBUG: it's possible there's a query length limit here return {};
// or that this slows things down with large libraries
// -- should probably use a temporary table instead
if (search.hasPostSearchFilter()) {
var ids = search.search();
var sql = "SELECT DISTINCT tagID, tag, tagType FROM itemTags "
+ "NATURAL JOIN tags WHERE itemID IN (" + ids.join() + ") ";
if (types) {
sql += "AND tagType IN (" + types.join() + ") ";
}
sql += "ORDER BY tag COLLATE NOCASE";
var tags = Zotero.DB.query(sql);
} }
else {
var sql = "CREATE TEMPORARY TABLE tmpSearchResults AS " + search.getSQL();
Zotero.DB.query(sql, search.getSQLParams());
sql = "CREATE INDEX tmpSearchResults_itemID ON tmpSearchResults(itemID)";
Zotero.DB.query(sql);
var sql = "SELECT DISTINCT tagID, tag, tagType FROM itemTags " var sql = "SELECT DISTINCT tagID, tag, tagType FROM itemTags "
+ "NATURAL JOIN tags WHERE (" + "NATURAL JOIN tags WHERE itemID IN "
+ "itemID IN (SELECT itemID FROM tmpSearchResults) OR " + "(SELECT itemID FROM " + tmpTable + ") ";
+ "itemID IN (SELECT itemID FROM itemNotes WHERE sourceItemID IN (SELECT itemID FROM tmpSearchResults)) OR " if (types) {
+ "itemID IN (SELECT itemID FROM itemAttachments WHERE sourceItemID IN (SELECT itemID FROM tmpSearchResults))" sql += "AND tagType IN (" + types.join() + ") ";
+ ") ";
if (types) {
sql += "AND tagType IN (" + types.join() + ") ";
}
sql += "ORDER BY tag COLLATE NOCASE";
var tags = Zotero.DB.query(sql);
sql = "DROP TABLE tmpSearchResults";
Zotero.DB.query(sql);
} }
var tags = Zotero.DB.query(sql);
Zotero.DB.query("DROP TABLE " + tmpTable);
if (!tags) {
return {};
}
var collation = Zotero.getLocaleCollation();
tags.sort(function(a, b) {
return collation.compareString(0, a.tag, b.tag);
});
var indexed = {}; var indexed = {};
for each(var tag in tags) { for (var i=0; i<tags.length; i++) {
indexed[tag.tagID] = { indexed[tags[i].tagID] = {
tag: tag.tag, tag: tags[i].tag,
type: tag.tagType type: tags[i].tagType
}; };
} }
return indexed; return indexed;
@ -4558,11 +4562,7 @@ Zotero.getCollections = function(parent, recursive){
} }
// Do proper collation sort // Do proper collation sort
var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"] var collation = Zotero.getLocaleCollation();
.getService(Components.interfaces.nsILocaleService);
var collationFactory = Components.classes["@mozilla.org/intl/collation-factory;1"]
.getService(Components.interfaces.nsICollationFactory);
var collation = collationFactory.CreateCollation(localeService.getApplicationLocale());
children.sort(function (a, b) { children.sort(function (a, b) {
return collation.compareString(0, a.name, b.name); return collation.compareString(0, a.name, b.name);
}); });

View File

@ -718,11 +718,7 @@ Zotero.ItemTreeView.prototype.sort = function(itemID)
var columnField = this.getSortField(); var columnField = this.getSortField();
var order = this.getSortDirection() == 'ascending'; var order = this.getSortDirection() == 'ascending';
var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"] var collation = Zotero.getLocaleCollation();
.getService(Components.interfaces.nsILocaleService);
var collationFactory = Components.classes["@mozilla.org/intl/collation-factory;1"]
.getService(Components.interfaces.nsICollationFactory);
var collation = collationFactory.CreateCollation(localeService.getApplicationLocale());
// Year is really the date field truncated // Year is really the date field truncated
if (columnField == 'year') { if (columnField == 'year') {

View File

@ -318,7 +318,7 @@ Zotero.Search.prototype.hasPostSearchFilter = function() {
/* /*
* Run the search and return an array of item ids for results * Run the search and return an array of item ids for results
*/ */
Zotero.Search.prototype.search = function(){ Zotero.Search.prototype.search = function(asTempTable){
if (!this._sql){ if (!this._sql){
this._buildQuery(); this._buildQuery();
} }
@ -331,49 +331,47 @@ Zotero.Search.prototype.search = function(){
return false; return false;
} }
Zotero.DB.query("DROP TABLE IF EXISTS tmpSearchResults"); var tmpTable = this._idsToTempTable(ids);
var sql = "CREATE TEMPORARY TABLE tmpSearchResults (itemID INT)";
Zotero.DB.query(sql);
var sql = "INSERT INTO tmpSearchResults VALUES (?)";
var insertStatement = Zotero.DB.getStatement(sql);
for (var i=0; i<ids.length; i++) {
insertStatement.bindInt32Parameter(1, ids[i]);
try {
insertStatement.execute();
}
catch (e) {
throw (Zotero.DB.getLastErrorString());
}
}
insertStatement.reset();
} }
// Otherwise, just copy to temp table directly // Otherwise, just copy to temp table directly
else { else {
var sql = "CREATE TEMPORARY TABLE tmpSearchResults AS " var tmpTable = "tmpSearchResults_" + Zotero.randomString(8);
var sql = "CREATE TEMPORARY TABLE " + tmpTable + " AS "
+ this._scope.getSQL(); + this._scope.getSQL();
Zotero.DB.query(sql, this._scope.getSQLParams()); Zotero.DB.query(sql, this._scope.getSQLParams());
var sql = "CREATE INDEX " + tmpTable + "_itemID ON " + tmpTable + "(itemID)";
Zotero.DB.query(sql);
} }
var sql = "CREATE INDEX tmpSearchResults_itemID ON tmpSearchResults(itemID)"; // Search ids in temp table and their child items
Zotero.DB.query(sql);
var sql = "SELECT itemID FROM items WHERE itemID IN (" + this._sql + ") " var sql = "SELECT itemID FROM items WHERE itemID IN (" + this._sql + ") "
+ "AND (" + "AND ("
+ "itemID IN (SELECT itemID FROM tmpSearchResults) OR " + "itemID IN (SELECT itemID FROM " + tmpTable + ") OR "
+ "itemID IN (SELECT itemID FROM itemAttachments" + "itemID IN (SELECT itemID FROM itemAttachments"
+ " WHERE sourceItemID IN (SELECT itemID FROM tmpSearchResults)) OR " + " WHERE sourceItemID IN (SELECT itemID FROM " + tmpTable + ")) OR "
+ "itemID IN (SELECT itemID FROM itemNotes" + "itemID IN (SELECT itemID FROM itemNotes"
+ " WHERE sourceItemID IN (SELECT itemID FROM tmpSearchResults))" + " WHERE sourceItemID IN (SELECT itemID FROM " + tmpTable + "))"
+ ")"; + ")";
var ids = Zotero.DB.columnQuery(sql, this._sqlParams);
Zotero.DB.query("DROP TABLE tmpSearchResults"); if (asTempTable) {
var tmpTable2 = "tmpSearchResults_" + Zotero.randomString(8);
sql = "CREATE TEMPORARY TABLE " + tmpTable2 + " AS " + sql;
Zotero.DB.query(sql, this._sqlParams);
return tmpTable2;
}
else {
var ids = Zotero.DB.columnQuery(sql, this._sqlParams);
Zotero.DB.query("DROP TABLE " + tmpTable);
return ids;
}
} }
else {
var ids = Zotero.DB.columnQuery(this._sql, this._sqlParams); if (this._scope) {
throw ("Fulltext content search with custom scope not currently supported in Zotero.Search.search()");
} }
var ids = Zotero.DB.columnQuery(this._sql, this._sqlParams);
//Zotero.debug('IDs from main search: '); //Zotero.debug('IDs from main search: ');
//Zotero.debug(ids); //Zotero.debug(ids);
@ -406,10 +404,6 @@ Zotero.Search.prototype.search = function(){
// (a separate fulltext word search filtered by fulltext content) // (a separate fulltext word search filtered by fulltext content)
for each(var condition in this._conditions){ for each(var condition in this._conditions){
if (condition['condition']=='fulltextContent'){ if (condition['condition']=='fulltextContent'){
if (this._scope) {
throw ("Cannot perform fulltext content search with custom scope in Zotero.Search.search()");
}
//Zotero.debug('Running subsearch against fulltext word index'); //Zotero.debug('Running subsearch against fulltext word index');
// Run a new search against the fulltext word index // Run a new search against the fulltext word index
@ -500,6 +494,15 @@ Zotero.Search.prototype.search = function(){
//Zotero.debug('Final result set'); //Zotero.debug('Final result set');
//Zotero.debug(ids); //Zotero.debug(ids);
if (asTempTable) {
var ids = this._scope.search();
if (!ids) {
return false;
}
return this._idsToTempTable(ids);
}
return ids; return ids;
} }
@ -523,6 +526,34 @@ Zotero.Search.prototype.getSQLParams = function(){
} }
/*
* Batch insert
*/
Zotero.Search.prototype._idsToTempTable = function (ids) {
var tmpTable = "tmpSearchResults_" + Zotero.randomString(8);
var sql = "CREATE TEMPORARY TABLE " + tmpTable + " (itemID INT)";
Zotero.DB.query(sql);
var sql = "INSERT INTO " + tmpTable + " VALUES (?)";
var insertStatement = Zotero.DB.getStatement(sql);
for (var i=0; i<ids.length; i++) {
insertStatement.bindInt32Parameter(1, ids[i]);
try {
insertStatement.execute();
}
catch (e) {
throw (Zotero.DB.getLastErrorString());
}
}
insertStatement.reset();
var sql = "CREATE INDEX " + tmpTable + "_itemID ON " + tmpTable + "(itemID)";
Zotero.DB.query(sql);
return tmpTable;
}
/* /*
* Build the SQL query for the search * Build the SQL query for the search
*/ */

View File

@ -47,6 +47,7 @@ var Zotero = new function(){
this.varDump = varDump; this.varDump = varDump;
this.safeDebug = safeDebug; this.safeDebug = safeDebug;
this.getString = getString; this.getString = getString;
this.getLocaleCollation = getLocaleCollation;
this.setFontSize = setFontSize; this.setFontSize = setFontSize;
this.flattenArguments = flattenArguments; this.flattenArguments = flattenArguments;
this.getAncestorByTagName = getAncestorByTagName; this.getAncestorByTagName = getAncestorByTagName;
@ -569,6 +570,15 @@ var Zotero = new function(){
} }
function getLocaleCollation() {
var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
.getService(Components.interfaces.nsILocaleService);
var collationFactory = Components.classes["@mozilla.org/intl/collation-factory;1"]
.getService(Components.interfaces.nsICollationFactory);
return collation = collationFactory.CreateCollation(localeService.getApplicationLocale());
}
/* /*
* Sets font size based on prefs -- intended for use on root element * Sets font size based on prefs -- intended for use on root element
* (zotero-pane, note window, etc.) * (zotero-pane, note window, etc.)