switching to when.js for promises

This commit is contained in:
Tim Griesser 2013-05-08 20:16:39 -04:00
parent 374fbf527d
commit a9faa909e3
19 changed files with 116 additions and 124 deletions

View File

@ -1,4 +1,5 @@
var Q = require('q');
var When = require('when');
var nodefn = require('when/node/function');
var _ = require('underscore');
// Setup is called with the context of the current client.
@ -45,30 +46,30 @@ exports.protoProps = {
// Retrieves a connection from the connection pool,
// returning a promise.
getConnection: function() {
return Q.ninvoke(this.pool, 'acquire');
return nodefn.call(this.pool.acquire);
},
// Releases a connection from the connection pool,
// returning a promise.
releaseConnection: function(conn) {
return Q.ninvoke(this.pool, 'release', conn);
return nodefn.call(this.pool.release, conn);
},
// Begins a transaction statement on the instance,
// resolving with the connection of the current transaction.
startTransaction: function() {
return this.getConnection().then(function(connection) {
return Q.ninvoke(connection, 'query', 'begin;', []).then(function() {
return nodefn.call(connection.query, 'begin;', []).then(function() {
return connection;
});
});
},
finishTransaction: function(type, trans, dfd) {
Q.ninvoke(trans.connection, 'query', type + ';', []).then(function() {
nodefn.call(trans.connection.query, type + ';', []).then(function() {
if (type === 'commit') dfd.resolve(resp);
if (type === 'rollback') dfd.reject(resp);
}).fin(function() {
}).ensure(function() {
trans.connection.end();
trans.connection = null;
});

View File

@ -1,4 +1,4 @@
var Q = require('q');
var When = require('when');
var _ = require('underscore');
var util = require('util');
var base = require('./base');
@ -18,9 +18,9 @@ _.extend(MysqlClient.prototype, base.protoProps, {
var emptyConnection = !builder._connection;
var debug = this.debug || builder._debug;
var instance = this;
return Q((builder._connection || this.getConnection()))
return When((builder._connection || this.getConnection()))
.then(function(conn) {
var dfd = Q.defer();
var dfd = When.defer();
// If we have a debug flag set, console.log the query.
if (debug) base.debug(builder, conn);
@ -55,7 +55,7 @@ _.extend(MysqlClient.prototype, base.protoProps, {
// Empty the connection after we run the query, unless one was specifically
// set (in the case of transactions, etc).
return dfd.promise.fin(function() {
return dfd.promise.ensure(function() {
if (emptyConnection) instance.pool.release(conn);
});
});

View File

@ -1,4 +1,4 @@
var Q = require('q');
var When = require('when');
var _ = require('underscore');
var util = require('util');
var base = require('./base');
@ -18,9 +18,9 @@ _.extend(PostgresClient.prototype, base.protoProps, {
var emptyConnection = !builder._connection;
var debug = this.debug || builder._debug;
var instance = this;
return Q((builder._connection || this.getConnection()))
return When((builder._connection || this.getConnection()))
.then(function(conn) {
var dfd = Q.defer();
var dfd = When.defer();
// Bind all of the ? to numbered vars.
var questionCount = 0;
@ -62,7 +62,7 @@ _.extend(PostgresClient.prototype, base.protoProps, {
// Empty the connection after we run the query, unless one was specifically
// set (in the case of transactions, etc).
return dfd.promise.fin(function() {
return dfd.promise.ensure(function() {
if (emptyConnection) instance.pool.release(conn);
});
});

View File

@ -1,4 +1,4 @@
var Q = require('q');
var When = require('when');
var _ = require('underscore');
var util = require('util');
var base = require('./base');
@ -18,9 +18,9 @@ _.extend(Sqlite3Client.prototype, base.protoProps, {
var emptyConnection = !builder._connection;
var debug = this.debug || builder._debug;
var instance = this;
return Q((builder._connection || this.getConnection()))
return When((builder._connection || this.getConnection()))
.then(function(conn) {
var dfd = Q.defer();
var dfd = When.defer();
var method = (builder.type === 'insert' || builder.type === 'update') ? 'run' : 'all';
// If we have a debug flag set, console.log the query.
@ -57,7 +57,7 @@ _.extend(Sqlite3Client.prototype, base.protoProps, {
// Empty the connection after we run the query, unless one was specifically
// set (in the case of transactions, etc).
return dfd.promise.fin(function(resp) {
return dfd.promise.ensure(function(resp) {
if (emptyConnection) instance.pool.release(conn);
return resp;
});
@ -179,7 +179,18 @@ Sqlite3Client.schemaGrammar = _.extend({}, base.schemaGrammar, Sqlite3Client.gra
}
return sql;
},
// Get the primary key command if it exists on the blueprint.
getCommandByName: function(blueprint, name) {
var commands = this.getCommandsByName(blueprint, name);
if (commands.length > 0) return commands[0];
},
// Get all of the commands with a given name.
getCommandsByName: function(blueprint, name) {
return _.where(blueprint.commands, function(value) { return value.name == name; });
},
// Get the primary key syntax for a table creation statement.
addPrimaryKeys: function(blueprint) {
var primary = this.getCommandByName(blueprint, 'primary');

View File

@ -216,12 +216,12 @@
<li> <a href="#Builder-min">min</a></li>
<li> <a href="#Builder-max">max</a></li>
<li> <a href="#Builder-sum">sum</a></li>
<li> <a href="#Builder-then">then</a></li>
<li> <a href="#Builder-exec">exec</a></li>
<li> <a href="#Builder-increment">increment</a></li>
<li> <a href="#Builder-decrement">decrement</a></li>
<li> <a href="#Builder-exists">exists</a></li>
<li> <a href="#Builder-truncate">truncate *</a></li>
<li><b><a href="#Schema-Building">Interface:</a></b></li>
<li> <a href="#Builder-then">then</a></li>
<li> <a href="#Builder-exec">exec</a></li>
</ul>
<a class="toc_title" href="#Transaction">
@ -232,13 +232,12 @@
Schema
</a>
<ul class="toc_section">
<li> <a href="#Schema-connection">connection</a></li>
<li> <a href="#Schema-createTable">createTable</a></li>
<li> <a href="#Schema-renameTable">createTable</a></li>
<li> <a href="#Schema-renameTable">renameTable</a></li>
<li> <a href="#Schema-dropTable">dropTable</a></li>
<li> <a href="#Schema-hasTable">hasTable</a></li>
<li> <a href="#Schema-dropTableIfExists">dropTableIfExists</a></li>
<li> <a href="#Schema-table">table</a></li>
<li> <a href="#Schema-transacting">transacting *</a></li>
<li><b><a href="#Schema-Building">Schema Building:</a></b></li>
<li> <a href="#Schema-dropColumn">dropColumn</a></li>
<li> <a href="#Schema-dropColumns">dropColumns</a></li>
@ -319,7 +318,7 @@
<p>
All dependencies are specified in <tt>package.json</tt> file but include <tt>underscore.js</tt>,
<tt>q.js</tt>, and the <tt>generic-pool</tt> library. You then need to install
<tt>when.js</tt>, and the <tt>generic-pool</tt> library. You then need to install
either <tt>mysql</tt>, <tt>pg</tt>, or <tt>sqlite3</tt> from <tt>npm</tt> if you wish
to use one of these databases with node.js, or create your own client
adapter and specify it in <a href="#Initialize">Knex.Initialize</a>.
@ -338,7 +337,7 @@ $ npm install sqlite3
<p>
<tt>Knex.Initialize</tt> is the initializing function that must be called prior to using
<b>Knex</b>, accepting a few parameters. The <tt>client</tt> parameter is required
Knex, accepting a few parameters. The <tt>client</tt> parameter is required
and determines which client adapter will be used with the library.
</p>
@ -356,9 +355,9 @@ Knex.Initialize({
</pre>
<p>
It is also possible to use <b>Knex</b> with multiple database connection instances if you'd like,
by creating named instances with <tt>Knex.Initialize</tt>. To do this, pass the name of the
connection as the first parameter into <b>Knex</b> and it will return that instance, which may
It is also possible to use Knex with multiple database connection instances if you'd like,
by creating named instances. To do this, pass the name of the connection as the first
parameter into <tt>Knex.Initialize</tt> and it will return that instance, which may
also be referenced by name under <tt>Knex.Instances</tt>.
</p>
@ -396,8 +395,8 @@ SqliteDB('users')
<p>
The <tt>Knex.Builder</tt> is the interface used for building and executing standard SQL queries,
such as <tt>select</tt>, <tt>insert</tt>, <tt>update</tt>, <tt>delete</tt>. The query is run
by specifying a <a href="#Builder-table">tableName</a>, adding additional query parameters, and calling
one of the <a href="#Builder-promises">promise methods</a>.
by specifying a <a href="#Builder-table">tableName</a>, adding additional query parameters, and
executing the query with one of the public interface methods.
</p>
<p id="Builder-main">
@ -419,10 +418,10 @@ SqliteDB('users')
</p>
<pre>
// generates: "select `title`, `author`, `year` from `books`;"
// select "title", "author", "year" from "books"
Knex('books').select('title', 'author', 'year');
// generates "select * from `books`;"
// select * from "books"
Knex('books').select();
</pre>
@ -581,25 +580,26 @@ Knex('users')
</p>
<pre>
// generates: "select `title`, `author`, `year` from `books`;"
Knex('books').update({
title: '',
author: '',
year:
})
Knex('users').update({
});
Knex('books').update({
title: '',
author: '',
year: 2014
})
</pre>
<p id="Builder-del">
<b class="header">del / delete</b><code>.del()</code>
<br />
Aliased to <tt>del</tt> as <tt>delete</tt> is a reserved word in javascript, this method deletes
one or more rows, based on the other conditions specified in the query.
one or more rows, based on other conditions specified in the query.
</p>
<pre>
Knex('accounts')
.where('activated', false)
.del()
</pre>
<p id="Builder-count">
<b class="header">count</b><code>.count(column)</code>
<br />
@ -636,12 +636,6 @@ Knex('users')
Decrements a column's value by the specified amount.
</p>
<p id="Builder-exists">
<b class="header">exists</b><code>.exists(column, value)</code>
<br />
Decrements a column's value by the specified amount.
</p>
<h2 id="Transaction">Knex.Transaction</h2>
<p>

23
knex.js
View File

@ -10,7 +10,7 @@
// Required dependencies.
var _ = require('underscore');
var Q = require('q');
var When = require('when');
var push = Array.prototype.push;
@ -705,12 +705,6 @@
// ----------------------------------------------------------------------
// Determine if any rows exist for the current query.
exists: function() {
this.count();
return this.setType('exists');
},
// Retrieve the "count" result of the query.
count: function(column) {
return this._aggregate('count', column);
@ -899,7 +893,7 @@
// Initiate a deferred object, so we know when the
// transaction completes or fails, we know what to do.
var dfd = Q.defer();
var dfd = When.defer();
// Call the container with the transaction
// commit & rollback objects
@ -1372,17 +1366,6 @@
return sql;
},
// Get the primary key command if it exists on the blueprint.
getCommandByName: function(blueprint, name) {
var commands = this.getCommandsByName(blueprint, name);
if (commands.length > 0) return commands[0];
},
// Get all of the commands with a given name.
getCommandsByName: function(blueprint, name) {
return _.where(blueprint.commands, function(value) { return value.name == name; });
},
// Get the SQL for the column data type.
getType: function(column) {
return this["type" + capitalize(column.type)](column);
@ -1466,7 +1449,7 @@
// and returns a deferred promise.
Knex.runQuery = function(builder) {
if (builder.transaction) {
if (!builder.transaction.connection) return Q.reject(new Error('The transaction has already completed.'));
if (!builder.transaction.connection) return When.reject(new Error('The transaction has already completed.'));
builder._connection = builder.transaction.connection;
}

View File

@ -1,6 +1,6 @@
{
"name": "knex",
"version": "0.0.2",
"version": "0.0.3",
"description": "a fun sql query builder",
"main": "knex.js",
"directories": {
@ -14,7 +14,7 @@
"sqlite3": "~2.1.7"
},
"dependencies": {
"q": "~0.9.3",
"when": ">=2.0.1",
"underscore": "~1.4.4",
"generic-pool": "~2.0.3"
},

View File

@ -1,4 +1,4 @@
var Q = require('q');
var When = require('when');
var _ = require('underscore');
var Knex = require('../knex');
var conn = require(process.env.KNEX_TEST || './shared/config');
@ -22,11 +22,11 @@ var Postgres = Knex.Initialize('postgres', {
var runQuery = Knex.runQuery;
Knex.runQuery = function(builder) {
if (builder.transaction) {
if (!builder.transaction.connection) return Q.reject(new Error('The transaction has already completed.'));
if (!builder.transaction.connection) return When.reject(new Error('The transaction has already completed.'));
builder._connection = builder.transaction.connection;
}
// Query on the query builder, which should resolve with a promise.
return Q({
return When({
sql: builder.toSql(),
bindings: builder._cleanBindings()
});
@ -36,23 +36,17 @@ describe('Knex', function() {
var allDone;
Q.all([
When.all([
require('./string')(Knex, 'mysql'),
require('./string')(Postgres, 'postgres'),
require('./string')(Sqlite3, 'sqlite3')
]).then(function() {
Knex.runQuery = runQuery;
return Q.all([
return When.all([
require('./regular')(Knex, 'mysql'),
require('./regular')(Postgres, 'postgres'),
require('./regular')(Sqlite3, 'sqlite3')
]);
}).then(function() {
allDone();
}, allDone);
after(function(ok) {
allDone = ok;
});
});

View File

@ -1,4 +1,4 @@
var Q = require('q');
var _ = require('underscore');
module.exports = function(Knex, dbName, handler, type) {

View File

@ -1,4 +1,4 @@
var Q = require('q');
module.exports = function(Knex, dbName, handler, type) {
it('has a sum', function(ok) {

View File

@ -1,4 +1,4 @@
var Q = require('q');
module.exports = function(Knex, dbName, handler, type) {
it('should delete an item', function(ok) {

View File

@ -1,4 +1,4 @@
var Q = require('q');
module.exports = function(Knex, dbName, handler, type) {
describe(dbName, function() {

View File

@ -1,31 +1,30 @@
var Q = require('q');
module.exports = function(Knex, dbName, handler, type) {
describe(dbName, function() {
it('uses inner join by default', function(ok) {
Knex('accounts')
.join('test_table_two', 'accounts.id', '=', 'test_table_two.account_id')
.select('accounts.*', 'test_table_two.details')
.then(handler(ok), ok);
});
it('takes a fifth parameter to specify the join type', function(ok) {
Knex('accounts')
.join('test_table_two', 'accounts.id', '=', 'test_table_two.account_id', 'left')
.select('accounts.*', 'test_table_two.details')
.then(handler(ok), ok);
});
it('accepts a callback as the second argument for advanced joins', function(ok) {
Knex('accounts').join('test_table_two', function(join) {
join.on('accounts.id', '=', 'test_table_two.account_id');
join.orOn('accounts.email', '=', 'test_table_two.details');
}, 'left')
.select()
it('uses inner join by default', function(ok) {
Knex('accounts')
.join('test_table_two', 'accounts.id', '=', 'test_table_two.account_id')
.select('accounts.*', 'test_table_two.details')
.then(handler(ok), ok);
});
});
it('takes a fifth parameter to specify the join type', function(ok) {
Knex('accounts')
.join('test_table_two', 'accounts.id', '=', 'test_table_two.account_id', 'left')
.select('accounts.*', 'test_table_two.details')
.then(handler(ok), ok);
});
it('accepts a callback as the second argument for advanced joins', function(ok) {
Knex('accounts').join('test_table_two', function(join) {
join.on('accounts.id', '=', 'test_table_two.account_id');
join.orOn('accounts.email', '=', 'test_table_two.details');
}, 'left')
.select()
.then(handler(ok), ok);
});
});

View File

@ -1,15 +1,18 @@
var Q = require('q');
var When = require('when');
module.exports = function(Knex, handler, error, type, db) {
var res = null;
return Q.all([
return When.all([
Knex.Schema.dropTableIfExists('test_table_one'),
Knex.Schema.dropTableIfExists('test_table_two'),
Knex.Schema.dropTableIfExists('test_table_three'),
Knex.Schema.dropTableIfExists('accounts')
]).then(function(resp) {
res = [resp[0]]; // only really need one of these for the test output.
return Q.all([
return When.all([
Knex.Schema.createTable('test_table_one', function(table) {
table.increments('id');
table.string('first_name');
@ -29,6 +32,8 @@ module.exports = function(Knex, handler, error, type, db) {
table.text('paragraph').defaultTo('Lorem ipsum Qui quis qui in.');
})
]);
}, function(err) {
console.log(err.stack);
})
.then(function(resp) {
// Edit test table one

View File

@ -1,4 +1,4 @@
var Q = require('q');
var When = require('when');
module.exports = function(Knex, dbName, handler, type) {
describe(dbName, function() {
@ -14,7 +14,7 @@ module.exports = function(Knex, dbName, handler, type) {
}),
it('does simple "where" cases', function(ok) {
Q.all([
When.all([
Knex('accounts').where('id', 1).select('first_name', 'last_name'),
Knex('accounts').where('id', '>', 1).select(['email', 'logins']),
Knex('accounts').where({'id': 1}).select('*'),
@ -25,27 +25,27 @@ module.exports = function(Knex, dbName, handler, type) {
});
it('has a "distinct" clause', function(ok) {
Q.all([
When.all([
Knex('accounts').select().distinct('email').where('logins', 2),
Knex('accounts').distinct('email').select()
]).then(handler(ok, true), ok);
});
it('does "orWhere" cases', function(ok) {
Q.all([
When.all([
Knex('accounts').where('id', 1).orWhere('id', '>', 2).select('first_name', 'last_name')
// More tests can be added here.
]).then(handler(ok, true), ok);
});
it('does "andWhere" cases', function(ok) {
Q.all([
When.all([
Knex('accounts').select('first_name', 'last_name', 'about').where('id', 1).andWhere('email', 'test@example.com')
]).then(handler(ok, true), ok);
});
it('takes a function to wrap nested where statements', function(ok) {
Q.all([
When.all([
Knex('accounts').where(function() {
this.where('id', 2);
this.orWhere('id', 3);
@ -54,7 +54,7 @@ module.exports = function(Knex, dbName, handler, type) {
});
it('handles "where in" cases', function(ok) {
Q.all([
When.all([
Knex('accounts').whereIn('id', [1, 2, 3]).select()
]).then(handler(ok, true), ok);
});

View File

@ -1,4 +1,4 @@
var Q = require('q');
module.exports = function(Knex, dbName, handler, type) {
describe(dbName, function() {

View File

@ -1,4 +1,4 @@
var Q = require('q');
module.exports = function(Knex, dbName, handler, type) {
describe(dbName, function() {

View File

@ -1,4 +1,4 @@
var Q = require('q');
var When = require('when');
var _ = require('underscore');
var objectdump = require('objectdump');
var dev = parseInt(process.env.KNEX_DEV, 10);
@ -7,6 +7,8 @@ var assert = require('assert');
module.exports = function(Knex, type) {
var dfd = When.defer();
describe('DB Tests - ' + type, function() {
describe('Knex.Builder', function() {
@ -54,6 +56,7 @@ module.exports = function(Knex, type) {
after(function(ok) {
if (dev) require('fs').writeFileSync('./test/shared/output.js', 'module.exports = ' + objectdump(out));
dfd.resolve();
ok();
});
@ -61,6 +64,8 @@ module.exports = function(Knex, type) {
});
return dfd.promise;
};

View File

@ -1,4 +1,4 @@
var Q = require('q');
var When = require('when');
var _ = require('underscore');
var objectdump = require('objectdump');
var dev = parseInt(process.env.KNEX_DEV, 10);
@ -7,7 +7,7 @@ var assert = require('assert');
module.exports = function(Knex, type) {
var dfd = Q.defer();
var dfd = When.defer();
describe('String Tests', function() {