Mercurial > snowl
view extension/modules/collection.js @ 82:2c1612f4cb28
Fix SQL syntax error when read = 1
author | Myk Melez <myk@mozilla.org> |
---|---|
date | Thu, 15 May 2008 18:46:06 -0700 |
parents | 877a7694445f |
children | f5161c834622 |
line wrap: on
line source
const EXPORTED_SYMBOLS = ["SnowlCollection"]; const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; const Cu = Components.utils; Cu.import("resource://snowl/modules/log4moz.js"); Cu.import("resource://snowl/modules/datastore.js"); Cu.import("resource://snowl/modules/message.js"); /** * A group of messages. */ function SnowlCollection(aSourceID, aFilter, aCurrent, aRead) { this._sourceID = aSourceID; this._filter = aFilter; this._current = aCurrent; this._read = aRead; } SnowlCollection.prototype = { get _log() { let log = Log4Moz.Service.getLogger("Snowl.Collection"); this.__defineGetter__("_log", function() { return log }); return this._log; }, _sourceID: null, get sourceID() { return this._sourceID; }, set sourceID(newVal) { if (this._sourceID == newVal) return; this._sourceID = newVal; this.invalidate(); }, _filter: null, get filter() { return this._filter; }, set filter(newVal) { if (this._filter == newVal) return; this._filter = newVal; this.invalidate(); }, _current: undefined, _read: undefined, get read() { return this._read; }, set read(newValue) { if (this._read === newValue) return; this._read = (typeof newValue == "undefined") ? undefined : newValue ? true : false; // Invalidate the message cache. this._messages = null; }, sortProperty: "timestamp", sortOrder: 1, _messages: null, get messages() { if (this._messages) return this._messages; this._messages = []; this._messageIndex = {}; let statement = this._generateStatement(); try { while (statement.step()) { let message = new SnowlMessage(statement.row.id, statement.row.subject, statement.row.author, statement.row.link, statement.row.timestamp, (statement.row.read ? true : false)); this._messages.push(message); this._messageIndex[message.id] = message; } } finally { statement.reset(); } this.sort(this.sortProperty, this.sortOrder); // A bug in SQLite breaks relating a virtual table via a LEFT JOIN, so we // can't pull content with our initial query. Instead we do it here. // FIXME: stop doing this once we upgrade to a version of SQLite that does // not have this problem (i.e. 3.5.6+). this._getContent(); this._log.info("Retrieved " + this._messages.length + " messages."); return this._messages; }, invalidate: function() { this._messages = null; }, _getContent: function() { let query = "SELECT messageID, content, contentType " + "FROM parts " + "WHERE parts.messageID IN (" + this._messages.map(function(v) { return v.id }).join(",") + ")"; let statement = SnowlDatastore.createStatement(query); try { while (statement.step()) { let content = Cc["@mozilla.org/feed-textconstruct;1"]. createInstance(Ci.nsIFeedTextConstruct); content.text = statement.row.content; content.type = textConstructTypes[statement.row.contentType]; this._messageIndex[statement.row.messageID].content = content; } } finally { statement.reset(); } }, _generateStatement: function() { let query = //"SELECT subject, author, link, timestamp, content \ // FROM sources JOIN messages ON sources.id = messages.sourceID \ // LEFT JOIN parts on messages.id = parts.messageID"; "SELECT messages.id, subject, author, link, timestamp, read " + "FROM sources JOIN messages ON sources.id = messages.sourceID"; let conditions = []; if (this.sourceID) conditions.push("messages.sourceID = :sourceID"); // FIXME: use a left join here once the SQLite bug breaking left joins to // virtual tables has been fixed (i.e. after we upgrade to SQLite 3.5.7+). if (this.filter) conditions.push("messages.id IN (SELECT messageID FROM parts WHERE content MATCH :filter)"); if (typeof this._current != "undefined") conditions.push("current = " + (this._current ? "1" : "0")); if (typeof this.read != "undefined") conditions.push("(read = " + (this.read ? "1" : "0 OR read IS NULL") + ")"); if (conditions.length > 0) query += " WHERE " + conditions.join(" AND "); this._log.info(query); let statement = SnowlDatastore.createStatement(query); if (this.sourceID) statement.params.sourceID = this.sourceID; if (this.filter) statement.params.filter = this.filter; return statement; }, sort: function(aProperty, aOrder) { this.sortProperty = aProperty; this.sortOrder = aOrder; let compare = function(a, b) { if (prepareObjectForComparison(a[aProperty]) > prepareObjectForComparison(b[aProperty])) return 1 * aOrder; if (prepareObjectForComparison(a[aProperty]) < prepareObjectForComparison(b[aProperty])) return -1 * aOrder; // Fall back on the "subject" aProperty. if (aProperty != "subject") { if (prepareObjectForComparison(a.subject) > prepareObjectForComparison(b.subject)) return 1 * aOrder; if (prepareObjectForComparison(a.subject) < prepareObjectForComparison(b.subject)) return -1 * aOrder; } // Return an inconclusive result. return 0; }; this._messages.sort(compare); } } function prepareObjectForComparison(aObject) { if (typeof aObject == "string") return aObject.toLowerCase(); // Null values are neither greater than nor less than strings, so we // convert them into empty strings, which is how they appear to users. if (aObject == null) return ""; return aObject; } // FIXME: get this from message.js (or from something that both message.js and collection.js import). let textConstructTypes = { "text/html": "html", "application/xhtml+xml": "xhtml", "text/plain": "text" };