2014-09-01 17:18:45 +02:00
|
|
|
'use strict';
|
|
|
|
|
2014-05-08 18:31:25 -04:00
|
|
|
var _ = require('lodash');
|
|
|
|
var Promise = require('./promise');
|
2015-04-19 16:31:52 -04:00
|
|
|
var inherits = require('inherits')
|
|
|
|
var EventEmitter = require('events').EventEmitter
|
2014-04-08 16:25:57 -04:00
|
|
|
|
|
|
|
// The "Runner" constructor takes a "builder" (query, schema, or raw)
|
|
|
|
// and runs through each of the query statements, calling any additional
|
|
|
|
// "output" method provided alongside the query and bindings.
|
2015-04-19 16:31:52 -04:00
|
|
|
function Runner(client, connection) {
|
|
|
|
this.queries = []
|
|
|
|
this.client = client
|
|
|
|
this.builder = builder
|
|
|
|
this.connection = connection
|
2014-04-08 16:25:57 -04:00
|
|
|
}
|
2015-04-19 16:31:52 -04:00
|
|
|
inherits(Runner, EventEmitter)
|
2014-04-08 16:25:57 -04:00
|
|
|
|
2014-04-09 10:11:41 -04:00
|
|
|
// "Run" the target, calling "toSQL" on the builder, returning
|
2014-04-08 16:25:57 -04:00
|
|
|
// an object or array of queries to run, each of which are run on
|
|
|
|
// a single connection.
|
2015-04-19 16:31:52 -04:00
|
|
|
Runner.prototype.read = function(type, obj) {
|
|
|
|
var sql = this.builder.toSQL();
|
|
|
|
this.emit('start', this);
|
|
|
|
}
|
2014-06-22 15:11:01 -04:00
|
|
|
|
2015-04-19 16:31:52 -04:00
|
|
|
// if (_.isArray(sql)) {
|
|
|
|
// return this.queryArray(sql);
|
|
|
|
// }
|
|
|
|
// return this.query(sql);
|
|
|
|
|
|
|
|
// // If there are any "error" listeners, we fire an error event
|
|
|
|
// // and then re-throw the error to be eventually handled by
|
|
|
|
// // the promise chain. Useful if you're wrapping in a custom `Promise`.
|
|
|
|
// .catch(function(err) {
|
|
|
|
// if (this.builder._events && this.builder._events.error) {
|
|
|
|
// this.builder.emit('error', err);
|
|
|
|
// }
|
|
|
|
// throw err;
|
|
|
|
// })
|
|
|
|
|
|
|
|
// // Fire a single "end" event on the builder when
|
|
|
|
// // all queries have successfully completed.
|
|
|
|
// .tap(function() {
|
|
|
|
// this.builder.emit('end');
|
|
|
|
// })
|
|
|
|
// }
|
2014-04-08 16:25:57 -04:00
|
|
|
|
2014-04-09 10:11:41 -04:00
|
|
|
// Stream the result set, by passing through to the dialect's streaming
|
|
|
|
// capabilities. If the options are
|
|
|
|
var PassThrough;
|
2014-06-25 02:42:22 -04:00
|
|
|
Runner.prototype.stream = function(options, handler) {
|
2015-04-19 16:31:52 -04:00
|
|
|
var runner = this
|
|
|
|
var connection = this.connection
|
|
|
|
var client = this.client
|
|
|
|
|
2014-04-09 10:11:41 -04:00
|
|
|
// If we specify stream(handler).then(...
|
|
|
|
if (arguments.length === 1) {
|
|
|
|
if (_.isFunction(options)) {
|
|
|
|
handler = options;
|
|
|
|
options = {};
|
|
|
|
}
|
|
|
|
}
|
2014-05-06 16:18:39 -04:00
|
|
|
|
2014-06-25 02:42:22 -04:00
|
|
|
// Determines whether we emit an error or throw here.
|
|
|
|
var hasHandler = _.isFunction(handler);
|
|
|
|
|
2014-05-06 16:18:39 -04:00
|
|
|
// Lazy-load the "PassThrough" dependency.
|
|
|
|
PassThrough = PassThrough || require('readable-stream').PassThrough;
|
|
|
|
var stream = new PassThrough({objectMode: true});
|
|
|
|
var promise = Promise.bind(this)
|
2015-04-19 16:31:52 -04:00
|
|
|
.then(function() {
|
2014-05-05 19:48:12 -04:00
|
|
|
var sql = this.builder.toSQL();
|
|
|
|
var err = new Error('The stream may only be used with a single query statement.');
|
|
|
|
if (_.isArray(sql)) {
|
2014-06-25 02:42:22 -04:00
|
|
|
if (hasHandler) throw err;
|
2014-05-05 22:00:29 -04:00
|
|
|
stream.emit('error', err);
|
2014-05-05 19:48:12 -04:00
|
|
|
}
|
|
|
|
return sql;
|
2015-04-19 16:31:52 -04:00
|
|
|
})
|
|
|
|
.then(function(sql) {
|
2014-05-06 16:18:39 -04:00
|
|
|
return this._stream(sql, stream, options);
|
2015-04-19 16:31:52 -04:00
|
|
|
})
|
|
|
|
.finally(function() {
|
|
|
|
this.client.releaseConnection(this.connection)
|
|
|
|
});
|
2014-05-06 16:18:39 -04:00
|
|
|
|
|
|
|
// If a function is passed to handle the stream, send the stream
|
|
|
|
// there and return the promise, otherwise just return the stream
|
|
|
|
// and the promise will take care of itsself.
|
2014-06-25 02:42:22 -04:00
|
|
|
if (hasHandler) {
|
2014-05-06 16:18:39 -04:00
|
|
|
handler(stream);
|
|
|
|
return promise;
|
|
|
|
}
|
|
|
|
return stream;
|
2014-06-25 02:42:22 -04:00
|
|
|
};
|
2014-04-09 10:11:41 -04:00
|
|
|
|
2014-05-06 16:18:39 -04:00
|
|
|
// Allow you to pipe the stream to a writable stream.
|
|
|
|
Runner.prototype.pipe = function(writable) {
|
|
|
|
return this.stream().pipe(writable);
|
|
|
|
};
|
|
|
|
|
2014-04-15 11:43:47 -04:00
|
|
|
// "Runs" a query, returning a promise. All queries specified by the builder are guaranteed
|
|
|
|
// to run in sequence, and on the same connection, especially helpful when schema building
|
|
|
|
// and dealing with foreign key constraints, etc.
|
2015-04-19 16:31:52 -04:00
|
|
|
Runner.prototype.query = function(obj) {
|
2015-04-17 15:00:08 -04:00
|
|
|
obj.__knexUid = this.connection.__knexUid;
|
2015-04-19 16:31:52 -04:00
|
|
|
this.emit('query', obj)
|
2014-04-27 19:35:36 -04:00
|
|
|
this.builder.emit('query', obj);
|
2014-06-20 07:27:31 -04:00
|
|
|
this.client.emit('query', obj);
|
2014-04-16 01:23:50 -04:00
|
|
|
return this._query(obj).bind(this).then(this.processResponse);
|
2015-04-19 16:31:52 -04:00
|
|
|
}
|
2014-04-15 11:43:47 -04:00
|
|
|
|
|
|
|
// In the case of the "schema builder" we call `queryArray`, which runs each
|
|
|
|
// of the queries in sequence.
|
|
|
|
Runner.prototype.queryArray = Promise.method(function(queries) {
|
2014-04-16 01:23:50 -04:00
|
|
|
return queries.length === 1 ? this.query(queries[0]) : Promise.bind(this)
|
2014-04-15 11:43:47 -04:00
|
|
|
.thenReturn(queries)
|
|
|
|
.reduce(function(memo, query) {
|
|
|
|
return this.query(query).then(function(resp) {
|
|
|
|
memo.push(resp);
|
|
|
|
return memo;
|
2015-04-19 16:31:52 -04:00
|
|
|
})
|
|
|
|
}, [])
|
|
|
|
})
|
2014-04-08 16:25:57 -04:00
|
|
|
|
2014-04-09 10:11:41 -04:00
|
|
|
// Check whether we're "debugging", based on either calling `debug` on the query.
|
2014-04-08 16:25:57 -04:00
|
|
|
Runner.prototype.isDebugging = function() {
|
2015-03-08 13:09:03 +03:00
|
|
|
return this.builder._debug || (this.client.isDebugging === true && this.builder._debug !== false);
|
2015-04-19 16:31:52 -04:00
|
|
|
}
|
2014-04-09 10:11:41 -04:00
|
|
|
|
2014-09-01 23:22:07 +02:00
|
|
|
module.exports = Runner;
|