diff --git a/lib/connection.js b/lib/connection.js index c68f20e7a48..e77e0b9b757 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -1418,6 +1418,29 @@ Connection.prototype.syncIndexes = async function syncIndexes(options = {}) { * @api public */ +/** + * Removes the database connection with the given name created with with `useDb()`. + * + * Throws an error if the database connection was not found. + * + * #### Example: + * + * // Connect to `initialdb` first + * const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/initialdb').asPromise(); + * + * // Creates an un-cached connection to `mydb` + * const db = conn.useDb('mydb'); + * + * // Closes `db`, and removes `db` from `conn.relatedDbs` and `conn.otherDbs` + * await conn.removeDb('mydb'); + * + * @method removeDb + * @memberOf Connection + * @param {String} name The database name + * @return {Connection} this + * @api public + */ + /*! * Module exports. */ diff --git a/lib/drivers/node-mongodb-native/connection.js b/lib/drivers/node-mongodb-native/connection.js index 417085be12e..42a1f25333b 100644 --- a/lib/drivers/node-mongodb-native/connection.js +++ b/lib/drivers/node-mongodb-native/connection.js @@ -126,6 +126,44 @@ NativeConnection.prototype.useDb = function(name, options) { return newConn; }; +/** + * Removes the database connection with the given name created with with `useDb()`. + * + * Throws an error if the database connection was not found. + * + * #### Example: + * + * // Connect to `initialdb` first + * const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/initialdb').asPromise(); + * + * // Creates an un-cached connection to `mydb` + * const db = conn.useDb('mydb'); + * + * // Closes `db`, and removes `db` from `conn.relatedDbs` and `conn.otherDbs` + * await conn.removeDb('mydb'); + * + * @method removeDb + * @memberOf Connection + * @param {String} name The database name + * @return {Connection} this + */ + +NativeConnection.prototype.removeDb = function removeDb(name) { + const dbs = this.otherDbs.filter(db => db.name === name); + if (!dbs.length) { + throw new MongooseError(`No connections to database "${name}" found`); + } + + for (const db of dbs) { + db._closeCalled = true; + db._destroyCalled = true; + db._readyState = STATES.disconnected; + db.$wasForceClosed = true; + } + delete this.relatedDbs[name]; + this.otherDbs = this.otherDbs.filter(db => db.name !== name); +}; + /** * Closes the connection * diff --git a/test/connection.test.js b/test/connection.test.js index db79263a74d..2365f5c3338 100644 --- a/test/connection.test.js +++ b/test/connection.test.js @@ -6,6 +6,7 @@ const start = require('./common'); +const STATES = require('../lib/connectionstate'); const Q = require('q'); const assert = require('assert'); const mongodb = require('mongodb'); @@ -746,6 +747,35 @@ describe('connections:', function() { assert.strictEqual(db2, db3); return db.close(); }); + + it('supports removing db (gh-11821)', async function() { + const db = await mongoose.createConnection(start.uri).asPromise(); + + const schema = mongoose.Schema({ name: String }, { autoCreate: false, autoIndex: false }); + const Test = db.model('Test', schema); + await Test.deleteMany({}); + await Test.create({ name: 'gh-11821' }); + + const db2 = db.useDb(start.databases[1]); + const Test2 = db2.model('Test', schema); + + await Test2.deleteMany({}); + let doc = await Test2.findOne(); + assert.equal(doc, null); + + db.removeDb(start.databases[1]); + assert.equal(db2.readyState, STATES.disconnected); + assert.equal(db.readyState, STATES.connected); + await assert.rejects( + () => Test2.findOne(), + /Connection was force closed/ + ); + + doc = await Test.findOne(); + assert.equal(doc.name, 'gh-11821'); + + await db.close(); + }); }); describe('shouldAuthenticate()', function() {