Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(NODE-3150): allow retrieving PCRE-style RegExp #2840

Merged
merged 6 commits into from
Jun 25, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/bson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export interface BSONSerializeOptions
| 'evalFunctions'
| 'cacheFunctions'
| 'cacheFunctionsCrc32'
| 'bsonRegExp'
| 'allowObjectSmallerThanBufferSize'
| 'index'
> {
Expand All @@ -64,6 +63,7 @@ export function pluckBSONSerializeOptions(options: BSONSerializeOptions): BSONSe
promoteLongs,
serializeFunctions,
ignoreUndefined,
bsonRegExp,
raw
} = options;
return {
Expand All @@ -73,6 +73,7 @@ export function pluckBSONSerializeOptions(options: BSONSerializeOptions): BSONSe
promoteLongs,
serializeFunctions,
ignoreUndefined,
bsonRegExp,
raw
};
}
Expand All @@ -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 ?? {}
};
Expand Down
3 changes: 2 additions & 1 deletion src/cmap/auth/mongodb_aws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
34 changes: 26 additions & 8 deletions src/cmap/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ export class Response {
promoteLongs: boolean;
promoteValues: boolean;
promoteBuffers: boolean;
bsonRegExp?: boolean;
index?: number;

constructor(
Expand All @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -765,6 +774,7 @@ export class BinMsg {
promoteLongs: boolean;
promoteValues: boolean;
promoteBuffers: boolean;
bsonRegExp: boolean;
documents: (Document | Buffer)[];
index?: number;

Expand All @@ -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;
Expand All @@ -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 = [];
}
Expand All @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions src/cmap/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down
3 changes: 2 additions & 1 deletion src/cmap/wire_protocol/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions src/connection_string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,9 @@ export const OPTIONS = {
autoEncryption: {
type: 'record'
},
bsonRegExp: {
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
type: 'boolean'
},
serverApi: {
target: 'serverApi',
transform({ values: [version] }): ServerApi {
Expand Down
2 changes: 1 addition & 1 deletion src/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@ const DB_OPTIONS_ALLOW_LIST = [
'raw',
'authSource',
'ignoreUndefined',
'promoteLongs',
'readConcern',
'retryMiliSeconds',
'numberOfRetries',
'loggerLevel',
'logger',
'promoteBuffers',
'promoteLongs',
'bsonRegExp',
'promoteValues',
'compression',
'retryWrites'
Expand Down
1 change: 1 addition & 0 deletions src/operations/create_collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const ILLEGAL_COMMAND_FIELDS = new Set([
'promoteLongs',
'promoteValues',
'promoteBuffers',
'bsonRegExp',
'serializeFunctions',
'ignoreUndefined'
]);
Expand Down
1 change: 1 addition & 0 deletions src/operations/map_reduce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const exclusionList = [
'promoteLongs',
'promoteValues',
'promoteBuffers',
'bsonRegExp',
'serializeFunctions',
'ignoreUndefined',
'scope' // this option is reformatted thus exclude the original
Expand Down
29 changes: 29 additions & 0 deletions src/sdam/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,35 @@ import type { AutoEncrypter } from '../deps';
import type { ServerApi } from '../mongo_client';
import { TypedEventEmitter } from '../mongo_types';

// Used for filtering out fields for logging
const DEBUG_FIELDS = [
'reconnect',
'reconnectTries',
'reconnectInterval',
'emitError',
'cursorFactory',
'host',
'port',
'size',
'keepAlive',
'keepAliveInitialDelay',
'noDelay',
'connectionTimeout',
'checkServerIdentity',
'socketTimeoutMS',
'ssl',
'ca',
'crl',
'cert',
'key',
'rejectUnauthorized',
'promoteLongs',
'promoteValues',
'promoteBuffers',
'bsonRegExp',
'servername'
];
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved

const stateTransition = makeStateMachine({
[STATE_CLOSED]: [STATE_CLOSED, STATE_CONNECTING],
[STATE_CONNECTING]: [STATE_CONNECTING, STATE_CLOSING, STATE_CONNECTED, STATE_CLOSED],
Expand Down
2 changes: 2 additions & 0 deletions test/types/bson.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ expectType<boolean | undefined>(options.ignoreUndefined);
expectType<boolean | undefined>(options.promoteLongs);
expectType<boolean | undefined>(options.promoteBuffers);
expectType<boolean | undefined>(options.promoteValues);
expectType<boolean | undefined>(options.bsonRegExp);
expectType<Document | undefined>(options.fieldsAsRaw);

type PermittedBSONOptionKeys =
Expand All @@ -18,6 +19,7 @@ type PermittedBSONOptionKeys =
| 'promoteLongs'
| 'promoteBuffers'
| 'promoteValues'
| 'bsonRegExp'
| 'fieldsAsRaw'
| 'raw';

Expand Down
36 changes: 36 additions & 0 deletions test/unit/bson_regex.test.js
Original file line number Diff line number Diff line change
@@ -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();
}
});
}
});
});