diff --git a/src/bson.ts b/src/bson.ts index 862b96de46..8cf5aab9dc 100644 --- a/src/bson.ts +++ b/src/bson.ts @@ -48,7 +48,6 @@ export interface BSONSerializeOptions | 'evalFunctions' | 'cacheFunctions' | 'cacheFunctionsCrc32' - | 'bsonRegExp' | 'allowObjectSmallerThanBufferSize' | 'index' > { @@ -64,6 +63,7 @@ export function pluckBSONSerializeOptions(options: BSONSerializeOptions): BSONSe promoteLongs, serializeFunctions, ignoreUndefined, + bsonRegExp, raw } = options; return { @@ -73,6 +73,7 @@ export function pluckBSONSerializeOptions(options: BSONSerializeOptions): BSONSe promoteLongs, serializeFunctions, ignoreUndefined, + bsonRegExp, raw }; } @@ -94,6 +95,7 @@ export function resolveBSONOptions( promoteValues: options?.promoteValues ?? parentOptions?.promoteValues ?? true, promoteBuffers: options?.promoteBuffers ?? parentOptions?.promoteBuffers ?? false, ignoreUndefined: options?.ignoreUndefined ?? parentOptions?.ignoreUndefined ?? false, + bsonRegExp: options?.bsonRegExp ?? parentOptions?.bsonRegExp ?? false, serializeFunctions: options?.serializeFunctions ?? parentOptions?.serializeFunctions ?? false, fieldsAsRaw: options?.fieldsAsRaw ?? parentOptions?.fieldsAsRaw ?? {} }; diff --git a/src/cmap/auth/mongodb_aws.ts b/src/cmap/auth/mongodb_aws.ts index fb8a5f8f01..06b97b56ba 100644 --- a/src/cmap/auth/mongodb_aws.ts +++ b/src/cmap/auth/mongodb_aws.ts @@ -18,7 +18,8 @@ const AWS_EC2_PATH = '/latest/meta-data/iam/security-credentials'; const bsonOptions: BSONSerializeOptions = { promoteLongs: true, promoteValues: true, - promoteBuffers: false + promoteBuffers: false, + bsonRegExp: false }; interface AWSSaslContinuePayload { diff --git a/src/cmap/commands.ts b/src/cmap/commands.ts index 0123399c9a..72c55659e2 100644 --- a/src/cmap/commands.ts +++ b/src/cmap/commands.ts @@ -491,6 +491,7 @@ export class Response { promoteLongs: boolean; promoteValues: boolean; promoteBuffers: boolean; + bsonRegExp?: boolean; index?: number; constructor( @@ -502,7 +503,12 @@ export class Response { this.parsed = false; this.raw = message; this.data = msgBody; - this.opts = opts ?? { promoteLongs: true, promoteValues: true, promoteBuffers: false }; + this.opts = opts ?? { + promoteLongs: true, + promoteValues: true, + promoteBuffers: false, + bsonRegExp: false + }; // Read the message header this.length = msgHeader.length; @@ -530,6 +536,7 @@ export class Response { typeof this.opts.promoteValues === 'boolean' ? this.opts.promoteValues : true; this.promoteBuffers = typeof this.opts.promoteBuffers === 'boolean' ? this.opts.promoteBuffers : false; + this.bsonRegExp = typeof this.opts.bsonRegExp === 'boolean' ? this.opts.bsonRegExp : false; } isParsed(): boolean { @@ -547,13 +554,15 @@ export class Response { const promoteLongs = options.promoteLongs ?? this.opts.promoteLongs; const promoteValues = options.promoteValues ?? this.opts.promoteValues; const promoteBuffers = options.promoteBuffers ?? this.opts.promoteBuffers; + const bsonRegExp = options.bsonRegExp ?? this.opts.bsonRegExp; let bsonSize; // Set up the options const _options: BSONSerializeOptions = { - promoteLongs: promoteLongs, - promoteValues: promoteValues, - promoteBuffers: promoteBuffers + promoteLongs, + promoteValues, + promoteBuffers, + bsonRegExp }; // Position within OP_REPLY at which documents start @@ -765,6 +774,7 @@ export class BinMsg { promoteLongs: boolean; promoteValues: boolean; promoteBuffers: boolean; + bsonRegExp: boolean; documents: (Document | Buffer)[]; index?: number; @@ -777,7 +787,12 @@ export class BinMsg { this.parsed = false; this.raw = message; this.data = msgBody; - this.opts = opts ?? { promoteLongs: true, promoteValues: true, promoteBuffers: false }; + this.opts = opts ?? { + promoteLongs: true, + promoteValues: true, + promoteBuffers: false, + bsonRegExp: false + }; // Read the message header this.length = msgHeader.length; @@ -796,6 +811,7 @@ export class BinMsg { typeof this.opts.promoteValues === 'boolean' ? this.opts.promoteValues : true; this.promoteBuffers = typeof this.opts.promoteBuffers === 'boolean' ? this.opts.promoteBuffers : false; + this.bsonRegExp = typeof this.opts.bsonRegExp === 'boolean' ? this.opts.bsonRegExp : false; this.documents = []; } @@ -816,12 +832,14 @@ export class BinMsg { const promoteLongs = options.promoteLongs ?? this.opts.promoteLongs; const promoteValues = options.promoteValues ?? this.opts.promoteValues; const promoteBuffers = options.promoteBuffers ?? this.opts.promoteBuffers; + const bsonRegExp = options.bsonRegExp ?? this.opts.bsonRegExp; // Set up the options const _options: BSONSerializeOptions = { - promoteLongs: promoteLongs, - promoteValues: promoteValues, - promoteBuffers: promoteBuffers + promoteLongs, + promoteValues, + promoteBuffers, + bsonRegExp }; while (this.index < this.data.length) { diff --git a/src/cmap/connection.ts b/src/cmap/connection.ts index 81df7cdbc8..fc9436fa81 100644 --- a/src/cmap/connection.ts +++ b/src/cmap/connection.ts @@ -792,6 +792,7 @@ function write( promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true, promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true, promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false, + bsonRegExp: typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : false, raw: typeof options.raw === 'boolean' ? options.raw : false, started: 0 }; diff --git a/src/cmap/wire_protocol/shared.ts b/src/cmap/wire_protocol/shared.ts index 1273ae2669..ffab8d047e 100644 --- a/src/cmap/wire_protocol/shared.ts +++ b/src/cmap/wire_protocol/shared.ts @@ -42,7 +42,8 @@ export function applyCommonQueryOptions( raw: typeof options.raw === 'boolean' ? options.raw : false, promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true, promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true, - promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false + promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false, + bsonRegExp: typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : false }); if (options.session) { diff --git a/src/connection_string.ts b/src/connection_string.ts index 16d9ef5b35..c3e6978a82 100644 --- a/src/connection_string.ts +++ b/src/connection_string.ts @@ -588,6 +588,9 @@ export const OPTIONS = { autoEncryption: { type: 'record' }, + bsonRegExp: { + type: 'boolean' + }, serverApi: { target: 'serverApi', transform({ values: [version] }): ServerApi { diff --git a/src/db.ts b/src/db.ts index f8d8d21032..4fc77994e4 100644 --- a/src/db.ts +++ b/src/db.ts @@ -61,7 +61,6 @@ const DB_OPTIONS_ALLOW_LIST = [ 'raw', 'authSource', 'ignoreUndefined', - 'promoteLongs', 'readConcern', 'retryMiliSeconds', 'numberOfRetries', @@ -69,6 +68,7 @@ const DB_OPTIONS_ALLOW_LIST = [ 'logger', 'promoteBuffers', 'promoteLongs', + 'bsonRegExp', 'promoteValues', 'compression', 'retryWrites' diff --git a/src/operations/create_collection.ts b/src/operations/create_collection.ts index 064dd3fe43..e795d00949 100644 --- a/src/operations/create_collection.ts +++ b/src/operations/create_collection.ts @@ -25,6 +25,7 @@ const ILLEGAL_COMMAND_FIELDS = new Set([ 'promoteLongs', 'promoteValues', 'promoteBuffers', + 'bsonRegExp', 'serializeFunctions', 'ignoreUndefined' ]); diff --git a/src/operations/map_reduce.ts b/src/operations/map_reduce.ts index 2873ef9ae2..6f8540e736 100644 --- a/src/operations/map_reduce.ts +++ b/src/operations/map_reduce.ts @@ -30,6 +30,7 @@ const exclusionList = [ 'promoteLongs', 'promoteValues', 'promoteBuffers', + 'bsonRegExp', 'serializeFunctions', 'ignoreUndefined', 'scope' // this option is reformatted thus exclude the original diff --git a/test/types/bson.test-d.ts b/test/types/bson.test-d.ts index 8030bd2d47..548d0ec707 100644 --- a/test/types/bson.test-d.ts +++ b/test/types/bson.test-d.ts @@ -9,6 +9,7 @@ expectType(options.ignoreUndefined); expectType(options.promoteLongs); expectType(options.promoteBuffers); expectType(options.promoteValues); +expectType(options.bsonRegExp); expectType(options.fieldsAsRaw); type PermittedBSONOptionKeys = @@ -18,6 +19,7 @@ type PermittedBSONOptionKeys = | 'promoteLongs' | 'promoteBuffers' | 'promoteValues' + | 'bsonRegExp' | 'fieldsAsRaw' | 'raw'; diff --git a/test/unit/bson_regex.test.js b/test/unit/bson_regex.test.js new file mode 100644 index 0000000000..3a291bfa14 --- /dev/null +++ b/test/unit/bson_regex.test.js @@ -0,0 +1,36 @@ +'use strict'; + +const { expect } = require('chai'); +const { BSONRegExp } = require('../../src/index'); + +describe('BSONRegExp', () => { + describe('bsonRegExp option', () => { + // define client and option for tests to use + let client; + const option = { bsonRegExp: true }; + for (const passOptionTo of ['client', 'db', 'collection', 'operation']) { + it(`should respond with BSONRegExp class with option passed to ${passOptionTo}`, async function () { + try { + client = this.configuration.newClient(passOptionTo === 'client' ? option : undefined); + await client.connect(); + + const db = client.db('bson_regex_db', passOptionTo === 'db' ? option : undefined); + const collection = db.collection( + 'bson_regex_coll', + passOptionTo === 'collection' ? option : undefined + ); + + await collection.insertOne({ regex: new BSONRegExp('abc', 'imx') }); + const res = await collection.findOne( + { regex: new BSONRegExp('abc', 'imx') }, + passOptionTo === 'operation' ? option : undefined + ); + + expect(res).has.property('regex').that.is.instanceOf(BSONRegExp); + } finally { + await client.close(); + } + }); + } + }); +});