From ccfefd83664f0580a903a2f5800e98d56002a045 Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:25:23 -0400 Subject: [PATCH 1/2] feat: `listDatabases()` function --- lib/connection.js | 8 ++++++++ test/connection.test.js | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/connection.js b/lib/connection.js index 05ff52461b0..51b85ceaec2 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -647,6 +647,14 @@ Connection.prototype.listCollections = async function listCollections() { return await cursor.toArray(); }; +Connection.prototype.listDatabases = async function listDatabases() { + if (this.client) { + return this.client.db().admin().listDatabases(); + } else { + throw new MongooseError('No client could be found on the given connection'); + } +}; + /** * Helper for `dropDatabase()`. Deletes the given database, including all * collections, documents, and indexes. diff --git a/test/connection.test.js b/test/connection.test.js index 3d1170838cf..6a151e1321c 100644 --- a/test/connection.test.js +++ b/test/connection.test.js @@ -1580,6 +1580,20 @@ describe('connections:', function() { }); assert.ok(session); }); + it('should demonstrate the listDatabases() function (gh-9048)', async function() { + const client = await mongodb.MongoClient.connect(start.uri); + const db = mongoose.createConnection().setClient(client); + db.useDb(start.databases[1]); + const { databases } = await db.listDatabases(); + assert.ok(databases); + }); + it('should throw an error when no client is present (gh-9048)', async function() { + const db = mongoose.createConnection(); + const db2 = db.useDb(start.databases[1]); + assert.rejects(async() => { + await db.listDatabases(); + }, { message: 'No client could be found on the given connection' }); + }); describe('createCollections()', function() { it('should create collections for all models on the connection with the createCollections() function (gh-13300)', async function() { const m = new mongoose.Mongoose(); From f1667e0ffaafffb4f124f7896cc5eacef05e1aa8 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 8 Apr 2024 14:07:24 -0400 Subject: [PATCH 2/2] fix: make listDatabases() consistent with other connection methods and add typescript support + docs --- lib/connection.js | 24 ++++++++++++++++++++---- test/connection.test.js | 23 ++++++++++------------- test/types/connection.test.ts | 4 ++++ types/connection.d.ts | 6 ++++++ 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/lib/connection.js b/lib/connection.js index 51b85ceaec2..48ea6bb2450 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -647,12 +647,28 @@ Connection.prototype.listCollections = async function listCollections() { return await cursor.toArray(); }; +/** + * Helper for MongoDB Node driver's `listDatabases()`. + * Returns an object with a `databases` property that contains an + * array of database objects. + * + * #### Example: + * const { databases } = await mongoose.connection.listDatabases(); + * databases; // [{ name: 'mongoose_test', sizeOnDisk: 0, empty: false }] + * + * @method listCollections + * @return {Promise<{ databases: Array<{ name: string }> }>} + * @api public + */ + Connection.prototype.listDatabases = async function listDatabases() { - if (this.client) { - return this.client.db().admin().listDatabases(); - } else { - throw new MongooseError('No client could be found on the given connection'); + if ((this.readyState === STATES.connecting || this.readyState === STATES.disconnected) && this._shouldBufferCommands()) { + await new Promise(resolve => { + this._queue.push({ fn: resolve }); + }); } + + return await this.db.admin().listDatabases(); }; /** diff --git a/test/connection.test.js b/test/connection.test.js index 6a151e1321c..82df2ee4c3a 100644 --- a/test/connection.test.js +++ b/test/connection.test.js @@ -1580,19 +1580,16 @@ describe('connections:', function() { }); assert.ok(session); }); - it('should demonstrate the listDatabases() function (gh-9048)', async function() { - const client = await mongodb.MongoClient.connect(start.uri); - const db = mongoose.createConnection().setClient(client); - db.useDb(start.databases[1]); - const { databases } = await db.listDatabases(); - assert.ok(databases); - }); - it('should throw an error when no client is present (gh-9048)', async function() { - const db = mongoose.createConnection(); - const db2 = db.useDb(start.databases[1]); - assert.rejects(async() => { - await db.listDatabases(); - }, { message: 'No client could be found on the given connection' }); + it('listDatabases() should return a list of database objects with a name property (gh-9048)', async function() { + const connection = await mongoose.createConnection(start.uri).asPromise(); + // If this test is running in isolation, then the `start.uri` db might not + // exist yet, so create this collection (and the associated db) just in case + await connection.createCollection('tests').catch(() => {}); + + const { databases } = await connection.listDatabases(); + assert.ok(connection.name); + console.log(databases); + assert.ok(databases.map(database => database.name).includes(connection.name)); }); describe('createCollections()', function() { it('should create collections for all models on the connection with the createCollections() function (gh-13300)', async function() { diff --git a/test/types/connection.test.ts b/test/types/connection.test.ts index 93c3fc6c0d8..c5979663a20 100644 --- a/test/types/connection.test.ts +++ b/test/types/connection.test.ts @@ -78,6 +78,10 @@ expectType>( conn.listCollections().then(collections => collections.map(coll => coll.name)) ); +expectType>( + conn.listDatabases().then(dbs => dbs.databases.map(db => db.name)) +); + export function autoTypedModelConnection() { const AutoTypedSchema = autoTypedSchema(); const AutoTypedModel = connection.model('AutoTypeModelConnection', AutoTypedSchema); diff --git a/types/connection.d.ts b/types/connection.d.ts index b2812d01cf6..2f47bdc84e5 100644 --- a/types/connection.d.ts +++ b/types/connection.d.ts @@ -132,6 +132,12 @@ declare module 'mongoose' { */ listCollections(): Promise[]>; + /** + * Helper for MongoDB Node driver's `listDatabases()`. + * Returns an array of database names. + */ + listDatabases(): Promise; + /** * A [POJO](https://masteringjs.io/tutorials/fundamentals/pojo) containing * a map from model names to models. Contains all models that have been