Revert to generic pool (#1665)

This commit is contained in:
Tim Griesser 2016-09-13 18:12:23 -04:00 committed by GitHub
parent 3a5250d87d
commit 7069ce509e
23 changed files with 227 additions and 212 deletions

View File

@ -8,9 +8,9 @@
- Fix broken behavior on WebSQL build, #1638
- Oracle id sequence now handles manual inserts, #906
- Cleanup PG escaping, fix #1602, #1548
- Pool2 error event is left unhandled, allowing the server to crash and restart rather than end up in a bad state
- Added [`with`](#Builder-with) to builder for [common table expressions](https://www.postgresql.org/docs/9.4/static/queries-with.html), #1599
- Fix #1619, pluck with explicit column names
- Switching back to [generic-pool](https://github.com/coopernurse/node-pool) for pooling resource management
# 0.11.10 - 9 Aug, 2016

View File

@ -5,10 +5,11 @@
"main": "knex.js",
"dependencies": {
"babel-runtime": "^6.11.6",
"bluebird": "^3.3.4",
"bluebird": "^3.4.6",
"chalk": "^1.0.0",
"commander": "^2.2.0",
"debug": "^2.1.3",
"generic-pool": "^2.4.2",
"inherits": "~2.0.1",
"interpret": "^0.6.5",
"liftoff": "~2.2.0",
@ -64,6 +65,7 @@
"plaintest": "mocha --check-leaks -b -R spec test/index.js && npm run tape",
"prepublish": "npm run babel",
"tape": "node test/tape/index.js | tap-spec",
"debug_tape": "node-debug test/tape/index.js",
"test": "npm run lint && istanbul --config=test/.istanbul.yml cover node_modules/mocha/bin/_mocha -- --check-leaks -b -R spec test/index.js && npm run tape"
},
"bin": {

View File

@ -1,4 +1,3 @@
import Promise from 'bluebird';
import * as helpers from './helpers';
@ -17,7 +16,7 @@ import TableCompiler from './schema/tablecompiler';
import ColumnBuilder from './schema/columnbuilder';
import ColumnCompiler from './schema/columncompiler';
import Pool2 from 'pool2';
import { Pool } from 'generic-pool';
import inherits from 'inherits';
import { EventEmitter } from 'events';
@ -26,6 +25,12 @@ import { assign, uniqueId, cloneDeep } from 'lodash'
const debug = require('debug')('knex:client')
const debugQuery = require('debug')('knex:query')
const debugPool = require('debug')('knex:pool')
let id = 0
function clientId() {
return `client${id++}`
}
// The base client provides the general structure
// for a dialect specific client object.
@ -35,6 +40,7 @@ function Client(config = {}) {
if (this.driverName && config.connection) {
this.initializeDriver()
if (!config.pool || (config.pool && config.pool.max !== 0)) {
this.__cid = clientId()
this.initializePool(config)
}
}
@ -152,21 +158,19 @@ assign(Client.prototype, {
}
},
initializePool(config) {
if (this.pool) this.destroy()
this.pool = new Pool2(assign(this.poolDefaults(config.pool || {}), config.pool))
this.pool.on('warn', function(msg) {
helpers.warn(`Pool2 - ${msg}`)
})
},
poolDefaults(poolConfig) {
const client = this
const name = this.dialect + ':' + this.driverName + ':' + this.__cid
return {
min: 2,
max: 10,
acquire(callback) {
client.acquireRawConnection()
name: name,
log(str, level) {
if (level === 'info') {
debugPool(level.toUpperCase() + ' pool ' + name + ' - ' + str)
}
},
create: (callback) => {
this.acquireRawConnection()
.tap(function(connection) {
connection.__knexUid = uniqueId('__knexUid')
if (poolConfig.afterCreate) {
@ -175,32 +179,48 @@ assign(Client.prototype, {
})
.asCallback(callback)
},
dispose(connection, callback) {
destroy: (connection) => {
if (poolConfig.beforeDestroy) {
poolConfig.beforeDestroy(connection, function() {
if (connection !== undefined) {
client.destroyRawConnection(connection, callback)
}
})
} else if (connection !== void 0) {
client.destroyRawConnection(connection, callback)
helpers.warn(`
beforeDestroy is deprecated, please open an issue if you use this
to discuss alternative apis
`)
poolConfig.beforeDestroy(connection, function() {})
}
if (connection !== void 0) {
this.destroyRawConnection(connection)
}
},
ping(resource, callback) {
return client.ping(resource, callback);
validate: (connection) => {
if (connection.__knex__disposed) {
helpers.warn(`Connection Error: ${connection.__knex__disposed}`)
return false
}
return this.validateConnection(connection)
}
}
},
initializePool(config) {
if (this.pool) {
helpers.warn('The pool has already been initialized')
return
}
this.pool = new Pool(assign(this.poolDefaults(config.pool || {}), config.pool))
},
validateConnection(connection) {
return true
},
// Acquire a connection from the pool.
acquireConnection() {
const client = this
let request = null
const completed = new Promise(function(resolver, rejecter) {
if (!client.pool) {
return rejecter(new Error('There is no pool defined on the current client'))
const completed = new Promise((resolver, rejecter) => {
if (!this.pool) {
return rejecter(new Error('Unable to acquire a connection'))
}
request = client.pool.acquire(function(err, connection) {
request = this.pool.acquire(function(err, connection) {
if (err) return rejecter(err)
debug('acquired connection from pool: %s', connection.__knexUid)
resolver(connection)
@ -220,24 +240,27 @@ assign(Client.prototype, {
// Releases a connection back to the connection pool,
// returning a promise resolved when the connection is released.
releaseConnection(connection) {
const { pool } = this
return new Promise(function(resolver) {
return new Promise((resolver) => {
debug('releasing connection to pool: %s', connection.__knexUid)
pool.release(connection)
this.pool.release(connection)
resolver()
})
},
// Destroy the current connection pool for the client.
destroy(callback) {
const client = this
const promise = new Promise(function(resolver) {
if (!client.pool) return resolver()
client.pool.end(function() {
client.pool = undefined
resolver()
const promise = new Promise((resolver) => {
if (!this.pool) {
return resolver()
}
this.pool.drain(() => {
this.pool.destroyAllNow(() => {
this.pool = undefined
resolver()
})
})
})
// Allow either a callback or promise interface for destruction.
if (typeof callback === 'function') {
promise.asCallback(callback)

View File

@ -36,7 +36,6 @@ assign(Client_MariaSQL.prototype, {
return new Promise(function(resolver, rejecter) {
connection
.on('ready', function() {
connection.removeAllListeners('end');
connection.removeAllListeners('error');
resolver(connection);
})
@ -44,11 +43,15 @@ assign(Client_MariaSQL.prototype, {
})
},
validateConnection(connection) {
return connection.connected === true
},
// Used to explicitly close a connection, called internally by the pool
// when a connection times out or the pool is shutdown.
destroyRawConnection(connection, cb) {
destroyRawConnection(connection) {
connection.removeAllListeners()
connection.end()
cb()
},
// Return the database for the MariaSQL client.
@ -117,10 +120,6 @@ assign(Client_MariaSQL.prototype, {
default:
return response;
}
},
ping(resource, callback) {
resource.query('SELECT 1', callback);
}
})

View File

@ -73,22 +73,28 @@ assign(Client_MSSQL.prototype, {
// Get a raw connection, called by the `pool` whenever a new
// connection needs to be added to the pool.
acquireRawConnection() {
const client = this;
const connection = new this.driver.Connection(this.connectionSettings);
return new Promise(function(resolver, rejecter) {
connection.connect(function(err) {
if (err) return rejecter(err);
connection.on('error', connectionErrorHandler.bind(null, client, connection));
connection.on('end', connectionErrorHandler.bind(null, client, connection));
return new Promise((resolver, rejecter) => {
const connection = new this.driver.Connection(this.connectionSettings);
connection.connect((err) => {
if (err) {
return rejecter(err)
}
connection.on('error', (err) => {
connection.__knex__disposed = err
})
resolver(connection);
});
});
},
validateConnection(connection) {
return connection.connected === true
},
// Used to explicitly close a connection, called internally by the pool
// when a connection times out or the pool is shutdown.
destroyRawConnection(connection, cb) {
connection.close(cb);
destroyRawConnection(connection) {
connection.close()
},
// Position the bindings for the query.
@ -103,13 +109,14 @@ assign(Client_MSSQL.prototype, {
// Grab a connection, run the query via the MSSQL streaming interface,
// and pass that through to the stream we've sent back to the client.
_stream(connection, obj, stream, options) {
const client = this;
options = options || {}
if (!obj || typeof obj === 'string') obj = {sql: obj}
// convert ? params into positional bindings (@p1)
obj.sql = this.positionBindings(obj.sql);
return new Promise(function(resolver, rejecter) {
stream.on('error', rejecter);
return new Promise((resolver, rejecter) => {
stream.on('error', (err) => {
rejecter(err)
});
stream.on('end', resolver);
let { sql } = obj
if (!sql) return resolver()
@ -122,7 +129,7 @@ assign(Client_MSSQL.prototype, {
req.stream = true;
if (obj.bindings) {
for (let i = 0; i < obj.bindings.length; i++) {
client._setReqInput(req, i, obj.bindings[i])
this._setReqInput(req, i, obj.bindings[i])
}
}
req.pipe(stream)
@ -137,7 +144,7 @@ assign(Client_MSSQL.prototype, {
if (!obj || typeof obj === 'string') obj = {sql: obj}
// convert ? params into positional bindings (@p1)
obj.sql = this.positionBindings(obj.sql);
return new Promise(function(resolver, rejecter) {
return new Promise((resolver, rejecter) => {
let { sql } = obj
if (!sql) return resolver()
if (obj.options) {
@ -151,8 +158,10 @@ assign(Client_MSSQL.prototype, {
client._setReqInput(req, i, obj.bindings[i])
}
}
req.query(sql, function(err, recordset) {
if (err) return rejecter(err)
req.query(sql, (err, recordset) => {
if (err) {
return rejecter(err)
}
obj.response = recordset[0]
resolver(obj)
})
@ -206,10 +215,6 @@ assign(Client_MSSQL.prototype, {
default:
return response
}
},
ping(resource, callback) {
resource.request().query('SELECT 1', callback);
}
})
@ -229,13 +234,4 @@ class MSSQL_Formatter extends Formatter {
}
// MSSQL Specific error handler
function connectionErrorHandler(client, connection, err) {
if (connection && err && err.fatal) {
if (connection.__knex__disposed) return;
connection.__knex__disposed = true;
client.pool.destroy(connection);
}
}
export default Client_MSSQL

View File

@ -63,29 +63,34 @@ assign(Client_MySQL.prototype, {
// Get a raw connection, called by the `pool` whenever a new
// connection needs to be added to the pool.
acquireRawConnection() {
const client = this
const connection = this.driver.createConnection(this.connectionSettings)
return new Promise(function(resolver, rejecter) {
connection.connect(function(err) {
return new Promise((resolver, rejecter) => {
const connection = this.driver.createConnection(this.connectionSettings)
connection.connect((err) => {
if (err) return rejecter(err)
connection.on('error', client._connectionErrorHandler.bind(null, client, connection))
connection.on('end', client._connectionErrorHandler.bind(null, client, connection))
connection.on('error', err => {
connection.__knex__disposed = err
})
resolver(connection)
});
});
})
})
},
// Used to explicitly close a connection, called internally by the pool
// when a connection times out or the pool is shutdown.
destroyRawConnection(connection, cb) {
connection.end(cb);
destroyRawConnection(connection) {
connection.removeAllListeners()
connection.end()
},
validateConnection(connection) {
return connection.state === 'connected' || connection.state === 'authenticated'
},
// Grab a connection, run the query via the MySQL streaming interface,
// and pass that through to the stream we've sent back to the client.
_stream(connection, obj, stream, options) {
options = options || {}
return new Promise(function(resolver, rejecter) {
return new Promise((resolver, rejecter) => {
stream.on('error', rejecter)
stream.on('end', resolver)
connection.query(obj.sql, obj.bindings).stream(options).pipe(stream)
@ -135,18 +140,6 @@ assign(Client_MySQL.prototype, {
}
},
// MySQL Specific error handler
_connectionErrorHandler: (client, connection, err) => {
if(connection && err && err.fatal && !connection.__knex__disposed) {
connection.__knex__disposed = true;
client.pool.destroy(connection);
}
},
ping(resource, callback) {
resource.query('SELECT 1', callback);
},
canCancelQuery: true,
cancelQuery(connectionToKill) {

View File

@ -61,15 +61,22 @@ assign(Client_MySQL2.prototype, {
return require('mysql2')
},
validateConnection() {
return true
},
// Get a raw connection, called by the `pool` whenever a new
// connection needs to be added to the pool.
acquireRawConnection() {
const client = this;
const connection = this.driver.createConnection(pick(this.connectionSettings, configOptions))
return new Promise(function(resolver, rejecter) {
connection.connect(function(err) {
if (err) return rejecter(err)
connection.on('error', client._connectionErrorHandler.bind(null, client, connection))
return new Promise((resolver, rejecter) => {
connection.connect((err) => {
if (err) {
return rejecter(err)
}
connection.on('error', err => {
connection.__knex__disposed = err
})
resolver(connection)
})
})
@ -98,10 +105,6 @@ assign(Client_MySQL2.prototype, {
default:
return response
}
},
ping(resource, callback) {
resource.query('SELECT 1', callback);
}
})

View File

@ -84,25 +84,22 @@ assign(Client_Oracle.prototype, {
// Get a raw connection, called by the `pool` whenever a new
// connection needs to be added to the pool.
acquireRawConnection() {
const client = this
return new Promise(function(resolver, rejecter) {
client.driver.connect(client.connectionSettings,
function(err, connection) {
if (err) return rejecter(err)
Promise.promisifyAll(connection)
if (client.connectionSettings.prefetchRowCount) {
connection.setPrefetchRowCount(client.connectionSettings.prefetchRowCount)
}
resolver(connection)
})
return new Promise((resolver, rejecter) => {
this.driver.connect(this.connectionSettings, (err, connection) => {
if (err) return rejecter(err)
Promise.promisifyAll(connection)
if (this.connectionSettings.prefetchRowCount) {
connection.setPrefetchRowCount(this.connectionSettings.prefetchRowCount)
}
resolver(connection)
})
})
},
// Used to explicitly close a connection, called internally by the pool
// when a connection times out or the pool is shutdown.
destroyRawConnection(connection, cb) {
destroyRawConnection(connection) {
connection.close()
cb()
},
// Return the database for the Oracle client.
@ -122,11 +119,16 @@ assign(Client_Oracle.prototype, {
_stream(connection, obj, stream, options) {
obj.sql = this.positionBindings(obj.sql);
return new Promise(function (resolver, rejecter) {
stream.on('error', rejecter);
stream.on('error', (err) => {
if (isConnectionError(err)) {
connection.__knex__disposed = err
}
rejecter(err)
})
stream.on('end', resolver);
const queryStream = new OracleQueryStream(connection, obj.sql, obj.bindings, options);
queryStream.pipe(stream)
});
})
},
// Runs the query on the specified connection, providing the bindings
@ -146,6 +148,11 @@ assign(Client_Oracle.prototype, {
obj.response = response;
obj.rowsAffected = response.updateCount;
return obj;
}).catch(err => {
if (isConnectionError(err)) {
connection.__knex__disposed = err
}
throw err
})
},
@ -177,10 +184,16 @@ assign(Client_Oracle.prototype, {
default:
return response;
}
},
ping(resource, callback) {
resource.execute('SELECT 1 FROM DUAL', [], callback);
}
})
// If the error is any of these, we'll assume we need to
// mark the connection as failed
const connectionErrors = [
'ORA-12514', 'NJS-040', 'NJS-024', 'NJS-003', 'NJS-024'
]
function isConnectionError(err) {
return connectionErrors.some(prefix => err.message.indexOf(prefix) === 0)
}

View File

@ -198,8 +198,8 @@ Client_Oracledb.prototype.acquireRawConnection = function() {
// Used to explicitly close a connection, called internally by the pool
// when a connection times out or the pool is shutdown.
Client_Oracledb.prototype.destroyRawConnection = function(connection, cb) {
connection.release(cb);
Client_Oracledb.prototype.destroyRawConnection = function(connection) {
connection.release()
};
// Runs the query on the specified connection, providing the bindings

View File

@ -101,9 +101,12 @@ assign(Client_PG.prototype, {
return new Promise(function(resolver, rejecter) {
const connection = new client.driver.Client(client.connectionSettings);
connection.connect(function(err, connection) {
if (err) return rejecter(err);
connection.on('error', client.__endConnection.bind(client, connection));
connection.on('end', client.__endConnection.bind(client, connection));
if (err) {
return rejecter(err);
}
connection.on('error', (err) => {
connection.__knex__disposed = err
})
if (!client.version) {
return client.checkVersion(connection).then(function(version) {
client.version = version;
@ -119,9 +122,8 @@ assign(Client_PG.prototype, {
// Used to explicitly close a connection, called internally by the pool
// when a connection times out or the pool is shutdown.
destroyRawConnection(connection, cb) {
destroyRawConnection(connection) {
connection.end()
cb()
},
// In PostgreSQL, we need to do a version check to do some feature
@ -217,21 +219,8 @@ assign(Client_PG.prototype, {
return resp.rowCount;
}
return resp;
},
__endConnection(connection) {
if (!connection || connection.__knex__disposed) return;
if (this.pool) {
connection.__knex__disposed = true;
this.pool.destroy(connection);
}
},
ping(resource, callback) {
resource.query('SELECT 1', [], callback);
}
})
export default Client_PG

View File

@ -59,10 +59,11 @@ assign(Client_SQLite3.prototype, {
// Get a raw connection from the database, returning a promise with the connection object.
acquireRawConnection() {
const client = this;
return new Promise(function(resolve, reject) {
const db = new client.driver.Database(client.connectionSettings.filename, function(err) {
if (err) return reject(err)
return new Promise((resolve, reject) => {
const db = new this.driver.Database(this.connectionSettings.filename, (err) => {
if (err) {
return reject(err)
}
resolve(db)
})
})
@ -70,9 +71,12 @@ assign(Client_SQLite3.prototype, {
// Used to explicitly close a connection, called internally by the pool when
// a connection times out or the pool is shutdown.
destroyRawConnection(connection, cb) {
connection.close()
cb()
destroyRawConnection(connection) {
connection.close((err) => {
if (err) {
this.emit('error', err)
}
})
},
// Runs the query on the specified connection, providing the bindings and any
@ -146,13 +150,9 @@ assign(Client_SQLite3.prototype, {
poolDefaults(config) {
return assign(Client.prototype.poolDefaults.call(this, config), {
min: 1,
min: 0,
max: 1
})
},
ping(resource, callback) {
resource.each('SELECT 1', callback);
}
})

View File

@ -112,10 +112,6 @@ assign(Client_WebSQL.prototype, {
default:
return resp;
}
},
ping(resource, callback) {
callback();
}
})

View File

@ -214,7 +214,6 @@ assign(Runner.prototype, {
.catch(rejecter)
})
}).disposer(function() {
if (runner.connection.__knex__disposed) return
runner.client.releaseConnection(runner.connection)
})
}

View File

@ -126,15 +126,12 @@ export default function makeKnex(client) {
client.on('start', function(obj) {
knex.emit('start', obj)
})
client.on('query', function(obj) {
knex.emit('query', obj)
})
client.on('query-error', function(err, obj) {
knex.emit('query-error', err, obj)
})
client.on('query-response', function(response, obj, builder) {
knex.emit('query-response', response, obj, builder)
})

View File

@ -1,5 +1,5 @@
/*global describe, expect, it*/
/*eslint no-var:0, max-len:0 */
'use strict';
var Knex = require('../../../knex');
@ -185,7 +185,6 @@ module.exports = function(knex) {
it('should allow renaming a column', function() {
var countColumn
console.log(knex.client.dialect);
switch (knex.client.dialect) {
case 'oracle': countColumn = 'COUNT(*)'; break;
case 'mssql': countColumn = ''; break;
@ -380,7 +379,9 @@ module.exports = function(knex) {
it('.timeout(ms, {cancel: true}) should throw error if cancellation cannot acquire connection', function() {
// Only mysql/mariadb query cancelling supported for now
var dialect = knex.client.config.dialect;
if (!_.startsWith(dialect, "mysql") && !_.startsWith(dialect, "maria")) { return; }
if (!_.startsWith(dialect, "mysql") && !_.startsWith(dialect, "maria")) {
return;
}
//To make this test easier, I'm changing the pool settings to max 1.
var knexConfig = _.clone(knex.client.config);

View File

@ -7,9 +7,11 @@ var logger = require('./logger');
var config = require('../knexfile');
var fs = require('fs');
Object.keys(config).forEach(function(dialectName) {
require('./suite')(logger(knex(config[dialectName])));
});
var Promise = require('bluebird')
Promise.each(Object.keys(config), function(dialectName) {
return require('./suite')(logger(knex(config[dialectName])));
})
after(function(done) {
if (config.sqlite3 && config.sqlite3.connection.filename !== ':memory:') {
@ -17,4 +19,4 @@ after(function(done) {
} else {
done();
}
});
});

View File

@ -10,6 +10,10 @@ module.exports = function(knex) {
this.dialect = knex.client.dialect;
this.driverName = knex.client.driverName;
after(function() {
return knex.destroy()
})
require('./schema')(knex);
require('./migrate')(knex);
require('./seed')(knex);
@ -26,7 +30,7 @@ module.exports = function(knex) {
describe('knex.destroy', function() {
it('should allow destroying the pool with knex.destroy', function() {
var spy = sinon.spy(knex.client.pool, 'end');
var spy = sinon.spy(knex.client.pool, 'destroyAllNow');
return knex.destroy().then(function() {
expect(spy).to.have.callCount(1);
expect(knex.client.pool).to.equal(undefined);

View File

@ -12,10 +12,6 @@ var pool = {
afterCreate: function(connection, callback) {
assert.ok(typeof connection.__knexUid !== 'undefined')
callback(null, connection);
},
beforeDestroy: function(connection, continueFunc) {
assert.ok(typeof connection.__knexUid !== 'undefined')
continueFunc();
}
};

View File

@ -47,4 +47,4 @@ module.exports = function(tableName, knex) {
}
}
}

View File

@ -1,18 +1,19 @@
/*eslint no-var:0*/
'use strict';
var tape = require('tape')
// var wtf = require('wtfnode');
var tape = require('tape')
var makeKnex = require('../../knex')
var knexfile = require('../knexfile')
Object.keys(knexfile).forEach(function(key) {
require('./parse-connection')
require('./raw')
require('./query-builder')
require('./seed')
require('./migrate')
require('./pool')
require('./knex')
require('./parse-connection')
require('./raw')
require('./query-builder')
require('./seed')
require('./migrate')
require('./pool')
require('./knex')
Object.keys(knexfile).forEach(function(key) {
var knex = makeKnex(knexfile[key])
@ -21,9 +22,9 @@ Object.keys(knexfile).forEach(function(key) {
// Tear down the knex connection
tape(knex.client.driverName + ' - transactions: after', function(t) {
knex.destroy().then(function() {
knex.destroy(function() {
t.ok(true, 'Knex client destroyed')
t.end()
})
})
})

View File

@ -7,11 +7,11 @@ test('it should parse the connection string', function(t) {
t.plan(1)
var knexObj = knex({
client: 'mysql',
connection: "mysql://user:password@example.com/dbname"
connection: "mysql://user:password@localhost/dbname"
})
t.deepEqual(knexObj.client.config.connection, {
database: 'dbname',
host: 'example.com',
host: 'localhost',
password: 'password',
user: 'user'
})
@ -25,7 +25,7 @@ test('it should allow to use proprietary dialect', function(t) {
client: Client,
connection: {
database: 'dbname',
host: 'example.com',
host: 'localhost',
password: 'password',
user: 'user'
}
@ -35,7 +35,7 @@ test('it should allow to use proprietary dialect', function(t) {
client: Client,
connection: {
database: 'dbname',
host: 'example.com',
host: 'localhost',
password: 'password',
user: 'user'
}
@ -49,7 +49,7 @@ test('it should use knex suppoted dialect', function(t) {
client: 'postgres',
connection: {
database: 'dbname',
host: 'example.com',
host: 'localhost',
password: 'password',
user: 'user'
}
@ -58,7 +58,7 @@ test('it should use knex suppoted dialect', function(t) {
client: 'postgres',
connection: {
database: 'dbname',
host: 'example.com',
host: 'localhost',
password: 'password',
user: 'user'
}

View File

@ -2,28 +2,29 @@
var test = require('tape')
var Client = require('../../lib/dialects/sqlite3');
var Pool2 = require('pool2')
var Pool = require('generic-pool').Pool
test('#822, pool config, max: 0 should skip pool construction', function(t) {
var client = new Client({connection: {filename: ':memory:'}, pool: {max: 0}})
t.equal(client.pool, undefined)
client.destroy()
t.end()
try {
t.equal(client.pool, undefined)
t.end()
} finally {
client.destroy()
}
})
test('#823, should not skip pool construction pool config is not defined', function(t) {
var client = new Client({connection: {filename: ':memory:'}})
try {
t.ok(client.pool instanceof Pool)
t.end()
} finally {
client.destroy()
}
t.ok(client.pool instanceof Pool2)
client.destroy()
t.end()
})
})

View File

@ -14,10 +14,10 @@ module.exports = function(knex) {
setTimeout(next, 10);
}
knex.raw('select * from generate_series(0, 10, 1)').pipe(w).on('finish', function () {
console.log('finished');
t.ok(true, 'Streamed series');
t.end()
});
})
}
}
}