不要怂,就是干,撸起袖子干!

Commit 2a78517d by Sushant Committed by GitHub

Generic Pool Update (#7109)

* generic pool update and other fixes

* connection internally removed

* doc entry

* review changes

* pooling changes
1 parent ee8194e5
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
- [FIXED] Enforce unique association aliases [#7025](https://github.com/sequelize/sequelize/pull/7025) - [FIXED] Enforce unique association aliases [#7025](https://github.com/sequelize/sequelize/pull/7025)
- [FIXED] Information warnings when findAll is given incorrect inputs [#7047](https://github.com/sequelize/sequelize/pull/7047) - [FIXED] Information warnings when findAll is given incorrect inputs [#7047](https://github.com/sequelize/sequelize/pull/7047)
- [FIXED] scope method syntax loses parameters when used multiple times [#7058](https://github.com/sequelize/sequelize/issues/7058) - [FIXED] scope method syntax loses parameters when used multiple times [#7058](https://github.com/sequelize/sequelize/issues/7058)
- [INTERNAL] Updated to `generic-pool@3.1.6` [#7109](https://github.com/sequelize/sequelize/issues/7109)
## BC breaks: ## BC breaks:
- `DATEONLY` now returns string in `YYYY-MM-DD` format rather than `Date` type - `DATEONLY` now returns string in `YYYY-MM-DD` format rather than `Date` type
......
...@@ -6,15 +6,17 @@ const _ = require('lodash'); ...@@ -6,15 +6,17 @@ const _ = require('lodash');
const Utils = require('../../utils'); const Utils = require('../../utils');
const debug = Utils.getLogger().debugContext('pool'); const debug = Utils.getLogger().debugContext('pool');
const semver = require('semver'); const semver = require('semver');
const timers = require('timers');
const defaultPoolingConfig = { const defaultPoolingConfig = {
max: 5, max: 5,
min: 0, min: 0,
idle: 10000, idle: 10000,
acquire: 10000,
handleDisconnects: true handleDisconnects: true
}; };
class ConnectionManager { class ConnectionManager {
constructor(dialect, sequelize) { constructor(dialect, sequelize) {
const config = _.cloneDeep(sequelize.config); const config = _.cloneDeep(sequelize.config);
...@@ -22,24 +24,28 @@ class ConnectionManager { ...@@ -22,24 +24,28 @@ class ConnectionManager {
this.config = config; this.config = config;
this.dialect = dialect; this.dialect = dialect;
this.versionPromise = null; this.versionPromise = null;
this.poolError = null;
this.dialectName = this.sequelize.options.dialect; this.dialectName = this.sequelize.options.dialect;
if (config.pool !== false) { if (config.pool === false) {
config.pool =_.defaults(config.pool || {}, defaultPoolingConfig, {
validate: this._validate.bind(this)
}) ;
} else {
throw new Error('Support for pool:false was removed in v4.0'); throw new Error('Support for pool:false was removed in v4.0');
} }
config.pool =_.defaults(config.pool || {}, defaultPoolingConfig, {
validate: this._validate.bind(this),
Promise
}) ;
// Save a reference to the bound version so we can remove it with removeListener // Save a reference to the bound version so we can remove it with removeListener
this.onProcessExit = this.onProcessExit.bind(this); this.onProcessExit = this.onProcessExit.bind(this);
process.on('exit', this.onProcessExit); process.on('exit', this.onProcessExit);
this.initPools();
} }
refreshTypeParser(dataTypes) { refreshTypeParser(dataTypes) {
_.each(dataTypes, (dataType, key) => { _.each(dataTypes, (dataType) => {
if (dataType.hasOwnProperty('parse')) { if (dataType.hasOwnProperty('parse')) {
if (dataType.types[this.dialectName]) { if (dataType.types[this.dialectName]) {
this._refreshTypeParser(dataType); this._refreshTypeParser(dataType);
...@@ -51,47 +57,68 @@ class ConnectionManager { ...@@ -51,47 +57,68 @@ class ConnectionManager {
} }
onProcessExit() { onProcessExit() {
if (this.pool) { if (!this.pool) {
this.pool.drain(() => { return Promise.resolve();
}
return this.pool.drain(() => {
debug('connection drain due to process exit'); debug('connection drain due to process exit');
this.pool.destroyAllNow(); return this.pool.clear();
}); });
} }
}
close() { close() {
this.onProcessExit(); // Remove the listener, so all references to this instance can be garbage collected.
process.removeListener('exit', this.onProcessExit); // Remove the listener, so all references to this instance can be garbage collected. process.removeListener('exit', this.onProcessExit);
// Mark close of pool
this.getConnection = function getConnection() { this.getConnection = function getConnection() {
return Promise.reject(new Error('ConnectionManager.getConnection was called after the connection manager was closed!')); return Promise.reject(new Error('ConnectionManager.getConnection was called after the connection manager was closed!'));
}; };
return this.onProcessExit();
} }
// This cannot happen in the constructor because the user can specify a min. number of connections to have in the pool
// If he does this, generic-pool will try to call connect before the dialect-specific connection manager has been correctly set up
initPools() { initPools() {
const config = this.config; const config = this.config;
if (!config.replication) { if (!config.replication) {
this.pool = Pooling.Pool({ this.pool = Pooling.createPool({
name: 'sequelize-connection', create: () => new Promise((resolve) => {
create: (callback) => { this
this._connect(config).nodeify((err, connection) => { ._connect(config)
debug(`pool created max/min: ${config.pool.max}/${config.pool.min} with no replication`); .tap(() => {
callback(err, connection); // For some reason this is needed, else generic-pool things err is a connection or some shit this.poolError = null;
})
.then(resolve)
.catch(e => {
// dont throw otherwise pool will release _dispense call
// which will call _connect even if error is fatal
// https://github.com/coopernurse/node-pool/issues/161
this.poolError = e;
}); });
}, }),
destroy: (connection) => { destroy: (connection) => {
return this._disconnect(connection).tap(() => {
debug('connection destroy'); debug('connection destroy');
this._disconnect(connection); });
return null;
}, },
validate: config.pool.validate
}, {
Promise: config.pool.Promise,
max: config.pool.max, max: config.pool.max,
min: config.pool.min, min: config.pool.min,
validate: config.pool.validate, testOnBorrow: true,
autostart: false,
acquireTimeoutMillis: config.pool.acquire,
idleTimeoutMillis: config.pool.idle idleTimeoutMillis: config.pool.idle
}); });
this.pool.on('factoryCreateError', error => {
this.poolError = error;
});
debug(`pool created max/min: ${config.pool.max}/${config.pool.min} with no replication`);
return; return;
} }
...@@ -109,7 +136,7 @@ class ConnectionManager { ...@@ -109,7 +136,7 @@ class ConnectionManager {
_.defaults(readConfig, _.omit(this.config, 'replication')) _.defaults(readConfig, _.omit(this.config, 'replication'))
); );
// I'll make my own pool, with blackjack and hookers! (original credit goes to @janzeh) // custom pooling for replication (original author @janmeier)
this.pool = { this.pool = {
release: client => { release: client => {
if (client.queryType === 'read') { if (client.queryType === 'read') {
...@@ -118,67 +145,95 @@ class ConnectionManager { ...@@ -118,67 +145,95 @@ class ConnectionManager {
return this.pool.write.release(client); return this.pool.write.release(client);
} }
}, },
acquire: (callback, priority, queryType, useMaster) => { acquire: (priority, queryType, useMaster) => {
useMaster = _.isUndefined(useMaster) ? false : useMaster; useMaster = _.isUndefined(useMaster) ? false : useMaster;
if (queryType === 'SELECT' && !useMaster) { if (queryType === 'SELECT' && !useMaster) {
this.pool.read.acquire(callback, priority); return this.pool.read.acquire(priority);
} else { } else {
this.pool.write.acquire(callback, priority); return this.pool.write.acquire(priority);
} }
}, },
destroy: (connection) => { destroy: connection => {
debug('connection destroy'); debug('connection destroy');
return this.pool[connection.queryType].destroy(connection); return this.pool[connection.queryType].destroy(connection);
}, },
destroyAllNow: () => { clear: () => {
debug('all connection destroy'); debug('all connection clear');
this.pool.read.destroyAllNow(); return Promise.join(
this.pool.write.destroyAllNow(); this.pool.read.clear(),
this.pool.write.clear()
);
}, },
drain: (cb) => { drain: () => {
this.pool.write.drain(() => { return Promise.join(
this.pool.read.drain(cb); this.pool.write.drain(),
}); this.pool.read.drain()
);
}, },
read: Pooling.Pool({ read: Pooling.createPool({
name: 'sequelize-connection-read', create: () => {
create: (callback) => { const nextRead = reads++ % config.replication.read.length; // round robin config
// Simple round robin config return new Promise((resolve) => {
const nextRead = reads++ % config.replication.read.length; this
this._connect(config.replication.read[nextRead]).tap(connection => { ._connect(config.replication.read[nextRead])
.tap(connection => {
connection.queryType = 'read'; connection.queryType = 'read';
}).nodeify((err, connection) => { this.poolError = null;
callback(err, connection); // For some reason this is needed, else generic-pool things err is a connection or some shit resolve(connection);
})
.catch(e => {
this.poolError = e;
});
}); });
}, },
destroy: connection => { destroy: connection => {
this._disconnect(connection); return this._disconnect(connection);
return null;
}, },
validate: config.pool.validate, validate: config.pool.validate
}, {
Promise: config.pool.Promise,
max: config.pool.max, max: config.pool.max,
min: config.pool.min, min: config.pool.min,
testOnBorrow: true,
autostart: false,
acquireTimeoutMillis: config.pool.acquire,
idleTimeoutMillis: config.pool.idle idleTimeoutMillis: config.pool.idle
}), }),
write: Pooling.Pool({ write: Pooling.createPool({
name: 'sequelize-connection-write', create: () => new Promise((resolve) => {
create: callback => { this
this._connect(config.replication.write).tap(connection => { ._connect(config.replication.write)
.then(connection => {
connection.queryType = 'write'; connection.queryType = 'write';
}).nodeify((err, connection) => { this.poolError = null;
callback(err, connection); // For some reason this is needed, else generic-pool things err is a connection or some shit return resolve(connection);
})
.catch(e => {
this.poolError = e;
}); });
}, }),
destroy: connection => { destroy: connection => {
this._disconnect(connection); return this._disconnect(connection);
return null;
}, },
validate: config.pool.validate, validate: config.pool.validate
}, {
Promise: config.pool.Promise,
max: config.pool.max, max: config.pool.max,
min: config.pool.min, min: config.pool.min,
testOnBorrow: true,
autostart: false,
acquireTimeoutMillis: config.pool.acquire,
idleTimeoutMillis: config.pool.idle idleTimeoutMillis: config.pool.idle
}) })
}; };
this.pool.read.on('factoryCreateError', error => {
this.poolError = error;
});
this.pool.write.on('factoryCreateError', error => {
this.poolError = error;
});
} }
getConnection(options) { getConnection(options) {
...@@ -197,11 +252,9 @@ class ConnectionManager { ...@@ -197,11 +252,9 @@ class ConnectionManager {
return this.sequelize.databaseVersion(_options).then(version => { return this.sequelize.databaseVersion(_options).then(version => {
this.sequelize.options.databaseVersion = semver.valid(version) ? version : this.defaultVersion; this.sequelize.options.databaseVersion = semver.valid(version) ? version : this.defaultVersion;
this.versionPromise = null; this.versionPromise = null;
this._disconnect(connection); return this._disconnect(connection);
return null;
}); });
}).catch(err => { }).catch(err => {
this.versionPromise = null; this.versionPromise = null;
...@@ -212,20 +265,36 @@ class ConnectionManager { ...@@ -212,20 +265,36 @@ class ConnectionManager {
promise = Promise.resolve(); promise = Promise.resolve();
} }
return promise.then(() => new Promise((resolve, reject) => { return promise.then(() =>
this.pool.acquire((err, connection) => { new Promise((resolve, reject) => {
if (err) return reject(err); const connectionPromise = this.pool.acquire(options.priority, options.type, options.useMaster);
debug('connection acquired'); const connectionTimer = timers.setInterval(() => {
resolve(connection); let evictTimer = false;
}, options.priority, options.type, options.useMaster);
})); if (connectionPromise.isFulfilled()) {
resolve(connectionPromise);
debug('connection acquire');
evictTimer = true;
} else if (this.poolError) {
reject(this.poolError);
this.poolError = null;
evictTimer = true;
} else if (connectionPromise.isRejected()) {
connectionPromise.catch(reject);
evictTimer = true;
}
if (evictTimer) {
timers.clearInterval(connectionTimer);
}
}, 0);
})
);
} }
releaseConnection(connection) { releaseConnection(connection) {
return new Promise((resolve, reject) => { return this.pool.release(connection).tap(() => {
this.pool.release(connection);
debug('connection released'); debug('connection released');
resolve();
}); });
} }
......
...@@ -130,7 +130,7 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -130,7 +130,7 @@ class ConnectionManager extends AbstractConnectionManager {
const connection = connectionLock.unwrap(); const connection = connectionLock.unwrap();
// Dont disconnect a connection that is already disconnected // Dont disconnect a connection that is already disconnected
if (!!connection.closed) { if (connection.closed) {
return Promise.resolve(); return Promise.resolve();
} }
...@@ -143,7 +143,6 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -143,7 +143,6 @@ class ConnectionManager extends AbstractConnectionManager {
validate(connectionLock) { validate(connectionLock) {
const connection = connectionLock.unwrap(); const connection = connectionLock.unwrap();
return connection && connection.loggedIn; return connection && connection.loggedIn;
} }
} }
......
'use strict'; 'use strict';
var _ = require('lodash') const _ = require('lodash');
, Abstract = require('../abstract') const AbstractDialect = require('../abstract');
, ConnectionManager = require('./connection-manager') const ConnectionManager = require('./connection-manager');
, Query = require('./query') const Query = require('./query');
, QueryGenerator = require('./query-generator') const QueryGenerator = require('./query-generator');
, DataTypes = require('../../data-types').mssql; const DataTypes = require('../../data-types').mssql;
var MssqlDialect = function(sequelize) { class MssqlDialect extends AbstractDialect {
constructor(sequelize) {
super();
this.sequelize = sequelize; this.sequelize = sequelize;
this.connectionManager = new ConnectionManager(this, sequelize); this.connectionManager = new ConnectionManager(this, sequelize);
this.connectionManager.initPools();
this.QueryGenerator = _.extend({}, QueryGenerator, { this.QueryGenerator = _.extend({}, QueryGenerator, {
options: sequelize.options, options: sequelize.options,
_dialect: this, _dialect: this,
sequelize sequelize
}); });
}; }
}
MssqlDialect.prototype.supports = _.merge(_.cloneDeep(Abstract.prototype.supports), { MssqlDialect.prototype.supports = _.merge(_.cloneDeep(AbstractDialect.prototype.supports), {
'DEFAULT': true, 'DEFAULT': true,
'DEFAULT VALUES': true, 'DEFAULT VALUES': true,
'LIMIT ON UPDATE': true, 'LIMIT ON UPDATE': true,
...@@ -51,7 +53,7 @@ MssqlDialect.prototype.supports = _.merge(_.cloneDeep(Abstract.prototype.support ...@@ -51,7 +53,7 @@ MssqlDialect.prototype.supports = _.merge(_.cloneDeep(Abstract.prototype.support
tmpTableTrigger: true tmpTableTrigger: true
}); });
MssqlDialect.prototype.defaultVersion = '12.0.2000'; // SQL Server 2014 Express ConnectionManager.prototype.defaultVersion = '12.0.2000'; // SQL Server 2014 Express
MssqlDialect.prototype.Query = Query; MssqlDialect.prototype.Query = Query;
MssqlDialect.prototype.name = 'mssql'; MssqlDialect.prototype.name = 'mssql';
MssqlDialect.prototype.TICK_CHAR = '"'; MssqlDialect.prototype.TICK_CHAR = '"';
......
'use strict'; 'use strict';
var _ = require('lodash') const _ = require('lodash');
, Abstract = require('../abstract') const AbstractDialect = require('../abstract');
, ConnectionManager = require('./connection-manager') const ConnectionManager = require('./connection-manager');
, Query = require('./query') const Query = require('./query');
, QueryGenerator = require('./query-generator') const QueryGenerator = require('./query-generator');
, DataTypes = require('../../data-types').mysql; const DataTypes = require('../../data-types').mysql;
var MysqlDialect = function(sequelize) { class MysqlDialect extends AbstractDialect {
constructor(sequelize) {
super();
this.sequelize = sequelize; this.sequelize = sequelize;
this.connectionManager = new ConnectionManager(this, sequelize); this.connectionManager = new ConnectionManager(this, sequelize);
this.connectionManager.initPools();
this.QueryGenerator = _.extend({}, QueryGenerator, { this.QueryGenerator = _.extend({}, QueryGenerator, {
options: sequelize.options, options: sequelize.options,
_dialect: this, _dialect: this,
sequelize sequelize
}); });
}; }
}
MysqlDialect.prototype.supports = _.merge(_.cloneDeep(Abstract.prototype.supports), { MysqlDialect.prototype.supports = _.merge(_.cloneDeep(AbstractDialect.prototype.supports), {
'VALUES ()': true, 'VALUES ()': true,
'LIMIT ON UPDATE': true, 'LIMIT ON UPDATE': true,
'IGNORE': ' IGNORE', 'IGNORE': ' IGNORE',
......
...@@ -45,8 +45,8 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -45,8 +45,8 @@ class ConnectionManager extends AbstractConnectionManager {
if (dataType.types.postgres.array_oids) { if (dataType.types.postgres.array_oids) {
for (const oid of dataType.types.postgres.array_oids) { for (const oid of dataType.types.postgres.array_oids) {
this.lib.types.setTypeParser(oid, value => this.lib.types.setTypeParser(oid, value =>
this.lib.types.arrayParser.create(value, value => this.lib.types.arrayParser.create(value, (v) =>
dataType.parse(value, oid, this.lib.types.getTypeParser) dataType.parse(v, oid, this.lib.types.getTypeParser)
).parse() ).parse()
); );
} }
...@@ -172,7 +172,7 @@ class ConnectionManager extends AbstractConnectionManager { ...@@ -172,7 +172,7 @@ class ConnectionManager extends AbstractConnectionManager {
}); });
} }
disconnect(connection) { disconnect(connection) {
return new Promise((resolve, reject) => { return new Promise(resolve => {
connection.end(); connection.end();
resolve(); resolve();
}); });
......
...@@ -12,8 +12,6 @@ class PostgresDialect extends AbstractDialect { ...@@ -12,8 +12,6 @@ class PostgresDialect extends AbstractDialect {
super(); super();
this.sequelize = sequelize; this.sequelize = sequelize;
this.connectionManager = new ConnectionManager(this, sequelize); this.connectionManager = new ConnectionManager(this, sequelize);
this.connectionManager.initPools();
this.QueryGenerator = _.extend({}, QueryGenerator, { this.QueryGenerator = _.extend({}, QueryGenerator, {
options: sequelize.options, options: sequelize.options,
_dialect: this, _dialect: this,
......
...@@ -84,7 +84,8 @@ const _ = require('lodash'); ...@@ -84,7 +84,8 @@ const _ = require('lodash');
* @param {Integer} [options.pool.max] Maximum number of connection in pool. Default is 5 * @param {Integer} [options.pool.max] Maximum number of connection in pool. Default is 5
* @param {Integer} [options.pool.min] Minimum number of connection in pool. Default is 0 * @param {Integer} [options.pool.min] Minimum number of connection in pool. Default is 0
* @param {Integer} [options.pool.idle] The maximum time, in milliseconds, that a connection can be idle before being released * @param {Integer} [options.pool.idle] The maximum time, in milliseconds, that a connection can be idle before being released
* @param {Function} [options.pool.validateConnection] A function that validates a connection. Called with client. The default function checks that client is an object, and that its state is not disconnected * @param {Integer} [options.pool.acquire] The maximum time, in milliseconds, that pool will try to get connection before throwing error
* @param {Function} [options.pool.validate] A function that validates a connection. Called with client. The default function checks that client is an object, and that its state is not disconnected
* @param {Boolean} [options.quoteIdentifiers=true] Set to `false` to make table names and attributes case-insensitive on Postgres and skip double quoting of them. * @param {Boolean} [options.quoteIdentifiers=true] Set to `false` to make table names and attributes case-insensitive on Postgres and skip double quoting of them.
* @param {String} [options.transactionType='DEFERRED'] Set the default transaction type. See `Sequelize.Transaction.TYPES` for possible options. Sqlite only. * @param {String} [options.transactionType='DEFERRED'] Set the default transaction type. See `Sequelize.Transaction.TYPES` for possible options. Sqlite only.
* @param {String} [options.isolationLevel] Set the default transaction isolation level. See `Sequelize.Transaction.ISOLATION_LEVELS` for possible options. * @param {String} [options.isolationLevel] Set the default transaction isolation level. See `Sequelize.Transaction.ISOLATION_LEVELS` for possible options.
...@@ -265,10 +266,6 @@ class Sequelize { ...@@ -265,10 +266,6 @@ class Sequelize {
Sequelize.runHooks('afterInit', this); Sequelize.runHooks('afterInit', this);
} }
get connectorManager() {
return this.transactionManager.getConnectorManager();
}
refreshTypes() { refreshTypes() {
this.connectionManager.refreshTypeParser(DataTypes); this.connectionManager.refreshTypeParser(DataTypes);
} }
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
"depd": "^1.1.0", "depd": "^1.1.0",
"dottie": "^2.0.0", "dottie": "^2.0.0",
"env-cmd": "^4.0.0", "env-cmd": "^4.0.0",
"generic-pool": "^2.4.4", "generic-pool": "^3.1.6",
"inflection": "1.10.0", "inflection": "1.10.0",
"lodash": "^4.17.1", "lodash": "^4.17.1",
"moment": "^2.13.0", "moment": "^2.13.0",
......
...@@ -18,7 +18,7 @@ var poolEntry = { ...@@ -18,7 +18,7 @@ var poolEntry = {
pool: {} pool: {}
}; };
describe('Connction Manager', function() { describe('Connection Manager', function() {
var sandbox; var sandbox;
...@@ -37,7 +37,7 @@ describe('Connction Manager', function() { ...@@ -37,7 +37,7 @@ describe('Connction Manager', function() {
var sequelize = Support.createSequelizeInstance(options); var sequelize = Support.createSequelizeInstance(options);
var connectionManager = new ConnectionManager(Support.getTestDialect(), sequelize); var connectionManager = new ConnectionManager(Support.getTestDialect(), sequelize);
var poolSpy = sandbox.spy(Pooling, 'Pool'); var poolSpy = sandbox.spy(Pooling, 'createPool');
connectionManager.initPools(); connectionManager.initPools();
expect(poolSpy.calledOnce).to.be.true; expect(poolSpy.calledOnce).to.be.true;
}); });
...@@ -52,7 +52,7 @@ describe('Connction Manager', function() { ...@@ -52,7 +52,7 @@ describe('Connction Manager', function() {
var sequelize = Support.createSequelizeInstance(options); var sequelize = Support.createSequelizeInstance(options);
var connectionManager = new ConnectionManager(Support.getTestDialect(), sequelize); var connectionManager = new ConnectionManager(Support.getTestDialect(), sequelize);
var poolSpy = sandbox.spy(Pooling, 'Pool'); var poolSpy = sandbox.spy(Pooling, 'createPool');
connectionManager.initPools(); connectionManager.initPools();
expect(poolSpy.calledTwice).to.be.true; expect(poolSpy.calledTwice).to.be.true;
}); });
......
...@@ -22,10 +22,8 @@ if (dialect.match(/^mssql/)) { ...@@ -22,10 +22,8 @@ if (dialect.match(/^mssql/)) {
conn = connection; conn = connection;
// simulate a unexpected end // simulate a unexpected end
connection.unwrap().emit('error', {code: 'ECONNRESET'}); // connection removed from pool by MSSQL Conn Manager
}) conn.unwrap().emit('error', {code: 'ECONNRESET'});
.then(function() {
return cm.releaseConnection(conn);
}) })
.then(function() { .then(function() {
// Get next available connection // Get next available connection
......
...@@ -9,7 +9,7 @@ var chai = require('chai') ...@@ -9,7 +9,7 @@ var chai = require('chai')
, DataTypes = require(__dirname + '/../../../../lib/data-types'); , DataTypes = require(__dirname + '/../../../../lib/data-types');
if (dialect === 'mysql') { if (dialect === 'mysql') {
describe('[MYSQL Specific] Connector Manager', function() { describe('[MYSQL Specific] Connection Manager', function() {
it('works correctly after being idle', function() { it('works correctly after being idle', function() {
var User = this.sequelize.define('User', { username: DataTypes.STRING }) var User = this.sequelize.define('User', { username: DataTypes.STRING })
, spy = sinon.spy() , spy = sinon.spy()
......
'use strict';
/* jshint -W030 */
/* jshint -W110 */
const chai = require('chai');
const expect = chai.expect;
const Support = require(__dirname + '/support');
const dialect = Support.getTestDialect();
const sinon = require('sinon');
const Sequelize = Support.Sequelize;
describe(Support.getTestDialectTeaser('Pooling'), function() {
if (dialect === 'sqlite') return;
beforeEach(() => {
this.sinon = sinon.sandbox.create();
});
afterEach(() => {
this.sinon.restore();
});
it('should reject when unable to acquire connection in given time', () => {
this.testInstance = new Sequelize('localhost', 'ffd', 'dfdf', {
dialect,
databaseVersion: '1.2.3',
pool: {
acquire: 1000 //milliseconds
}
});
this.sinon.stub(this.testInstance.connectionManager, '_connect', () => new Sequelize.Promise(() => {}));
return expect(this.testInstance.authenticate())
.to.eventually.be.rejectedWith('TimeoutError: ResourceRequest timed out');
});
});
...@@ -2,16 +2,16 @@ ...@@ -2,16 +2,16 @@
/* jshint -W030 */ /* jshint -W030 */
/* jshint -W110 */ /* jshint -W110 */
var chai = require('chai') const chai = require('chai');
, expect = chai.expect const expect = chai.expect;
, Support = require(__dirname + '/support') const Support = require(__dirname + '/support');
, DataTypes = require(__dirname + '/../../lib/data-types') const DataTypes = require(__dirname + '/../../lib/data-types');
, dialect = Support.getTestDialect(); const dialect = Support.getTestDialect();
describe(Support.getTestDialectTeaser('Replication'), function() { describe(Support.getTestDialectTeaser('Replication'), function() {
if (dialect === 'sqlite') return; if (dialect === 'sqlite') return;
beforeEach(function () { beforeEach(() => {
this.sequelize = Support.getSequelizeInstance(null, null, null, { this.sequelize = Support.getSequelizeInstance(null, null, null, {
replication: { replication: {
write: Support.getConnectionOptions(), write: Support.getConnectionOptions(),
...@@ -32,13 +32,13 @@ describe(Support.getTestDialectTeaser('Replication'), function() { ...@@ -32,13 +32,13 @@ describe(Support.getTestDialectTeaser('Replication'), function() {
return this.User.sync({force: true}); return this.User.sync({force: true});
}); });
it('should be able to make a write', function () { it('should be able to make a write', () => {
return this.User.create({ return this.User.create({
firstName: Math.random().toString() firstName: Math.random().toString()
}); });
}); });
it('should be able to make a read', function () { it('should be able to make a read', () => {
return this.User.findAll(); return this.User.findAll();
}); });
}); });
'use strict'; 'use strict';
/* jshint -W030 */ /* jshint -W030 */
var chai = require('chai') const chai = require('chai');
, expect = chai.expect const expect = chai.expect;
, sinon = require('sinon') const sinon = require('sinon');
, Support = require(__dirname + '/support') const Support = require(__dirname + '/support');
, Sequelize = Support.Sequelize const Sequelize = Support.Sequelize;
, dialect = Support.getTestDialect() const dialect = Support.getTestDialect();
, current = Support.sequelize const current = Support.sequelize;
, Promise = Sequelize.Promise;
describe('Transaction', function() { describe('Transaction', function() {
before(() => {
before(function () { this.stub = sinon.stub(current, 'query').returns(Sequelize.Promise.resolve({}));
this.stub = sinon.stub(current, 'query').returns(Promise.resolve({}));
this.stubConnection = sinon.stub(current.connectionManager, 'getConnection') this.stubConnection = sinon.stub(current.connectionManager, 'getConnection')
.returns(Promise.resolve({ uuid: 'ssfdjd-434fd-43dfg23-2d', close : function() { }})); .returns(Sequelize.Promise.resolve({
uuid: 'ssfdjd-434fd-43dfg23-2d',
close(){}
}));
this.stubRelease = sinon.stub(current.connectionManager, 'releaseConnection')
.returns(Sequelize.Promise.resolve());
}); });
beforeEach(function () { beforeEach(() => {
this.stub.reset(); this.stub.reset();
this.stubConnection.reset(); this.stubConnection.reset();
this.stubRelease.reset();
}); });
after(function () { after(() => {
this.stub.restore(); this.stub.restore();
this.stubConnection.restore(); this.stubConnection.restore();
}); });
it('should run auto commit query only when needed', function() { it('should run auto commit query only when needed', () => {
var expectations = { const expectations = {
all: [ all: [
'START TRANSACTION;' 'START TRANSACTION;'
], ],
...@@ -43,7 +48,7 @@ describe('Transaction', function() { ...@@ -43,7 +48,7 @@ describe('Transaction', function() {
}; };
return current.transaction(() => { return current.transaction(() => {
expect(this.stub.args.map(arg => arg[0])).to.deep.equal(expectations[dialect] || expectations.all); expect(this.stub.args.map(arg => arg[0])).to.deep.equal(expectations[dialect] || expectations.all);
return Promise.resolve(); return Sequelize.Promise.resolve();
}); });
}); });
}); });
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!