Skip to content

feat(NODE-4867)!: adopt BSON v5 #3490

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

Merged
merged 18 commits into from
Jan 20, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion etc/notes/CHANGES_5.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The following is a detailed collection of the changes in the major v5 release of

### Dot Notation Typescript Support Removed By Default

**NOTE** This is a **Typescript compile-time only** change. Dot notation in filters sent to MongoDB will still work the same.
**NOTE** This is a **Typescript compile-time only** change. Dot notation in filters sent to MongoDB will still work the same.

Version 4.3.0 introduced Typescript support for dot notation in filter predicates. For example:

Expand Down
55 changes: 39 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"email": "[email protected]"
},
"dependencies": {
"bson": "^4.7.0",
"bson": "^5.0.0-alpha.3",
"mongodb-connection-string-url": "^2.6.0",
"socks": "^2.7.1"
},
Expand Down
11 changes: 3 additions & 8 deletions src/bson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import type { DeserializeOptions, SerializeOptions } from 'bson';

export {
Binary,
BSON,
BSONRegExp,
BSONSymbol,
BSONType,
calculateObjectSize,
Code,
DBRef,
Expand All @@ -13,21 +15,13 @@ export {
Double,
Int32,
Long,
Map,
MaxKey,
MinKey,
ObjectId,
serialize,
Timestamp
} from 'bson';

// TODO(NODE-4867): fix with bson v5
/** @internal */
// eslint-disable-next-line @typescript-eslint/no-var-requires
const BSON = require('bson');

export { BSON };

/**
* BSON Serialization options.
* @public
Expand All @@ -42,6 +36,7 @@ export interface BSONSerializeOptions
| 'allowObjectSmallerThanBufferSize'
| 'index'
| 'validation'
| 'useBigInt64'
> {
/**
* Enabling the raw option will return a [Node.js Buffer](https://nodejs.org/api/buffer.html)
Expand Down
7 changes: 4 additions & 3 deletions src/cmap/auth/mongodb_aws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
MongoMissingCredentialsError,
MongoRuntimeError
} from '../../error';
import { Callback, maxWireVersion, ns } from '../../utils';
import { ByteUtils, Callback, maxWireVersion, ns } from '../../utils';
import { AuthContext, AuthProvider } from './auth_provider';
import { MongoCredentials } from './mongo_credentials';
import { AuthMechanism } from './providers';
Expand Down Expand Up @@ -108,7 +108,8 @@ export class MongoDBAWS extends AuthProvider {
return;
}

if (serverNonce.compare(nonce, 0, nonce.length, 0, nonce.length) !== 0) {
// TODO(NODE-4990)
if (!ByteUtils.equals(serverNonce.subarray(0, nonce.byteLength), nonce)) {
// TODO(NODE-3483)
callback(new MongoRuntimeError('Server nonce does not begin with client nonce'));
return;
Expand All @@ -130,7 +131,7 @@ export class MongoDBAWS extends AuthProvider {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': body.length,
'X-MongoDB-Server-Nonce': serverNonce.toString('base64'),
'X-MongoDB-Server-Nonce': ByteUtils.toBase64(serverNonce),
'X-MongoDB-GS2-CB-Flag': 'n'
},
path: '/',
Expand Down
6 changes: 3 additions & 3 deletions src/cmap/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export class Query {
}

// Uses a single allocated buffer for the process, avoiding multiple memory allocations
toBin(): Buffer[] {
toBin(): Uint8Array[] {
const buffers = [];
let projection = null;

Expand Down Expand Up @@ -550,7 +550,7 @@ export class Msg {
return buffers;
}

makeDocumentSegment(buffers: Buffer[], document: Document): number {
makeDocumentSegment(buffers: Uint8Array[], document: Document): number {
const payloadTypeBuffer = Buffer.alloc(1);
payloadTypeBuffer[0] = 0;

Expand All @@ -561,7 +561,7 @@ export class Msg {
return payloadTypeBuffer.length + documentBuffer.length;
}

serializeBson(document: Document): Buffer {
serializeBson(document: Document): Uint8Array {
return BSON.serialize(document, {
checkKeys: this.checkKeys,
serializeFunctions: this.serializeFunctions,
Expand Down
5 changes: 2 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ import { MongoClient } from './mongo_client';
import { CancellationToken } from './mongo_types';
import { ClientSession } from './sessions';

/** @internal */
/** @public */
export { BSON } from './bson';
export {
Binary,
BSONRegExp,
BSONSymbol,
BSONType,
Code,
DBRef,
Decimal128,
Double,
Int32,
Long,
Map,
MaxKey,
MinKey,
ObjectId,
Expand Down Expand Up @@ -103,7 +103,6 @@ export { MongoErrorLabel } from './error';
export { ExplainVerbosity } from './explain';
export { LoggerLevel } from './logger';
export { ServerApiVersion } from './mongo_client';
export { BSONType } from './mongo_types';
export { ReturnDocument } from './operations/find_and_modify';
export { ProfilingLevel } from './operations/set_profiling_level';
export { ReadConcernLevel } from './read_concern';
Expand Down
29 changes: 1 addition & 28 deletions src/mongo_types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ObjectIdLike } from 'bson';
import type { BSONType, ObjectIdLike } from 'bson';
import { EventEmitter } from 'events';

import type {
Expand Down Expand Up @@ -158,33 +158,6 @@ export type BitwiseFilter =
| Binary /** BinData bit mask */
| ReadonlyArray<number>; /** `[ <position1>, <position2>, ... ]` */

/** @public */
export const BSONType = Object.freeze({
double: 1,
string: 2,
object: 3,
array: 4,
binData: 5,
undefined: 6,
objectId: 7,
bool: 8,
date: 9,
null: 10,
regex: 11,
dbPointer: 12,
javascript: 13,
symbol: 14,
javascriptWithScope: 15,
int: 16,
timestamp: 17,
long: 18,
decimal: 19,
minKey: -1,
maxKey: 127
} as const);

/** @public */
export type BSONType = typeof BSONType[keyof typeof BSONType];
/** @public */
export type BSONTypeAlias = keyof typeof BSONType;

Expand Down
3 changes: 2 additions & 1 deletion src/sessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { ReadPreference } from './read_preference';
import { _advanceClusterTime, ClusterTime, TopologyType } from './sdam/common';
import { isTransactionCommand, Transaction, TransactionOptions, TxnState } from './transactions';
import {
ByteUtils,
calculateDurationInMs,
Callback,
commandSupportsReadConcern,
Expand Down Expand Up @@ -347,7 +348,7 @@ export class ClientSession extends TypedEventEmitter<ClientSessionEvents> {
return false;
}

return this.id.id.buffer.equals(session.id.id.buffer);
return ByteUtils.equals(this.id.id.buffer, session.id.id.buffer);
}

/**
Expand Down
24 changes: 21 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,28 @@ import { W, WriteConcern, WriteConcernOptions } from './write_concern';
*/
export type Callback<T = any> = (error?: AnyError, result?: T) => void;

export const MAX_JS_INT = Number.MAX_SAFE_INTEGER + 1;

export type AnyOptions = Document;

export const ByteUtils = {
toLocalBufferType(this: void, buffer: Buffer | Uint8Array): Buffer {
return Buffer.isBuffer(buffer)
? buffer
: Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength);
},

equals(this: void, seqA: Uint8Array, seqB: Uint8Array) {
return ByteUtils.toLocalBufferType(seqA).equals(seqB);
},

compare(this: void, seqA: Uint8Array, seqB: Uint8Array) {
return ByteUtils.toLocalBufferType(seqA).compare(seqB);
},

toBase64(this: void, uint8array: Uint8Array) {
return ByteUtils.toLocalBufferType(uint8array).toString('base64');
}
};

/**
* Throws if collectionName is not a valid mongodb collection namespace.
* @internal
Expand Down Expand Up @@ -1401,7 +1419,7 @@ export function compareObjectId(oid1?: ObjectId | null, oid2?: ObjectId | null):
return 1;
}

return oid1.id.compare(oid2.id);
return ByteUtils.compare(oid1.id, oid2.id);
}

export function parseInteger(value: unknown): number | null {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ describe('Change Stream prose tests', function () {

// Helpers
timestamp() {
return new Timestamp(this._timestampCounter++, Date.now());
return new Timestamp({ i: this._timestampCounter++, t: this._timestampCounter });
}

applyOpTime(obj) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,6 @@ const skippedAuthTests = [
'unset works with an encrypted field',
'updateOne with deterministic encryption',
'updateMany with deterministic encryption',
'type=date',
'type=regex',
'type=timestamp',
'type=javascript',
'type=binData',
'type=int',
'type=objectId',
'type=symbol',
'replaceOne with encryption',
'Insert with encryption on a missing key',
'A local schema should override',
Expand Down
Loading