diff --git a/src/connection_string.ts b/src/connection_string.ts index b61eb817d56..0ed6cbd3de2 100644 --- a/src/connection_string.ts +++ b/src/connection_string.ts @@ -32,7 +32,7 @@ import type { TagSet } from './sdam/server_description'; import { Logger, LoggerLevel } from './logger'; import { PromiseProvider } from './promise_provider'; import { Encrypter } from './encrypter'; -import { Compressor } from './cmap/wire_protocol/compression'; +import { Compressor, CompressorName } from './cmap/wire_protocol/compression'; const VALID_TXT_RECORDS = ['authSource', 'replicaSet', 'loadBalanced']; @@ -612,8 +612,14 @@ export const OPTIONS = { target: 'compressors', transform({ values }) { const compressionList = new Set(); - for (const compVal of values as string[]) { - for (const c of compVal.split(',')) { + for (const compVal of values as (CompressorName[] | string)[]) { + const compValArray = typeof compVal === 'string' ? compVal.split(',') : compVal; + if (!Array.isArray(compValArray)) { + throw new MongoInvalidArgumentError( + 'compressors must be an array or a comma-delimited list of strings' + ); + } + for (const c of compValArray) { if (Object.keys(Compressor).includes(String(c))) { compressionList.add(String(c)); } else { diff --git a/src/mongo_client.ts b/src/mongo_client.ts index 69aed2d3614..19192aa0208 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -128,8 +128,8 @@ export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeC connectTimeoutMS?: number; /** The time in milliseconds to attempt a send or receive on a socket before the attempt times out. */ socketTimeoutMS?: number; - /** Comma-delimited string of compressors to enable network compression for communication between this client and a mongod/mongos instance. */ - compressors?: CompressorName[]; + /** An array or comma-delimited string of compressors to enable network compression for communication between this client and a mongod/mongos instance. */ + compressors?: CompressorName[] | string; /** An integer that specifies the compression level if using zlib for network compression. */ zlibCompressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | undefined; /** The maximum number of connections in the connection pool. */ @@ -620,7 +620,6 @@ export interface MongoOptions Pick< MongoClientOptions, | 'autoEncryption' - | 'compressors' | 'connectTimeoutMS' | 'directConnection' | 'driverInfo' @@ -659,6 +658,7 @@ export interface MongoOptions readConcern: ReadConcern; loadBalanced: boolean; serverApi: ServerApi; + compressors: CompressorName[]; writeConcern: WriteConcern; dbName: string; metadata: ClientMetadata; diff --git a/test/types/community/changes_from_36.test-d.ts b/test/types/community/changes_from_36.test-d.ts index 4aa7250818e..55970768042 100644 --- a/test/types/community/changes_from_36.test-d.ts +++ b/test/types/community/changes_from_36.test-d.ts @@ -69,7 +69,7 @@ expectAssignable<((host: string, cert: PeerCertificate) => Error | undefined) | // compression options have simpler specification: // old way: {compression: { compressors: ['zlib', 'snappy'] }} expectType>(false); -expectType<('none' | 'snappy' | 'zlib')[] | undefined>(options.compressors); +expectType<('none' | 'snappy' | 'zlib')[] | string | undefined>(options.compressors); // Removed cursor API const cursor = new MongoClient('').db().aggregate(); diff --git a/test/unit/mongo_client_options.test.js b/test/unit/mongo_client_options.test.js index c1f07e4544f..083908f2913 100644 --- a/test/unit/mongo_client_options.test.js +++ b/test/unit/mongo_client_options.test.js @@ -78,7 +78,7 @@ describe('MongoOptions', function () { autoEncryption: { bypassAutoEncryption: true }, checkKeys: true, checkServerIdentity: false, - compressors: 'snappy', // TODO + compressors: 'snappy,zlib', connectTimeoutMS: 123, directConnection: true, dbName: 'test', @@ -385,6 +385,58 @@ describe('MongoOptions', function () { expect(optionsUndefined.checkServerIdentity).to.equal(undefined); }); + describe('compressors', function () { + it('can be set when passed in as an array in the options object', function () { + const clientViaOpt = new MongoClient('mongodb://localhost', { + compressors: ['zlib', 'snappy'] + }); + expect(clientViaOpt.options) + .to.have.property('compressors') + .deep.equal(['zlib', 'snappy', 'none']); + }); + + it('can be set when passed in as a comma-delimited string in the options object or URI', function () { + const clientViaOpt = new MongoClient('mongodb://localhost', { + compressors: 'zlib,snappy' + }); + const clientViaUri = new MongoClient('mongodb://localhost?compressors=zlib,snappy'); + expect(clientViaOpt.options) + .to.have.property('compressors') + .deep.equal(['zlib', 'snappy', 'none']); + expect(clientViaUri.options) + .to.have.property('compressors') + .deep.equal(['zlib', 'snappy', 'none']); + }); + + it('should validate that a string or an array of strings is provided as input', function () { + expect( + () => + new MongoClient('mongodb://localhost', { + compressors: { zlib: true } + }) + ).to.throw(/^compressors must be an array or a comma-delimited list of strings/); + }); + + it('should throw an error if an unrecognized compressor is specified', function () { + const expectedErrRegex = /not a valid compression mechanism/; + expect( + () => + new MongoClient('mongodb://localhost', { + compressors: ['invalid'] + }) + ).to.throw(expectedErrRegex); + expect( + () => + new MongoClient('mongodb://localhost', { + compressors: 'invalid' + }) + ).to.throw(expectedErrRegex); + expect(() => new MongoClient('mongodb://localhost?compressors=invalid')).to.throw( + expectedErrRegex + ); + }); + }); + describe('serverApi', function () { it('is supported as a client option when it is a valid ServerApiVersion string', function () { const validVersions = Object.values(ServerApiVersion);