Skip to content

Commit 63b16cf

Browse files
committed
wip
1 parent cf5d985 commit 63b16cf

File tree

7 files changed

+61
-69
lines changed

7 files changed

+61
-69
lines changed

src/cmap/connection.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ import {
2020
MongoNetworkTimeoutError,
2121
MongoParseError,
2222
MongoServerError,
23-
MongoUnexpectedServerResponseError,
24-
MongoWriteConcernError
23+
MongoUnexpectedServerResponseError
2524
} from '../error';
2625
import type { ServerApi, SupportedNodeConnectionOptions } from '../mongo_client';
2726
import { type MongoClientAuthProviders } from '../mongo_client_auth_providers';
@@ -510,7 +509,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
510509
this.emit(Connection.CLUSTER_TIME_RECEIVED, document.$clusterTime);
511510
}
512511

513-
if (document.isError) {
512+
if (document.ok === 0) {
514513
throw new MongoServerError((object ??= document.toObject(bsonOptions)));
515514
}
516515

@@ -573,16 +572,8 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
573572
): Promise<Document> {
574573
this.throwIfAborted();
575574
for await (const document of this.sendCommand(ns, command, options, responseType)) {
576-
if (
577-
(MongoDBResponse.is(document) && document.has('writeConcernError')) ||
578-
(!MongoDBResponse.is(document) && document.writeConcernError)
579-
) {
580-
const object = MongoDBResponse.is(document) ? document.toObject(options) : document;
581-
throw new MongoWriteConcernError(object.writeConcernError, object);
582-
}
583575
return document;
584576
}
585-
586577
throw new MongoUnexpectedServerResponseError('Unable to get response from server');
587578
}
588579

src/cmap/wire_protocol/responses.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,6 @@ export class MongoDBResponse extends OnDemandDocument {
8181
// {ok:1}
8282
static empty = new MongoDBResponse(new Uint8Array([13, 0, 0, 0, 16, 111, 107, 0, 1, 0, 0, 0, 0]));
8383

84-
/** Indicates this document is a server error */
85-
public get isError() {
86-
let isError = this.ok === 0;
87-
isError ||= this.has('errmsg');
88-
isError ||= this.has('code');
89-
isError ||= this.has('$err'); // The '$err' field is used in OP_REPLY responses
90-
return isError;
91-
}
92-
9384
/**
9485
* Drivers can safely assume that the `recoveryToken` field is always a BSON document but drivers MUST NOT modify the
9586
* contents of the document.
@@ -120,6 +111,7 @@ export class MongoDBResponse extends OnDemandDocument {
120111
return this.get('operationTime', BSONType.timestamp);
121112
}
122113

114+
/** Normalizes whatever BSON value is "ok" to a JS number 1 or 0. */
123115
public get ok(): 0 | 1 {
124116
return this.getNumber('ok') ? 1 : 0;
125117
}
@@ -174,7 +166,7 @@ export class MongoDBResponse extends OnDemandDocument {
174166
encryptedResponse?: MongoDBResponse;
175167
}
176168

177-
// Here's a litle blast from the past.
169+
// Here's a little blast from the past.
178170
// OLD style method definition so that I can override get without redefining ALL the fancy TS :/
179171
Object.defineProperty(MongoDBResponse.prototype, 'get', {
180172
value: function get(name: any, as: any, required: any) {
@@ -210,7 +202,11 @@ export class CursorResponse extends MongoDBResponse {
210202
}
211203

212204
public get id(): Long {
213-
return Long.fromBigInt(this.cursor.get('id', BSONType.long, true));
205+
try {
206+
return Long.fromBigInt(this.cursor.get('id', BSONType.long, true));
207+
} catch (cause) {
208+
throw new MongoUnexpectedServerResponseError(cause.message, { cause });
209+
}
214210
}
215211

216212
public get ns() {

test/integration/collection-management/collection.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,13 @@ describe('Collection', function () {
458458
expect(countC).to.be.a('number').that.equals(0);
459459
});
460460

461+
it('does not mutate options', async () => {
462+
const options = Object.freeze(Object.create(null));
463+
const count = await collection.countDocuments({}, options);
464+
expect(count).to.be.a('number').that.equals(100);
465+
expect(options).to.deep.equal({});
466+
});
467+
461468
context('when a filter is applied', () => {
462469
it('adds a $match pipeline', async () => {
463470
await collection.countDocuments({ test: 'a' });

test/unit/assorted/sessions_collection.test.js

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,27 +48,5 @@ describe('Sessions - unit/sessions', function () {
4848
return client.close();
4949
});
5050
});
51-
52-
it('does not mutate command options', function () {
53-
const options = Object.freeze({});
54-
test.server.setMessageHandler(request => {
55-
const doc = request.document;
56-
if (isHello(doc)) {
57-
request.reply(mock.HELLO);
58-
} else if (doc.count || doc.aggregate || doc.endSessions) {
59-
request.reply({ ok: 1 });
60-
}
61-
});
62-
63-
const client = new MongoClient(`mongodb://${test.server.uri()}/test`);
64-
return client.connect().then(client => {
65-
const coll = client.db('foo').collection('bar');
66-
67-
return coll.countDocuments({}, options).then(() => {
68-
expect(options).to.deep.equal({});
69-
return client.close();
70-
});
71-
});
72-
});
7351
});
7452
});

test/unit/client-side-encryption/auto_encrypter.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ describe('AutoEncrypter', function () {
162162
local: { key: Buffer.alloc(96) }
163163
}
164164
});
165-
const decrypted = await mc.decrypt(input);
165+
const decrypted = BSON.deserialize(await mc.decrypt(input));
166166
expect(decrypted).to.eql({ filter: { find: 'test', ssn: '457-55-5462' } });
167167
expect(decrypted).to.not.have.property(Symbol.for('@@mdb.decryptedKeys'));
168168
expect(decrypted.filter).to.not.have.property(Symbol.for('@@mdb.decryptedKeys'));
@@ -186,7 +186,7 @@ describe('AutoEncrypter', function () {
186186
}
187187
});
188188
mc[Symbol.for('@@mdb.decorateDecryptionResult')] = true;
189-
let decrypted = await mc.decrypt(input);
189+
let decrypted = BSON.deserialize(await mc.decrypt(input));
190190
expect(decrypted).to.eql({ filter: { find: 'test', ssn: '457-55-5462' } });
191191
expect(decrypted).to.not.have.property(Symbol.for('@@mdb.decryptedKeys'));
192192
expect(decrypted.filter[Symbol.for('@@mdb.decryptedKeys')]).to.eql(['ssn']);
@@ -243,7 +243,7 @@ describe('AutoEncrypter', function () {
243243
aws: {}
244244
}
245245
});
246-
const decrypted = await mc.decrypt(input);
246+
const decrypted = BSON.deserialize(await mc.decrypt(input));
247247
expect(decrypted).to.eql({ filter: { find: 'test', ssn: '457-55-5462' } });
248248
});
249249
});

test/unit/cmap/wire_protocol/responses.test.ts

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -86,30 +86,58 @@ describe('class MongoDBResponse', () => {
8686
});
8787

8888
describe('class CursorResponse', () => {
89-
describe('constructor()', () => {
89+
describe('get cursor()', () => {
9090
it('throws if input does not contain cursor embedded document', () => {
91-
expect(() => new CursorResponse(BSON.serialize({ ok: 1 }))).to.throw(BSONError);
91+
// @ts-expect-error: testing private getter
92+
expect(() => new CursorResponse(BSON.serialize({ ok: 1 })).cursor).to.throw(
93+
MongoUnexpectedServerResponseError
94+
);
9295
});
96+
});
9397

98+
describe('get id()', () => {
9499
it('throws if input does not contain cursor.id int64', () => {
95-
expect(() => new CursorResponse(BSON.serialize({ ok: 1, cursor: {} }))).to.throw(BSONError);
100+
expect(() => new CursorResponse(BSON.serialize({ ok: 1, cursor: {} })).id).to.throw(
101+
MongoUnexpectedServerResponseError
102+
);
103+
});
104+
});
105+
106+
describe('get batch()', () => {
107+
it('throws if input does not contain firstBatch nor nextBatch', () => {
108+
expect(
109+
// @ts-expect-error: testing private getter
110+
() => new CursorResponse(BSON.serialize({ ok: 1, cursor: { id: 0n, batch: [] } })).batch
111+
).to.throw(MongoUnexpectedServerResponseError);
96112
});
113+
});
97114

115+
describe('get ns()', () => {
98116
it('sets namespace to null if input does not contain cursor.ns', () => {
99117
expect(new CursorResponse(BSON.serialize({ ok: 1, cursor: { id: 0n, firstBatch: [] } })).ns)
100118
.to.be.null;
101119
});
120+
});
102121

103-
it('throws if input does not contain firstBatch nor nextBatch', () => {
104-
expect(
105-
() => new CursorResponse(BSON.serialize({ ok: 1, cursor: { id: 0n, batch: [] } }))
106-
).to.throw(MongoUnexpectedServerResponseError);
122+
describe('get batchSize()', () => {
123+
it('reports the returned batch size', () => {
124+
const response = new CursorResponse(
125+
BSON.serialize({ ok: 1, cursor: { id: 0n, nextBatch: [{}, {}, {}] } })
126+
);
127+
expect(response.batchSize).to.equal(3);
128+
expect(response.shift()).to.deep.equal({});
129+
expect(response.batchSize).to.equal(3);
107130
});
131+
});
108132

109-
it('reports a length equal to the batch', () => {
110-
expect(
111-
new CursorResponse(BSON.serialize({ ok: 1, cursor: { id: 0n, nextBatch: [1, 2, 3] } }))
112-
).to.have.lengthOf(3);
133+
describe('get length()', () => {
134+
it('reports number of documents remaining in the batch', () => {
135+
const response = new CursorResponse(
136+
BSON.serialize({ ok: 1, cursor: { id: 0n, nextBatch: [{}, {}, {}] } })
137+
);
138+
expect(response).to.have.lengthOf(3);
139+
expect(response.shift()).to.deep.equal({});
140+
expect(response).to.have.lengthOf(2); // length makes CursorResponse act like an array
113141
});
114142
});
115143

@@ -162,12 +190,4 @@ describe('class CursorResponse', () => {
162190
expect(response.shift()).to.be.null;
163191
});
164192
});
165-
166-
describe('pushMany()', () =>
167-
it('throws unsupported error', () =>
168-
expect(CursorResponse.prototype.pushMany).to.throw(/Unsupported/i)));
169-
170-
describe('push()', () =>
171-
it('throws unsupported error', () =>
172-
expect(CursorResponse.prototype.push).to.throw(/Unsupported/i)));
173193
});

test/unit/error.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ describe('MongoErrors', () => {
301301
};
302302

303303
const RAW_USER_WRITE_CONCERN_ERROR = {
304-
ok: 0,
304+
ok: 1,
305305
errmsg: 'waiting for replication timed out',
306306
code: 64,
307307
codeName: 'WriteConcernFailed',
@@ -316,7 +316,7 @@ describe('MongoErrors', () => {
316316
};
317317

318318
const RAW_USER_WRITE_CONCERN_ERROR_INFO = {
319-
ok: 0,
319+
ok: 1,
320320
errmsg: 'waiting for replication timed out',
321321
code: 64,
322322
codeName: 'WriteConcernFailed',
@@ -367,7 +367,7 @@ describe('MongoErrors', () => {
367367
replSet.connect();
368368
}
369369

370-
it('should expose a user command writeConcern error like a normal WriteConcernError', function () {
370+
it.only('should expose a user command writeConcern error like a normal WriteConcernError', function () {
371371
test.primaryServer.setMessageHandler(request => {
372372
const doc = request.document;
373373
if (isHello(doc)) {

0 commit comments

Comments
 (0)