knex/lib/common.js
2013-09-03 22:01:31 -04:00

116 lines
3.5 KiB
JavaScript

var _ = require('underscore');
var when = require('when');
var Raw = require('./raw').Raw;
var Helpers = require('./helpers').Helpers;
// Methods common to both the `Grammar` and `SchemaGrammar` interfaces,
// used to generate the sql in one form or another.
exports.Common = {
_debug: false,
_promise: null,
debug: function() {
this._debug = true;
return this;
},
// For those who dislike promise interfaces.
// Multiple calls to `exec` will resolve with the same value
// if called more than once. Any unhandled errors will be thrown
// after the last block.
exec: function(callback) {
this._promise || (this._promise = this.runQuery());
return this._promise.then(function(resp) {
if (callback) callback(null, resp);
}, function(err) {
if (callback) callback(err, null);
}).then(null, function(err) {
setTimeout(function() { throw err; }, 0);
});
},
// The promise interface for the query builder.
then: function(onFulfilled, onRejected) {
this._promise || (this._promise = this.runQuery());
return this._promise.then(onFulfilled, onRejected);
},
// Returns an array of query strings filled out with the
// correct values based on bindings, etc. Useful for debugging.
toString: function() {
this.type || (this.type = 'select');
var data = this.toSql();
var builder = this;
if (!_.isArray(data)) data = [data];
return _.map(data, function(str) {
var questionCount = 0;
return str.replace(/\?/g, function() {
return builder.bindings[questionCount++];
});
}).join('; ');
},
// Explicitly sets the connection.
connection: function(connection) {
this._connection = connection;
return this;
},
// The connection the current query is being run on, optionally
// specified by the `connection` method.
_connection: false,
// Sets the "type" of the current query, so we can potentially place
// `select`, `update`, `del`, etc. anywhere in the query statement
// and have it come out fine.
_setType: function(type) {
if (this.type) {
throw new Error('The query type has already been set to ' + this.type);
}
this.type = type;
return this;
},
// Returns all bindings excluding the `Knex.Raw` types.
_cleanBindings: function() {
var bindings = this.bindings;
var cleaned = [];
for (var i = 0, l = bindings.length; i < l; i++) {
if (!(bindings[i] instanceof Raw)) {
cleaned.push(bindings[i]);
} else {
push.apply(cleaned, bindings[i].bindings);
}
}
return cleaned;
},
// Runs the query on the current builder instance and returns a promise.
runQuery: function() {
if (this.transaction) {
if (!this.transaction.connection) return when.reject(new Error('The transaction has already completed.'));
this._connection = this.transaction.connection;
}
// Prep the SQL associated with the this.
this.sql = this.toSql();
this.bindings = this._cleanBindings();
if (!_.isArray(this.sql)) this.sql = [this.sql];
var chain;
for (var i = 0, l = this.sql.length; i < l; i++) {
if (chain) {
chain.then(Helpers.multiQuery(this, i, chain));
} else {
chain = Helpers.multiQuery(this, i);
}
}
return chain;
}
};