From 97358aad7ac16878b0a14dcb65938ea8df310f55 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Fri, 22 Mar 2013 02:18:00 -0400 Subject: [PATCH] Asynchronous DB query methods (experimental) See comment in db.js for example usage. This requires Firefox 20 or later unless we bundle the necessary code modules ourselves. --- chrome/content/zotero/xpcom/db.js | 341 +++++++++++++++++++++++++----- install.rdf | 4 +- update.rdf | 4 +- 3 files changed, 290 insertions(+), 59 deletions(-) diff --git a/chrome/content/zotero/xpcom/db.js b/chrome/content/zotero/xpcom/db.js index 3292fd801..a1b90145f 100644 --- a/chrome/content/zotero/xpcom/db.js +++ b/chrome/content/zotero/xpcom/db.js @@ -34,6 +34,18 @@ Zotero.DBConnection = function(dbName) { throw ('DB name not provided in Zotero.DBConnection()'); } + // Code modules for async methods + // Fx21+ + try { + Components.utils.import("resource://gre/modules/commonjs/sdk/core/promise.js", this); + } + // Fx20 + catch (e) { + Components.utils.import("resource://gre/modules/commonjs/promise/core.js", this); + } + Components.utils.import("resource://gre/modules/Task.jsm", this); + Components.utils.import("resource://gre/modules/Sqlite.jsm", this); + this.skipBackup = false; this.transactionVacuum = false; @@ -67,6 +79,7 @@ Zotero.DBConnection = function(dbName) { this._dbName = dbName; this._shutdown = false; this._connection = null; + this._connectionAsync = null; this._transactionDate = null; this._lastTransactionDate = null; this._transactionRollback = null; @@ -238,61 +251,7 @@ Zotero.DBConnection.prototype.getStatement = function (sql, params, checkParams) var matches = sql.match(/^[^\s\(]*/); var queryMethod = matches[0].toLowerCase(); - if (params) { - // If single scalar value or single non-array object, wrap in an array - if (typeof params != 'object' || params === null || - (params && typeof params == 'object' && !params.length)) { - var params = [params]; - } - - // Since we might make changes, only work on a copy of the array - var params = params.concat(); - - // Replace NULL bound parameters with hard-coded NULLs - var nullRE = /\s*=?\s*\?/g; - // Reset lastIndex, since regexp isn't recompiled dynamically - nullRE.lastIndex = 0; - var lastNullParamIndex = -1; - for (var i=0; i "a" +// // '1' => "b" +// // '2' => "c" +// // '3' => "d" +// +// let rows = yield Zotero.DB.queryAsync("SELECT * FROM tmpFoo"); +// for each(let row in rows) { +// // row.foo == 'a', row.bar == 1 +// // row.foo == 'b', row.bar == 2 +// // row.foo == 'c', row.bar == 3 +// // row.foo == 'd', row.bar == 4 +// } +// +// // Optional, but necessary to pass 'rows' on to the next handler +// Zotero.DB.asyncResult(rows); +// ) +// then(function (rows) { +// // rows == same as above +// ) +// .done(); +// +/** + * @param {Function} func Task.js-style generator function that yields promises, + * generally from queryAsync() and similar + * @return {Promise} Q promise for result of generator function, which can + * pass a result by calling asyncResult(val) at the end + */ +Zotero.DBConnection.prototype.executeTransaction = function (func) { + return Q( + this._getConnectionAsync() + .then(function (conn) { + return conn.executeTransaction(func); + }) + ); +}; + + +/** + * @param {String} sql SQL statement to run + * @param {Array|String|Integer} [params] SQL parameters to bind + * @return {Promise|FALSE} A Q promise for an array of rows, or FALSE if none. + * The individual rows are Proxy objects that return + * values from the underlying mozIStorageRows based + * on column names. + */ +Zotero.DBConnection.prototype.queryAsync = function (sql, params) { + let conn; + let self = this; + return this._getConnectionAsync(). + then(function (c) { + conn = c; + [sql, params] = self.parseQueryAndParams(sql, params); + Zotero.debug(sql, 5); + return conn.executeCached(sql, params); + }) + .then(function (rows) { + // Parse out the SQL command being used + var op = sql.match(/^[^a-z]*[^ ]+/i); + if (op) { + op = op.toString().toLowerCase(); + } + + // If SELECT statement, return result + if (op == 'select') { + // Fake an associative array with a proxy + let handler = { + get: function(target, name) { + return target.getResultByName(name); + } + }; + for (let i=0, len=rows.length; i {ec8030f7-c20a-464f-9b0e-13a3a9e97384} - 17.0 - 21.* + 20.0 + 22.* diff --git a/update.rdf b/update.rdf index f9213eb36..240e41df1 100644 --- a/update.rdf +++ b/update.rdf @@ -11,8 +11,8 @@ {ec8030f7-c20a-464f-9b0e-13a3a9e97384} - 17.0 - 21.* + 20.0 + 22.* http://download.zotero.org/extension/zotero.xpi sha1: