Skip to content

Commit 7a6cc32

Browse files
UziTechsushantdhiman
authored andcommitted
feat(hooks): beforeDisconnect / afterDisconnect (#11117)
1 parent 92cb903 commit 7a6cc32

File tree

8 files changed

+87
-7
lines changed

8 files changed

+87
-7
lines changed

docs/hooks.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,13 @@ new Sequelize(..., {
186186

187187
### Connection Hooks
188188

189-
Sequelize provides two hooks that are executed immediately before and after a database connection is obtained:
189+
Sequelize provides four hooks that are executed immediately before and after a database connection is obtained or released:
190190

191191
```text
192192
beforeConnect(config)
193193
afterConnect(connection, config)
194+
beforeDisconnect(connection)
195+
afterDisconnect(connection)
194196
```
195197

196198
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.

lib/dialects/abstract/connection-manager.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,9 @@ class ConnectionManager {
320320
* @returns {Promise}
321321
*/
322322
_disconnect(connection) {
323-
return this.dialect.connectionManager.disconnect(connection);
323+
return this.sequelize.runHooks('beforeDisconnect', connection)
324+
.then(() => this.dialect.connectionManager.disconnect(connection))
325+
.then(() => this.sequelize.runHooks('afterDisconnect', connection));
324326
}
325327

326328
/**

lib/hooks.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ const hookTypes = {
4242
afterAssociate: { params: 2, sync: true },
4343
beforeConnect: { params: 1, noModel: true },
4444
afterConnect: { params: 2, noModel: true },
45+
beforeDisconnect: { params: 1, noModel: true },
46+
afterDisconnect: { params: 1, noModel: true },
4547
beforeSync: { params: 1 },
4648
afterSync: { params: 1 },
4749
beforeBulkSync: { params: 1 },
@@ -501,11 +503,27 @@ exports.applyTo = applyTo;
501503
/**
502504
* A hook that is run after a connection is created
503505
* @param {string} name
504-
* @param {Function} fn A callback function that is called with the connection object and thye config passed to connection
506+
* @param {Function} fn A callback function that is called with the connection object and the config passed to connection
505507
* @name afterConnect
506508
* @memberof Sequelize
507509
*/
508510

511+
/**
512+
* A hook that is run before a connection is disconnected
513+
* @param {string} name
514+
* @param {Function} fn A callback function that is called with the connection object
515+
* @name beforeDisconnect
516+
* @memberof Sequelize
517+
*/
518+
519+
/**
520+
* A hook that is run after a connection is disconnected
521+
* @param {string} name
522+
* @param {Function} fn A callback function that is called with the connection object
523+
* @name afterDisconnect
524+
* @memberof Sequelize
525+
*/
526+
509527
/**
510528
* A hook that is run before Model.sync call
511529
* @param {string} name

lib/sequelize.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class Sequelize {
167167
* @param {number} [options.retry.max] How many times a failing query is automatically retried. Set to 0 to disable retrying on SQL_BUSY error.
168168
* @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.
169169
* @param {Object} [options.operatorsAliases] String based operator alias. Pass object to limit set of aliased operators.
170-
* @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.
170+
* @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.
171171
*/
172172
constructor(database, username, password, options) {
173173
let config;

test/unit/connection-manager.test.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,42 @@ describe('connection manager', () => {
6666
});
6767
});
6868
});
69+
70+
describe('_disconnect', () => {
71+
beforeEach(function() {
72+
this.connection = {};
73+
74+
this.dialect = {
75+
connectionManager: {
76+
disconnect: sinon.stub().resolves(this.connection)
77+
}
78+
};
79+
80+
this.sequelize = Support.createSequelizeInstance();
81+
});
82+
83+
it('should call beforeDisconnect', function() {
84+
const spy = sinon.spy();
85+
this.sequelize.beforeDisconnect(spy);
86+
87+
const connectionManager = new ConnectionManager(this.dialect, this.sequelize);
88+
89+
return connectionManager._disconnect(this.connection).then(() => {
90+
expect(spy.callCount).to.equal(1);
91+
expect(spy.firstCall.args[0]).to.equal(this.connection);
92+
});
93+
});
94+
95+
it('should call afterDisconnect', function() {
96+
const spy = sinon.spy();
97+
this.sequelize.afterDisconnect(spy);
98+
99+
const connectionManager = new ConnectionManager(this.dialect, this.sequelize);
100+
101+
return connectionManager._disconnect(this.connection).then(() => {
102+
expect(spy.callCount).to.equal(1);
103+
expect(spy.firstCall.args[0]).to.equal(this.connection);
104+
});
105+
});
106+
});
69107
});

test/unit/hooks.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe(Support.getTestDialectTeaser('Hooks'), () => {
1515
});
1616

1717
it('does not expose non-model hooks', function() {
18-
for (const badHook of ['beforeDefine', 'afterDefine', 'beforeConnect', 'afterConnect', 'beforeInit', 'afterInit']) {
18+
for (const badHook of ['beforeDefine', 'afterDefine', 'beforeConnect', 'afterConnect', 'beforeDisconnect', 'afterDisconnect', 'beforeInit', 'afterInit']) {
1919
expect(this.Model).to.not.have.property(badHook);
2020
}
2121
});

types/lib/hooks.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ export interface SequelizeHooks extends ModelHooks {
5454
afterInit(sequelize: Sequelize): void;
5555
beforeConnect(config: Config): HookReturn;
5656
afterConnect(connection: unknown, config: Config): HookReturn;
57+
beforeDisconnect(connection: unknown): HookReturn;
58+
afterDisconnect(connection: unknown): HookReturn;
5759
}
5860

5961
/**

types/lib/sequelize.d.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ export interface SyncOptions extends Logging {
5757
* The schema that the tables should be created in. This can be overridden for each table in sequelize.define
5858
*/
5959
schema?: string;
60-
60+
6161
/**
6262
* An optional parameter to specify the schema search_path (Postgres only)
6363
*/
6464
searchPath?: string;
65-
65+
6666
/**
6767
* If hooks is true then beforeSync, afterSync, beforeBulkSync, afterBulkSync hooks will be called
6868
*/
@@ -621,6 +621,24 @@ export class Sequelize extends Hooks {
621621
public static afterConnect(name: string, fn: (connection: unknown, options: Config) => void): void;
622622
public static afterConnect(fn: (connection: unknown, options: Config) => void): void;
623623

624+
/**
625+
* A hook that is run before a connection is released
626+
*
627+
* @param name
628+
* @param fn A callback function that is called with options
629+
*/
630+
public static beforeDisconnect(name: string, fn: (connection: unknown) => void): void;
631+
public static beforeDisconnect(fn: (connection: unknown) => void): void;
632+
633+
/**
634+
* A hook that is run after a connection is released
635+
*
636+
* @param name
637+
* @param fn A callback function that is called with options
638+
*/
639+
public static afterDisconnect(name: string, fn: (connection: unknown) => void): void;
640+
public static afterDisconnect(fn: (connection: unknown) => void): void;
641+
624642
/**
625643
* A hook that is run before a find (select) query, after any { include: {all: ...} } options are expanded
626644
*

0 commit comments

Comments
 (0)