diff --git a/src/operations/list_collections.ts b/src/operations/list_collections.ts index 82c8004d379..b9e704cfd53 100644 --- a/src/operations/list_collections.ts +++ b/src/operations/list_collections.ts @@ -15,6 +15,8 @@ const LIST_COLLECTIONS_WIRE_VERSION = 3; export interface ListCollectionsOptions extends CommandOperationOptions { /** Since 4.0: If true, will only return the collection name in the response, and will omit additional info */ nameOnly?: boolean; + /** Since 4.0: If true and nameOnly is true, allows a user without the required privilege (i.e. listCollections action on the database) to run the command when access control is enforced. */ + authorizedCollections?: boolean; /** The batchSize for the returned command cursor or if pre 2.8 the systems batch collection */ batchSize?: number; } @@ -25,6 +27,7 @@ export class ListCollectionsOperation extends CommandOperation { db: Db; filter: Document; nameOnly: boolean; + authorizedCollections: boolean; batchSize?: number; constructor(db: Db, filter: Document, options?: ListCollectionsOptions) { @@ -34,6 +37,7 @@ export class ListCollectionsOperation extends CommandOperation { this.db = db; this.filter = filter; this.nameOnly = !!this.options.nameOnly; + this.authorizedCollections = !!this.options.authorizedCollections; if (typeof this.options.batchSize === 'number') { this.batchSize = this.options.batchSize; @@ -99,7 +103,8 @@ export class ListCollectionsOperation extends CommandOperation { listCollections: 1, filter: this.filter, cursor: this.batchSize ? { batchSize: this.batchSize } : {}, - nameOnly: this.nameOnly + nameOnly: this.nameOnly, + authorizedCollections: this.authorizedCollections }; } } diff --git a/test/unit/operations/list_collections.test.js b/test/unit/operations/list_collections.test.js index 541edc37f71..d63d7c0c160 100644 --- a/test/unit/operations/list_collections.test.js +++ b/test/unit/operations/list_collections.test.js @@ -12,7 +12,7 @@ describe('ListCollectionsOperation', function () { const operation = new ListCollectionsOperation(db, {}, { nameOnly: true, dbName: db }); it('sets nameOnly to true', function () { - expect(operation.nameOnly).to.be.true; + expect(operation).to.have.property('nameOnly', true); }); }); @@ -20,16 +20,46 @@ describe('ListCollectionsOperation', function () { const operation = new ListCollectionsOperation(db, {}, { nameOnly: false, dbName: db }); it('sets nameOnly to false', function () { - expect(operation.nameOnly).to.be.false; + expect(operation).to.have.property('nameOnly', false); }); }); }); - context('when nameOnly is not provided', function () { + context('when authorizedCollections is provided', function () { + context('when authorizedCollections is true', function () { + const operation = new ListCollectionsOperation( + db, + {}, + { authorizedCollections: true, dbName: db } + ); + + it('sets authorizedCollections to true', function () { + expect(operation).to.have.property('authorizedCollections', true); + }); + }); + + context('when authorizedCollections is false', function () { + const operation = new ListCollectionsOperation( + db, + {}, + { authorizedCollections: false, dbName: db } + ); + + it('sets authorizedCollections to false', function () { + expect(operation).to.have.property('authorizedCollections', false); + }); + }); + }); + + context('when no options are provided', function () { const operation = new ListCollectionsOperation(db, {}, { dbName: db }); it('sets nameOnly to false', function () { - expect(operation.nameOnly).to.be.false; + expect(operation).to.have.property('nameOnly', false); + }); + + it('sets authorizedCollections to false', function () { + expect(operation).to.have.property('authorizedCollections', false); }); }); }); @@ -44,7 +74,8 @@ describe('ListCollectionsOperation', function () { listCollections: 1, cursor: {}, filter: {}, - nameOnly: true + nameOnly: true, + authorizedCollections: false }); }); }); @@ -57,21 +88,61 @@ describe('ListCollectionsOperation', function () { listCollections: 1, cursor: {}, filter: {}, - nameOnly: false + nameOnly: false, + authorizedCollections: false }); }); }); }); - context('when nameOnly is not provided', function () { + context('when authorizedCollections is provided', function () { + context('when authorizedCollections is true', function () { + const operation = new ListCollectionsOperation( + db, + {}, + { authorizedCollections: true, dbName: db } + ); + + it('sets authorizedCollections to true', function () { + expect(operation.generateCommand()).to.deep.equal({ + listCollections: 1, + cursor: {}, + filter: {}, + nameOnly: false, + authorizedCollections: true + }); + }); + }); + + context('when authorizedCollections is false', function () { + const operation = new ListCollectionsOperation( + db, + {}, + { authorizedCollections: false, dbName: db } + ); + + it('sets authorizedCollections to false', function () { + expect(operation.generateCommand()).to.deep.equal({ + listCollections: 1, + cursor: {}, + filter: {}, + nameOnly: false, + authorizedCollections: false + }); + }); + }); + }); + + context('when no options are provided', function () { const operation = new ListCollectionsOperation(db, {}, { dbName: db }); - it('sets nameOnly to false', function () { + it('sets nameOnly and authorizedCollections properties to false', function () { expect(operation.generateCommand()).to.deep.equal({ listCollections: 1, cursor: {}, filter: {}, - nameOnly: false + nameOnly: false, + authorizedCollections: false }); }); });