www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

searches.js (6042B)


      1 /*
      2     ***** BEGIN LICENSE BLOCK *****
      3     
      4     Copyright © 2006-2016 Center for History and New Media
      5                           George Mason University, Fairfax, Virginia, USA
      6                           https://zotero.org
      7     
      8     This file is part of Zotero.
      9     
     10     Zotero is free software: you can redistribute it and/or modify
     11     it under the terms of the GNU Affero General Public License as published by
     12     the Free Software Foundation, either version 3 of the License, or
     13     (at your option) any later version.
     14     
     15     Zotero is distributed in the hope that it will be useful,
     16     but WITHOUT ANY WARRANTY; without even the implied warranty of
     17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18     GNU Affero General Public License for more details.
     19     
     20     You should have received a copy of the GNU Affero General Public License
     21     along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
     22     
     23     ***** END LICENSE BLOCK *****
     24 */
     25 
     26 Zotero.Searches = function() {
     27 	this.constructor = null;
     28 	
     29 	this._ZDO_object = 'search';
     30 	this._ZDO_id = 'savedSearchID';
     31 	this._ZDO_table = 'savedSearches';
     32 	
     33 	this._primaryDataSQLParts = {
     34 		savedSearchID: "O.savedSearchID",
     35 		name: "O.savedSearchName AS name",
     36 		libraryID: "O.libraryID",
     37 		key: "O.key",
     38 		version: "O.version",
     39 		synced: "O.synced"
     40 	}
     41 	
     42 	this._primaryDataSQLFrom = "FROM savedSearches O";
     43 	
     44 	this.init = Zotero.Promise.coroutine(function* () {
     45 		yield Zotero.DataObjects.prototype.init.apply(this);
     46 		yield Zotero.SearchConditions.init();
     47 	});
     48 	
     49 	
     50 	this.getByLibrary = function (libraryID) {
     51 		var searches = [];
     52 		for (let id in this._objectCache) {
     53 			let s = this._objectCache[id];
     54 			if (s.libraryID == libraryID) {
     55 				searches.push(s);
     56 			}
     57 		}
     58 		
     59 		// Do proper collation sort
     60 		var collation = Zotero.getLocaleCollation();
     61 		searches.sort(function (a, b) {
     62 			return collation.compareString(1, a.name, b.name);
     63 		});
     64 		return searches;
     65 	};
     66 	
     67 	
     68 	/**
     69 	 * Returns an array of Zotero.Search objects, ordered by name
     70 	 *
     71 	 * @param	{Integer}	[libraryID]
     72 	 */
     73 	this.getAll = Zotero.Promise.coroutine(function* (libraryID) {
     74 		var sql = "SELECT savedSearchID FROM savedSearches WHERE libraryID=?";
     75 		var ids = yield Zotero.DB.columnQueryAsync(sql, libraryID);
     76 		if (!ids.length) {
     77 			return []
     78 		}
     79 		
     80 		var searches = this.get(ids);
     81 		// Do proper collation sort
     82 		var collation = Zotero.getLocaleCollation();
     83 		searches.sort(function (a, b) {
     84 			return collation.compareString(1, a.name, b.name);
     85 		});
     86 		return searches;
     87 	});
     88 	
     89 	
     90 	this.getPrimaryDataSQL = function () {
     91 		// This should be the same as the query in Zotero.Search.loadPrimaryData(),
     92 		// just without a specific savedSearchID
     93 		return "SELECT "
     94 			+ Object.keys(this._primaryDataSQLParts).map(key => this._primaryDataSQLParts[key]).join(", ") + " "
     95 			+ "FROM savedSearches O WHERE 1";
     96 	}
     97 	
     98 	
     99 	this.conditionEquals = function (data1, data2) {
    100 		return data1.condition === data2.condition
    101 			&& data1.operator === data2.operator
    102 			&& data1.value === data2.value;
    103 	},
    104 	
    105 	
    106 	this._loadConditions = Zotero.Promise.coroutine(function* (libraryID, ids, idSQL) {
    107 		var sql = "SELECT savedSearchID, searchConditionID, condition, operator, value, required "
    108 			+ "FROM savedSearches LEFT JOIN savedSearchConditions USING (savedSearchID) "
    109 			+ "WHERE libraryID=?" + idSQL
    110 			+ "ORDER BY savedSearchID, searchConditionID";
    111 		var params = [libraryID];
    112 		var lastID = null;
    113 		var rows = [];
    114 		var setRows = function (searchID, rows) {
    115 			var search = this._objectCache[searchID];
    116 			if (!search) {
    117 				throw new Error("Search " + searchID + " not found");
    118 			}
    119 			
    120 			search._conditions = {};
    121 			
    122 			if (rows.length) {
    123 				search._maxSearchConditionID = rows[rows.length - 1].searchConditionID;
    124 			}
    125 			
    126 			// Reindex conditions, in case they're not contiguous in the DB
    127 			for (let i = 0; i < rows.length; i++) {
    128 				let condition = rows[i];
    129 				
    130 				// Parse "condition[/mode]"
    131 				let [conditionName, mode] = Zotero.SearchConditions.parseCondition(condition.condition);
    132 				
    133 				// Not sure how this can happen, but prevent an error if it does
    134 				if (condition.value === null) {
    135 					condition.value = '';
    136 				}
    137 				
    138 				let cond = Zotero.SearchConditions.get(conditionName);
    139 				if (!cond || cond.noLoad) {
    140 					Zotero.debug("Invalid saved search condition '" + conditionName + "' -- skipping", 2);
    141 					continue;
    142 				}
    143 				
    144 				// Convert itemTypeID to itemType
    145 				//
    146 				// TEMP: This can be removed at some point
    147 				if (conditionName == 'itemTypeID') {
    148 					conditionName = 'itemType';
    149 					condition.value = Zotero.ItemTypes.getName(condition.value);
    150 				}
    151 				// Parse old-style collection/savedSearch conditions ('0_ABCD2345' -> 'ABCD2345')
    152 				else if (conditionName == 'collection' || conditionName == 'savedSearch') {
    153 					if (condition.value.includes('_')) {
    154 						let [_, objKey] = condition.value.split('_');
    155 						condition.value = objKey;
    156 					}
    157 				}
    158 				
    159 				search._conditions[i] = {
    160 					id: i,
    161 					condition: conditionName,
    162 					mode: mode,
    163 					operator: condition.operator,
    164 					value: condition.value,
    165 					required: !!condition.required
    166 				};
    167 			}
    168 			search._loaded.conditions = true;
    169 			search._clearChanged('conditions');
    170 		}.bind(this);
    171 		
    172 		yield Zotero.DB.queryAsync(
    173 			sql,
    174 			params,
    175 			{
    176 				noCache: ids.length != 1,
    177 				onRow: function (row) {
    178 					let searchID = row.getResultByIndex(0);
    179 					
    180 					if (lastID && searchID != lastID) {
    181 						setRows(lastID, rows);
    182 						rows = [];
    183 					}
    184 					
    185 					lastID = searchID;
    186 					let searchConditionID = row.getResultByIndex(1);
    187 					// No conditions
    188 					if (searchConditionID === null) {
    189 						return;
    190 					}
    191 					rows.push({
    192 						searchConditionID,
    193 						condition: row.getResultByIndex(2),
    194 						operator: row.getResultByIndex(3),
    195 						value: row.getResultByIndex(4),
    196 						required: row.getResultByIndex(5)
    197 					});
    198 				}.bind(this)
    199 			}
    200 		);
    201 		if (lastID) {
    202 			setRows(lastID, rows);
    203 		}
    204 	});
    205 	
    206 	Zotero.DataObjects.call(this);
    207 	
    208 	return this;
    209 }.bind(Object.create(Zotero.DataObjects.prototype))();