Skip to content

Commit c508f0f

Browse files
committed
fix: address comments
1 parent bd6f1d9 commit c508f0f

File tree

2 files changed

+37
-17
lines changed

2 files changed

+37
-17
lines changed

src/cmap/commands.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ const QUERY_FAILURE = 2;
3030
const SHARD_CONFIG_STALE = 4;
3131
const AWAIT_CAPABLE = 8;
3232

33+
const encodeUTF8Into = BSON.BSON.onDemand.ByteUtils.encodeUTF8Into;
34+
3335
/** @internal */
3436
export type WriteProtocolMessageType = OpQueryRequest | OpMsgRequest;
3537

@@ -413,11 +415,9 @@ export interface OpMsgOptions {
413415

414416
/** @internal */
415417
export class DocumentSequence {
416-
field: string;
417418
documents: Document[];
418419

419-
constructor(field: string, documents: Document[]) {
420-
this.field = field;
420+
constructor(documents: Document[]) {
421421
this.documents = documents;
422422
}
423423
}
@@ -506,7 +506,7 @@ export class OpMsgRequest {
506506
*/
507507
makeSections(buffers: Uint8Array[], document: Document): number {
508508
const sequencesBuffer = this.extractDocumentSequences(document);
509-
const payloadTypeBuffer = Buffer.alloc(1);
509+
const payloadTypeBuffer = Buffer.allocUnsafe(1);
510510
payloadTypeBuffer[0] = 0;
511511

512512
const documentBuffer = this.serializeBson(document);
@@ -530,23 +530,20 @@ export class OpMsgRequest {
530530
for (const [key, value] of Object.entries(document)) {
531531
if (value instanceof DocumentSequence) {
532532
// Document sequences starts with type 1 at the first byte.
533-
const payloadTypeBuffer = Buffer.alloc(1);
534-
payloadTypeBuffer[0] = 1;
535-
chunks.push(payloadTypeBuffer);
536-
// Second part of the sequence is the length;
537-
const lengthBuffer = Buffer.alloc(4);
538-
chunks.push(lengthBuffer);
539-
// Third part is the field name.
540-
const fieldBuffer = Buffer.from(key);
541-
chunks.push(fieldBuffer);
533+
const buffer = Buffer.allocUnsafe(1 + 4 + key.length);
534+
buffer[0] = 1;
535+
// Third part is the field name at offset 5.
536+
encodeUTF8Into(buffer, key, 5);
537+
chunks.push(buffer);
542538
// Fourth part are the documents' bytes.
543539
let docsLength = 0;
544540
for (const doc of value.documents) {
545541
const docBson = this.serializeBson(doc);
546542
docsLength += docBson.length;
547543
chunks.push(docBson);
548544
}
549-
lengthBuffer.writeInt32LE(fieldBuffer.length + docsLength);
545+
// Second part of the sequence is the length at offset 1;
546+
buffer.writeInt32LE(key.length + docsLength, 1);
550547
// Why are we removing the field from the command? This is because it needs to be
551548
// removed in the OP_MSG request first section, and DocumentSequence is not a
552549
// BSON type and is specific to the MongoDB wire protocol so there's nothing
@@ -560,6 +557,8 @@ export class OpMsgRequest {
560557
if (chunks.length > 0) {
561558
return Buffer.concat(chunks);
562559
}
560+
// If we have no document sequences we return an empty buffer for nothing to add
561+
// to the payload.
563562
return Buffer.alloc(0);
564563
}
565564

test/unit/cmap/commands.test.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as BSON from 'bson';
12
import { expect } from 'chai';
23

34
import { DocumentSequence, OpMsgRequest, OpReply } from '../../mongodb';
@@ -14,11 +15,21 @@ describe('commands', function () {
1415
context('when there is one document sequence', function () {
1516
const command = {
1617
test: 1,
17-
field: new DocumentSequence('test', [{ test: 1 }])
18+
field: new DocumentSequence([{ test: 1 }])
1819
};
1920
const msg = new OpMsgRequest('admin', command, {});
2021
const buffers = msg.toBin();
2122

23+
it('keeps the first section as type 0', function () {
24+
// The type byte for the first section is at index 1.
25+
expect(buffers[1][0]).to.equal(0);
26+
});
27+
28+
it('does not serialize the document sequences in the first section', function () {
29+
// Buffer at index 2 is the type 0 section - one document.
30+
expect(BSON.deserialize(buffers[2])).to.deep.equal({ test: 1, $db: 'admin' });
31+
});
32+
2233
it('removes the document sequence fields from the command', function () {
2334
expect(command).to.not.haveOwnProperty('field');
2435
});
@@ -42,12 +53,22 @@ describe('commands', function () {
4253
context('when there are multiple document sequences', function () {
4354
const command = {
4455
test: 1,
45-
fieldOne: new DocumentSequence('test', [{ test: 1 }]),
46-
fieldTwo: new DocumentSequence('test', [{ test: 1 }])
56+
fieldOne: new DocumentSequence([{ test: 1 }]),
57+
fieldTwo: new DocumentSequence([{ test: 1 }])
4758
};
4859
const msg = new OpMsgRequest('admin', command, {});
4960
const buffers = msg.toBin();
5061

62+
it('keeps the first section as type 0', function () {
63+
// The type byte for the first section is at index 1.
64+
expect(buffers[1][0]).to.equal(0);
65+
});
66+
67+
it('does not serialize the document sequences in the first section', function () {
68+
// Buffer at index 2 is the type 0 section - one document.
69+
expect(BSON.deserialize(buffers[2])).to.deep.equal({ test: 1, $db: 'admin' });
70+
});
71+
5172
it('removes the document sequence fields from the command', function () {
5273
expect(command).to.not.haveOwnProperty('fieldOne');
5374
expect(command).to.not.haveOwnProperty('fieldTwo');

0 commit comments

Comments
 (0)