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

Commit 7a6cc32f by Tony Brix Committed by Sushant

feat(hooks): beforeDisconnect / afterDisconnect (#11117)

1 parent 92cb9038
......@@ -186,11 +186,13 @@ new Sequelize(..., {
### Connection Hooks
Sequelize provides two hooks that are executed immediately before and after a database connection is obtained:
Sequelize provides four hooks that are executed immediately before and after a database connection is obtained or released:
```text
beforeConnect(config)
afterConnect(connection, config)
beforeDisconnect(connection)
afterDisconnect(connection)
```
These hooks can be useful if you need to asynchronously obtain database credentials, or need to directly access the low-level database connection after it has been created.
......
......@@ -320,7 +320,9 @@ class ConnectionManager {
* @returns {Promise}
*/
_disconnect(connection) {
return this.dialect.connectionManager.disconnect(connection);
return this.sequelize.runHooks('beforeDisconnect', connection)
.then(() => this.dialect.connectionManager.disconnect(connection))
.then(() => this.sequelize.runHooks('afterDisconnect', connection));
}
/**
......
......@@ -42,6 +42,8 @@ const hookTypes = {
afterAssociate: { params: 2, sync: true },
beforeConnect: { params: 1, noModel: true },
afterConnect: { params: 2, noModel: true },
beforeDisconnect: { params: 1, noModel: true },
afterDisconnect: { params: 1, noModel: true },
beforeSync: { params: 1 },
afterSync: { params: 1 },
beforeBulkSync: { params: 1 },
......@@ -501,12 +503,28 @@ exports.applyTo = applyTo;
/**
* A hook that is run after a connection is created
* @param {string} name
* @param {Function} fn A callback function that is called with the connection object and thye config passed to connection
* @param {Function} fn A callback function that is called with the connection object and the config passed to connection
* @name afterConnect
* @memberof Sequelize
*/
/**
* A hook that is run before a connection is disconnected
* @param {string} name
* @param {Function} fn A callback function that is called with the connection object
* @name beforeDisconnect
* @memberof Sequelize
*/
/**
* A hook that is run after a connection is disconnected
* @param {string} name
* @param {Function} fn A callback function that is called with the connection object
* @name afterDisconnect
* @memberof Sequelize
*/
/**
* A hook that is run before Model.sync call
* @param {string} name
* @param {Function} fn A callback function that is called with options passed to Model.sync
......
......@@ -167,7 +167,7 @@ class Sequelize {
* @param {number} [options.retry.max] How many times a failing query is automatically retried. Set to 0 to disable retrying on SQL_BUSY error.
* @param {boolean} [options.typeValidation=false] Run built in type validators on insert and update, e.g. validate that arguments passed to integer fields are integer-like.
* @param {Object} [options.operatorsAliases] String based operator alias. Pass object to limit set of aliased operators.
* @param {Object} [options.hooks] An object of global hook functions that are called before and after certain lifecycle events. Global hooks will run after any model-specific hooks defined for the same event (See `Sequelize.Model.init()` for a list). Additionally, `beforeConnect()` and `afterConnect()` hooks may be defined here.
* @param {Object} [options.hooks] An object of global hook functions that are called before and after certain lifecycle events. Global hooks will run after any model-specific hooks defined for the same event (See `Sequelize.Model.init()` for a list). Additionally, `beforeConnect()`, `afterConnect()`, `beforeDisconnect()`, and `afterDisconnect()` hooks may be defined here.
*/
constructor(database, username, password, options) {
let config;
......
......@@ -66,4 +66,42 @@ describe('connection manager', () => {
});
});
});
describe('_disconnect', () => {
beforeEach(function() {
this.connection = {};
this.dialect = {
connectionManager: {
disconnect: sinon.stub().resolves(this.connection)
}
};
this.sequelize = Support.createSequelizeInstance();
});
it('should call beforeDisconnect', function() {
const spy = sinon.spy();
this.sequelize.beforeDisconnect(spy);
const connectionManager = new ConnectionManager(this.dialect, this.sequelize);
return connectionManager._disconnect(this.connection).then(() => {
expect(spy.callCount).to.equal(1);
expect(spy.firstCall.args[0]).to.equal(this.connection);
});
});
it('should call afterDisconnect', function() {
const spy = sinon.spy();
this.sequelize.afterDisconnect(spy);
const connectionManager = new ConnectionManager(this.dialect, this.sequelize);
return connectionManager._disconnect(this.connection).then(() => {
expect(spy.callCount).to.equal(1);
expect(spy.firstCall.args[0]).to.equal(this.connection);
});
});
});
});
......@@ -15,7 +15,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
});
it('does not expose non-model hooks', function() {
for (const badHook of ['beforeDefine', 'afterDefine', 'beforeConnect', 'afterConnect', 'beforeInit', 'afterInit']) {
for (const badHook of ['beforeDefine', 'afterDefine', 'beforeConnect', 'afterConnect', 'beforeDisconnect', 'afterDisconnect', 'beforeInit', 'afterInit']) {
expect(this.Model).to.not.have.property(badHook);
}
});
......
......@@ -54,6 +54,8 @@ export interface SequelizeHooks extends ModelHooks {
afterInit(sequelize: Sequelize): void;
beforeConnect(config: Config): HookReturn;
afterConnect(connection: unknown, config: Config): HookReturn;
beforeDisconnect(connection: unknown): HookReturn;
afterDisconnect(connection: unknown): HookReturn;
}
/**
......
......@@ -57,12 +57,12 @@ export interface SyncOptions extends Logging {
* The schema that the tables should be created in. This can be overridden for each table in sequelize.define
*/
schema?: string;
/**
* An optional parameter to specify the schema search_path (Postgres only)
*/
searchPath?: string;
/**
* If hooks is true then beforeSync, afterSync, beforeBulkSync, afterBulkSync hooks will be called
*/
......@@ -622,6 +622,24 @@ export class Sequelize extends Hooks {
public static afterConnect(fn: (connection: unknown, options: Config) => void): void;
/**
* A hook that is run before a connection is released
*
* @param name
* @param fn A callback function that is called with options
*/
public static beforeDisconnect(name: string, fn: (connection: unknown) => void): void;
public static beforeDisconnect(fn: (connection: unknown) => void): void;
/**
* A hook that is run after a connection is released
*
* @param name
* @param fn A callback function that is called with options
*/
public static afterDisconnect(name: string, fn: (connection: unknown) => void): void;
public static afterDisconnect(fn: (connection: unknown) => void): void;
/**
* A hook that is run before a find (select) query, after any { include: {all: ...} } options are expanded
*
* @param name
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!