Skip to content

Commit fb0b27d

Browse files
authored
refactor(NODE-3405): implement MongoRuntimeError children (#2913)
1 parent 7785e07 commit fb0b27d

File tree

14 files changed

+109
-118
lines changed

14 files changed

+109
-118
lines changed

src/change_stream.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
isResumableError,
66
MongoDriverError,
77
MongoAPIError,
8-
MongoChangeStreamError
8+
MongoChangeStreamError,
9+
MongoRuntimeError
910
} from './error';
1011
import { AggregateOperation, AggregateOptions } from './operations/aggregate';
1112
import {
@@ -558,8 +559,9 @@ function setIsEmitter<TSchema>(changeStream: ChangeStream<TSchema>): void {
558559

559560
function setIsIterator<TSchema>(changeStream: ChangeStream<TSchema>): void {
560561
if (changeStream[kMode] === 'emitter') {
562+
// TODO(NODE-3485): Replace with MongoChangeStreamModeError
561563
throw new MongoAPIError(
562-
'ChangeStream cannot be used as an EventEmitter after being used as an iterator'
564+
'ChangeStream cannot be used as an iterator after being used as an EventEmitter'
563565
);
564566
}
565567
changeStream[kMode] = 'iterator';
@@ -683,15 +685,15 @@ function processNewChange<TSchema>(
683685
callback?: Callback<ChangeStreamDocument<TSchema>>
684686
) {
685687
if (changeStream[kClosed]) {
686-
// TODO(NODE-3405): Replace with MongoStreamClosedError
687-
if (callback) callback(new MongoDriverError(CHANGESTREAM_CLOSED_ERROR));
688+
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
689+
if (callback) callback(new MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
688690
return;
689691
}
690692

691693
// a null change means the cursor has been notified, implicitly closing the change stream
692694
if (change == null) {
693-
// TODO(NODE-3405): Replace with MongoStreamClosedError
694-
return closeWithError(changeStream, new MongoDriverError(CHANGESTREAM_CLOSED_ERROR), callback);
695+
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
696+
return closeWithError(changeStream, new MongoRuntimeError(CHANGESTREAM_CLOSED_ERROR), callback);
695697
}
696698

697699
if (change && !change._id) {
@@ -723,8 +725,8 @@ function processError<TSchema>(
723725

724726
// If the change stream has been closed explicitly, do not process error.
725727
if (changeStream[kClosed]) {
726-
// TODO(NODE-3405): Replace with MongoStreamClosedError
727-
if (callback) callback(new MongoDriverError(CHANGESTREAM_CLOSED_ERROR));
728+
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
729+
if (callback) callback(new MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
728730
return;
729731
}
730732

@@ -784,8 +786,8 @@ function processError<TSchema>(
784786
*/
785787
function getCursor<T>(changeStream: ChangeStream<T>, callback: Callback<ChangeStreamCursor<T>>) {
786788
if (changeStream[kClosed]) {
787-
// TODO(NODE-3405): Replace with MongoStreamClosedError
788-
callback(new MongoDriverError(CHANGESTREAM_CLOSED_ERROR));
789+
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
790+
callback(new MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
789791
return;
790792
}
791793

@@ -810,8 +812,8 @@ function processResumeQueue<TSchema>(changeStream: ChangeStream<TSchema>, err?:
810812
const request = changeStream[kResumeQueue].pop();
811813
if (!err) {
812814
if (changeStream[kClosed]) {
813-
// TODO(NODE-3405): Replace with MongoStreamClosedError
814-
request(new MongoDriverError(CHANGESTREAM_CLOSED_ERROR));
815+
// TODO(NODE-3485): Replace with MongoChangeStreamClosedError
816+
request(new MongoAPIError(CHANGESTREAM_CLOSED_ERROR));
815817
return;
816818
}
817819
if (!changeStream.cursor) {

src/cmap/commands.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export class Query {
8484

8585
// Validate that we are not passing 0x00 in the collection name
8686
if (ns.indexOf('\x00') !== -1) {
87-
// TODO(NODE-3483): Replace with MongoCommandError
87+
// TODO(NODE-3483): Use MongoNamespace static method
8888
throw new MongoDriverError('Namespace cannot contain a null character');
8989
}
9090

src/cmap/connection_pool.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ import { Logger } from '../logger';
55
import { ConnectionPoolMetrics } from './metrics';
66
import { connect } from './connect';
77
import { eachAsync, makeCounter, Callback } from '../utils';
8-
import { MongoDriverError, MongoError, MongoInvalidArgumentError } from '../error';
8+
import {
9+
MongoError,
10+
MongoInvalidArgumentError,
11+
MongoDriverError,
12+
MongoRuntimeError
13+
} from '../error';
914
import { PoolClosedError, WaitQueueTimeoutError } from './errors';
1015
import {
1116
ConnectionPoolCreatedEvent,
@@ -388,7 +393,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
388393
clearTimeout(waitQueueMember.timer);
389394
}
390395
if (!waitQueueMember[kCancelled]) {
391-
waitQueueMember.callback(new MongoDriverError('connection pool closed'));
396+
// TODO(NODE-3483): Replace with MongoConnectionPoolClosedError
397+
waitQueueMember.callback(new MongoRuntimeError('Connection pool closed'));
392398
}
393399
}
394400
}

src/error.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,8 @@ export class MongoRuntimeError extends MongoDriverError {
226226
* @category Error
227227
*/
228228
export class MongoBatchReExecutionError extends MongoAPIError {
229-
constructor(message?: string) {
230-
super(message || 'This batch has already been executed, create new batch to execute');
229+
constructor(message = 'This batch has already been executed, create new batch to execute') {
230+
super(message);
231231
}
232232

233233
get name(): string {
@@ -294,7 +294,7 @@ export class MongoTransactionError extends MongoAPIError {
294294
* @category Error
295295
*/
296296
export class MongoExpiredSessionError extends MongoAPIError {
297-
constructor(message: string) {
297+
constructor(message = 'Cannot use a session that has ended') {
298298
super(message);
299299
}
300300

@@ -343,8 +343,8 @@ export class MongoChangeStreamError extends MongoRuntimeError {
343343
* @category Error
344344
*/
345345
export class MongoTailableCursorError extends MongoAPIError {
346-
constructor(message?: string) {
347-
super(message || 'Tailable cursor does not support this operation');
346+
constructor(message = 'Tailable cursor does not support this operation') {
347+
super(message);
348348
}
349349

350350
get name(): string {
@@ -392,8 +392,8 @@ export class MongoGridFSChunkError extends MongoRuntimeError {
392392
* @category Error
393393
*/
394394
export class MongoCursorInUseError extends MongoAPIError {
395-
constructor(message?: string) {
396-
super(message || 'Cursor is already initialized');
395+
constructor(message = 'Cursor is already initialized') {
396+
super(message);
397397
}
398398

399399
get name(): string {
@@ -409,7 +409,7 @@ export class MongoCursorInUseError extends MongoAPIError {
409409
* @category Error
410410
*/
411411
export class MongoServerClosedError extends MongoAPIError {
412-
constructor(message: string) {
412+
constructor(message = 'Server is closed') {
413413
super(message);
414414
}
415415

@@ -442,7 +442,7 @@ export class MongoCursorExhaustedError extends MongoAPIError {
442442
* @category Error
443443
*/
444444
export class MongoTopologyClosedError extends MongoAPIError {
445-
constructor(message: string) {
445+
constructor(message = 'Topology is closed') {
446446
super(message);
447447
}
448448

src/gridfs/upload.ts

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,8 @@ import { Writable } from 'stream';
22
import type { Document } from '../bson';
33
import { ObjectId } from '../bson';
44
import type { Collection } from '../collection';
5-
import {
6-
AnyError,
7-
MONGODB_ERROR_CODES,
8-
MongoDriverError,
9-
MongoError,
10-
MongoGridFSStreamError
11-
} from '../error';
12-
import { PromiseProvider } from '../promise_provider';
13-
import type { Callback } from '../utils';
5+
import { AnyError, MONGODB_ERROR_CODES, MongoError, MongoAPIError } from '../error';
6+
import { Callback, maybePromise } from '../utils';
147
import type { WriteConcernOptions } from '../write_concern';
158
import { WriteConcern } from './../write_concern';
169
import type { GridFSFile } from './download';
@@ -149,27 +142,19 @@ export class GridFSBucketWriteStream extends Writable {
149142
abort(): Promise<void>;
150143
abort(callback: Callback<void>): void;
151144
abort(callback?: Callback<void>): Promise<void> | void {
152-
const Promise = PromiseProvider.get();
153-
let error: MongoGridFSStreamError;
154-
if (this.state.streamEnd) {
155-
// TODO(NODE-3405): Replace with MongoStreamClosedError
156-
error = new MongoDriverError('Cannot abort a stream that has already completed');
157-
if (typeof callback === 'function') {
158-
return callback(error);
145+
return maybePromise(callback, callback => {
146+
if (this.state.streamEnd) {
147+
// TODO(NODE-3485): Replace with MongoGridFSStreamClosed
148+
return callback(new MongoAPIError('Cannot abort a stream that has already completed'));
159149
}
160-
return Promise.reject(error);
161-
}
162-
if (this.state.aborted) {
163-
// TODO(NODE-3405): Replace with MongoStreamClosedError
164-
error = new MongoDriverError('Cannot call abort() on a stream twice');
165-
if (typeof callback === 'function') {
166-
return callback(error);
150+
151+
if (this.state.aborted) {
152+
// TODO(NODE-3485): Replace with MongoGridFSStreamClosed
153+
return callback(new MongoAPIError('Cannot call abort() on a stream twice'));
167154
}
168-
return Promise.reject(error);
169-
}
170-
this.state.aborted = true;
171-
this.chunks.deleteMany({ files_id: this.id }, error => {
172-
if (typeof callback === 'function') callback(error);
155+
156+
this.state.aborted = true;
157+
this.chunks.deleteMany({ files_id: this.id }, error => callback(error));
173158
});
174159
}
175160

@@ -565,8 +550,8 @@ function writeRemnant(stream: GridFSBucketWriteStream, callback?: Callback): boo
565550
function checkAborted(stream: GridFSBucketWriteStream, callback?: Callback<void>): boolean {
566551
if (stream.state.aborted) {
567552
if (typeof callback === 'function') {
568-
// TODO(NODE-3405): Replace with MongoStreamClosedError
569-
callback(new MongoDriverError('this stream has been aborted'));
553+
// TODO(NODE-3485): Replace with MongoGridFSStreamClosedError
554+
callback(new MongoAPIError('Stream has been aborted'));
570555
}
571556
return true;
572557
}

src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ export {
5252
MongoBatchReExecutionError,
5353
MongoCursorExhaustedError,
5454
MongoCursorInUseError,
55-
MongoNotConnectedError
55+
MongoNotConnectedError,
56+
MongoExpiredSessionError,
57+
MongoTransactionError,
58+
MongoKerberosError,
59+
MongoServerClosedError,
60+
MongoTopologyClosedError
5661
} from './error';
5762
export { MongoBulkWriteError, BulkWriteOptions, AnyBulkWriteOperation } from './bulk/common';
5863
export {

src/operations/common_functions.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MongoDriverError } from '../error';
1+
import { MongoTopologyClosedError } from '../error';
22
import { Callback, getTopology } from '../utils';
33
import type { Document } from '../bson';
44
import type { Db } from '../db';
@@ -41,8 +41,7 @@ export function indexInformation(
4141
const full = options.full == null ? false : options.full;
4242

4343
// Did the user destroy the topology
44-
if (getTopology(db).isDestroyed())
45-
return callback(new MongoDriverError('topology was destroyed'));
44+
if (getTopology(db).isDestroyed()) return callback(new MongoTopologyClosedError());
4645
// Process all the results from the index command and collection
4746
function processResults(indexes: any) {
4847
// Contains all the information

src/operations/execute_operation.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import {
66
MongoDriverError,
77
MongoNetworkError,
88
MongoCompatibilityError,
9-
MongoServerError
9+
MongoServerError,
10+
MongoExpiredSessionError,
11+
MongoTransactionError
1012
} from '../error';
1113
import { Aspect, AbstractOperation } from './operation';
1214
import { maxWireVersion, maybePromise, Callback } from '../utils';
@@ -88,10 +90,9 @@ export function executeOperation<
8890
owner = Symbol();
8991
session = topology.startSession({ owner, explicit: false });
9092
} else if (session.hasEnded) {
91-
// TODO(NODE-3405): Change this out for MongoExpiredSessionError
92-
return cb(new MongoDriverError('Use of expired sessions is not permitted'));
93+
return cb(new MongoExpiredSessionError('Use of expired sessions is not permitted'));
9394
} else if (session.snapshotEnabled && !topology.capabilities.supportsSnapshotReads) {
94-
return cb(new MongoDriverError('Snapshot reads require MongoDB 5.0 or later'));
95+
return cb(new MongoCompatibilityError('Snapshot reads require MongoDB 5.0 or later'));
9596
}
9697
} else if (session) {
9798
// If the user passed an explicit session and we are still, after server selection,
@@ -132,8 +133,7 @@ function executeWithServerSelection(
132133

133134
if (inTransaction && !readPreference.equals(ReadPreference.primary)) {
134135
callback(
135-
// TODO(NODE-3405): Change this out for MongoTransactionError
136-
new MongoDriverError(
136+
new MongoTransactionError(
137137
`Read preference in a transaction must be primary, not: ${readPreference.mode}`
138138
)
139139
);
@@ -218,8 +218,7 @@ function executeWithServerSelection(
218218
session.inTransaction()
219219
) {
220220
callback(
221-
// TODO(NODE-3405): Change this out for MongoTransactionError
222-
new MongoDriverError(
221+
new MongoTransactionError(
223222
`Read preference in a transaction must be primary, not: ${readPreference.mode}`
224223
)
225224
);

src/sdam/server.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ import {
3333
isRetryableWriteError,
3434
isNodeShuttingDownError,
3535
isNetworkErrorBeforeHandshake,
36-
MongoDriverError,
3736
MongoCompatibilityError,
38-
MongoInvalidArgumentError
37+
MongoInvalidArgumentError,
38+
MongoServerClosedError
3939
} from '../error';
4040
import {
4141
Connection,
@@ -292,8 +292,7 @@ export class Server extends TypedEventEmitter<ServerEvents> {
292292
}
293293

294294
if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
295-
// TODO(NODE-3405): Change this out for MongoServerClosedError
296-
callback(new MongoDriverError('Server is closed'));
295+
callback(new MongoServerClosedError());
297296
return;
298297
}
299298

@@ -351,7 +350,7 @@ export class Server extends TypedEventEmitter<ServerEvents> {
351350
*/
352351
query(ns: MongoDBNamespace, cmd: Document, options: QueryOptions, callback: Callback): void {
353352
if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
354-
callback(new MongoDriverError('server is closed'));
353+
callback(new MongoServerClosedError());
355354
return;
356355
}
357356

@@ -385,7 +384,7 @@ export class Server extends TypedEventEmitter<ServerEvents> {
385384
callback: Callback<Document>
386385
): void {
387386
if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
388-
callback(new MongoDriverError('server is closed'));
387+
callback(new MongoServerClosedError());
389388
return;
390389
}
391390

@@ -420,7 +419,7 @@ export class Server extends TypedEventEmitter<ServerEvents> {
420419
): void {
421420
if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
422421
if (typeof callback === 'function') {
423-
callback(new MongoDriverError('server is closed'));
422+
callback(new MongoServerClosedError());
424423
}
425424

426425
return;

src/sdam/topology.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ import {
1111
} from '../sessions';
1212
import { SrvPoller, SrvPollingEvent } from './srv_polling';
1313
import { CMAP_EVENTS, ConnectionPoolEvents } from '../cmap/connection_pool';
14-
import { MongoServerSelectionError, MongoCompatibilityError, MongoDriverError } from '../error';
14+
import {
15+
MongoServerSelectionError,
16+
MongoCompatibilityError,
17+
MongoDriverError,
18+
MongoTopologyClosedError
19+
} from '../error';
1520
import { readPreferenceServerSelector, ServerSelector } from './server_selection';
1621
import {
1722
makeStateMachine,
@@ -491,7 +496,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
491496

492497
stateTransition(this, STATE_CLOSING);
493498

494-
drainWaitQueue(this[kWaitQueue], new MongoDriverError('Topology closed'));
499+
drainWaitQueue(this[kWaitQueue], new MongoTopologyClosedError());
495500
drainTimerQueue(this.s.connectionTimers);
496501

497502
if (this.s.srvPoller) {
@@ -982,10 +987,7 @@ function drainWaitQueue(queue: Denque<ServerSelectionRequest>, err?: MongoDriver
982987

983988
function processWaitQueue(topology: Topology) {
984989
if (topology.s.state === STATE_CLOSED) {
985-
drainWaitQueue(
986-
topology[kWaitQueue],
987-
new MongoDriverError('Topology is closed, please connect')
988-
);
990+
drainWaitQueue(topology[kWaitQueue], new MongoTopologyClosedError());
989991
return;
990992
}
991993

0 commit comments

Comments
 (0)