Skip to content

Commit 967c193

Browse files
authored
refactor(NODE-3402): implement MongoAPIError and its children (#2891)
1 parent c67daea commit 967c193

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+522
-309
lines changed

src/bulk/common.ts

+17-14
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
AnyError,
66
MONGODB_ERROR_CODES,
77
MongoServerError,
8-
MongoDriverError
8+
MongoDriverError,
9+
MongoInvalidArgumentError
910
} from '../error';
1011
import {
1112
applyRetryableWrites,
@@ -753,7 +754,7 @@ export class FindOperators {
753754
/** Add a single update operation to the bulk operation */
754755
updateOne(updateDocument: Document): BulkOperationBase {
755756
if (!hasAtomicOperators(updateDocument)) {
756-
throw new MongoDriverError('Update document requires atomic operators');
757+
throw new MongoInvalidArgumentError('Update document requires atomic operators');
757758
}
758759

759760
const currentOp = buildCurrentOp(this.bulkOperation);
@@ -766,7 +767,7 @@ export class FindOperators {
766767
/** Add a replace one operation to the bulk operation */
767768
replaceOne(replacement: Document): BulkOperationBase {
768769
if (hasAtomicOperators(replacement)) {
769-
throw new MongoDriverError('Replacement document must not use atomic operators');
770+
throw new MongoInvalidArgumentError('Replacement document must not use atomic operators');
770771
}
771772

772773
const currentOp = buildCurrentOp(this.bulkOperation);
@@ -1049,7 +1050,7 @@ export abstract class BulkOperationBase {
10491050
*/
10501051
find(selector: Document): FindOperators {
10511052
if (!selector) {
1052-
throw new MongoDriverError('Bulk find operation must specify a selector');
1053+
throw new MongoInvalidArgumentError('Bulk find operation must specify a selector');
10531054
}
10541055

10551056
// Save a current selector
@@ -1083,51 +1084,51 @@ export abstract class BulkOperationBase {
10831084
if ('replaceOne' in op || 'updateOne' in op || 'updateMany' in op) {
10841085
if ('replaceOne' in op) {
10851086
if ('q' in op.replaceOne) {
1086-
throw new MongoDriverError('Raw operations are not allowed');
1087+
throw new MongoInvalidArgumentError('Raw operations are not allowed');
10871088
}
10881089
const updateStatement = makeUpdateStatement(
10891090
op.replaceOne.filter,
10901091
op.replaceOne.replacement,
10911092
{ ...op.replaceOne, multi: false }
10921093
);
10931094
if (hasAtomicOperators(updateStatement.u)) {
1094-
throw new MongoDriverError('Replacement document must not use atomic operators');
1095+
throw new MongoInvalidArgumentError('Replacement document must not use atomic operators');
10951096
}
10961097
return this.addToOperationsList(BatchType.UPDATE, updateStatement);
10971098
}
10981099

10991100
if ('updateOne' in op) {
11001101
if ('q' in op.updateOne) {
1101-
throw new MongoDriverError('Raw operations are not allowed');
1102+
throw new MongoInvalidArgumentError('Raw operations are not allowed');
11021103
}
11031104
const updateStatement = makeUpdateStatement(op.updateOne.filter, op.updateOne.update, {
11041105
...op.updateOne,
11051106
multi: false
11061107
});
11071108
if (!hasAtomicOperators(updateStatement.u)) {
1108-
throw new MongoDriverError('Update document requires atomic operators');
1109+
throw new MongoInvalidArgumentError('Update document requires atomic operators');
11091110
}
11101111
return this.addToOperationsList(BatchType.UPDATE, updateStatement);
11111112
}
11121113

11131114
if ('updateMany' in op) {
11141115
if ('q' in op.updateMany) {
1115-
throw new MongoDriverError('Raw operations are not allowed');
1116+
throw new MongoInvalidArgumentError('Raw operations are not allowed');
11161117
}
11171118
const updateStatement = makeUpdateStatement(op.updateMany.filter, op.updateMany.update, {
11181119
...op.updateMany,
11191120
multi: true
11201121
});
11211122
if (!hasAtomicOperators(updateStatement.u)) {
1122-
throw new MongoDriverError('Update document requires atomic operators');
1123+
throw new MongoInvalidArgumentError('Update document requires atomic operators');
11231124
}
11241125
return this.addToOperationsList(BatchType.UPDATE, updateStatement);
11251126
}
11261127
}
11271128

11281129
if ('deleteOne' in op) {
11291130
if ('q' in op.deleteOne) {
1130-
throw new MongoDriverError('Raw operations are not allowed');
1131+
throw new MongoInvalidArgumentError('Raw operations are not allowed');
11311132
}
11321133
return this.addToOperationsList(
11331134
BatchType.DELETE,
@@ -1137,7 +1138,7 @@ export abstract class BulkOperationBase {
11371138

11381139
if ('deleteMany' in op) {
11391140
if ('q' in op.deleteMany) {
1140-
throw new MongoDriverError('Raw operations are not allowed');
1141+
throw new MongoInvalidArgumentError('Raw operations are not allowed');
11411142
}
11421143
return this.addToOperationsList(
11431144
BatchType.DELETE,
@@ -1146,7 +1147,7 @@ export abstract class BulkOperationBase {
11461147
}
11471148

11481149
// otherwise an unknown operation was provided
1149-
throw new MongoDriverError(
1150+
throw new MongoInvalidArgumentError(
11501151
'bulkWrite only supports insertOne, updateOne, updateMany, deleteOne, deleteMany'
11511152
);
11521153
}
@@ -1198,7 +1199,9 @@ export abstract class BulkOperationBase {
11981199
}
11991200
// If we have no operations in the bulk raise an error
12001201
if (this.s.batches.length === 0) {
1201-
const emptyBatchError = new MongoDriverError('Invalid BulkOperation, Batch cannot be empty');
1202+
const emptyBatchError = new MongoInvalidArgumentError(
1203+
'Invalid BulkOperation, Batch cannot be empty'
1204+
);
12021205
return handleEarlyError(emptyBatchError, callback);
12031206
}
12041207

src/bulk/ordered.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Document } from '../bson';
44
import type { Collection } from '../collection';
55
import type { UpdateStatement } from '../operations/update';
66
import type { DeleteStatement } from '../operations/delete';
7-
import { MongoDriverError } from '../error';
7+
import { MongoInvalidArgumentError } from '../error';
88

99
/** @public */
1010
export class OrderedBulkOperation extends BulkOperationBase {
@@ -26,7 +26,8 @@ export class OrderedBulkOperation extends BulkOperationBase {
2626

2727
// Throw error if the doc is bigger than the max BSON size
2828
if (bsonSize >= this.s.maxBsonObjectSize)
29-
throw new MongoDriverError(
29+
// TODO(NODE-3483): Change this to MongoBSONError
30+
throw new MongoInvalidArgumentError(
3031
`Document is larger than the maximum size ${this.s.maxBsonObjectSize}`
3132
);
3233

@@ -68,7 +69,7 @@ export class OrderedBulkOperation extends BulkOperationBase {
6869

6970
// We have an array of documents
7071
if (Array.isArray(document)) {
71-
throw new MongoDriverError('Operation passed in cannot be an Array');
72+
throw new MongoInvalidArgumentError('Operation passed in cannot be an Array');
7273
}
7374

7475
this.s.currentBatch.originalIndexes.push(this.s.currentIndex);

src/bulk/unordered.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { Document } from '../bson';
55
import type { Collection } from '../collection';
66
import type { UpdateStatement } from '../operations/update';
77
import type { DeleteStatement } from '../operations/delete';
8-
import { MongoDriverError } from '../error';
8+
import { MongoInvalidArgumentError } from '../error';
99

1010
/** @public */
1111
export class UnorderedBulkOperation extends BulkOperationBase {
@@ -36,7 +36,8 @@ export class UnorderedBulkOperation extends BulkOperationBase {
3636

3737
// Throw error if the doc is bigger than the max BSON size
3838
if (bsonSize >= this.s.maxBsonObjectSize) {
39-
throw new MongoDriverError(
39+
// TODO(NODE-3483): Change this to MongoBSONError
40+
throw new MongoInvalidArgumentError(
4041
`Document is larger than the maximum size ${this.s.maxBsonObjectSize}`
4142
);
4243
}
@@ -79,7 +80,7 @@ export class UnorderedBulkOperation extends BulkOperationBase {
7980

8081
// We have an array of documents
8182
if (Array.isArray(document)) {
82-
throw new MongoDriverError('Operation passed in cannot be an Array');
83+
throw new MongoInvalidArgumentError('Operation passed in cannot be an Array');
8384
}
8485

8586
this.s.currentBatch.operations.push(document);

src/change_stream.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,9 @@ export class ChangeStream<TSchema extends Document = Document> extends TypedEven
259259
} else if (parent instanceof MongoClient) {
260260
this.type = CHANGE_DOMAIN_TYPES.CLUSTER;
261261
} else {
262+
// TODO(NODE-3404): Replace this with MongoChangeStreamError
262263
throw new MongoDriverError(
263-
'parent provided to ChangeStream constructor is not an instance of Collection, Db, or MongoClient'
264+
'Parent provided to ChangeStream constructor must an instance of Collection, Db, or MongoClient'
264265
);
265266
}
266267

@@ -364,6 +365,7 @@ export class ChangeStream<TSchema extends Document = Document> extends TypedEven
364365
*/
365366
stream(options?: CursorStreamOptions): Readable {
366367
this.streamOptions = options;
368+
// TODO(NODE-3404): Replace this with MongoChangeStreamError
367369
if (!this.cursor) throw new MongoDriverError(NO_CURSOR_ERROR);
368370
return this.cursor.stream(options);
369371
}

src/cmap/auth/auth_provider.ts

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export class AuthProvider {
5454
* @param callback - The callback to return the result from the authentication
5555
*/
5656
auth(context: AuthContext, callback: Callback): void {
57+
// TODO(NODE-3485): Replace this with MongoMethodOverrideError
5758
callback(new MongoDriverError('`auth` method must be overridden by subclass'));
5859
}
5960
}

src/cmap/auth/gssapi.ts

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { AuthProvider, AuthContext } from './auth_provider';
2-
import { MongoDriverError, MongoError } from '../../error';
2+
import {
3+
MongoDriverError,
4+
MongoInvalidArgumentError,
5+
MongoMissingCredentialsError,
6+
MongoError,
7+
MongoMissingDependencyError
8+
} from '../../error';
39
import { Kerberos, KerberosClient } from '../../deps';
410
import { Callback, ns } from '../../utils';
511
import type { Document } from '../../bson';
@@ -15,7 +21,10 @@ import * as dns from 'dns';
1521
export class GSSAPI extends AuthProvider {
1622
auth(authContext: AuthContext, callback: Callback): void {
1723
const { connection, credentials } = authContext;
18-
if (credentials == null) return callback(new MongoDriverError('credentials required'));
24+
if (credentials == null)
25+
return callback(
26+
new MongoMissingCredentialsError('Credentials required for GSSAPI authentication')
27+
);
1928
const { username } = credentials;
2029
function externalCommand(
2130
command: Document,
@@ -25,7 +34,7 @@ export class GSSAPI extends AuthProvider {
2534
}
2635
makeKerberosClient(authContext, (err, client) => {
2736
if (err) return callback(err);
28-
if (client == null) return callback(new MongoDriverError('gssapi client missing'));
37+
if (client == null) return callback(new MongoMissingDependencyError('GSSAPI client missing'));
2938
client.step('', (err, payload) => {
3039
if (err) return callback(err);
3140

@@ -66,7 +75,7 @@ function makeKerberosClient(authContext: AuthContext, callback: Callback<Kerbero
6675
const { credentials } = authContext;
6776
if (!hostAddress || typeof hostAddress.host !== 'string' || !credentials) {
6877
return callback(
69-
new MongoDriverError('Connection must have host and port and credentials defined.')
78+
new MongoInvalidArgumentError('Connection must have host and port and credentials defined.')
7079
);
7180
}
7281

src/cmap/auth/mongo_credentials.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Resolves the default auth mechanism according to
22

33
import type { Document } from '../../bson';
4-
import { MongoDriverError } from '../../error';
4+
import { MongoDriverError, MongoMissingCredentialsError } from '../../error';
55
import { AuthMechanism } from './defaultAuthProviders';
66

77
// https://github.com/mongodb/specifications/blob/master/source/auth/auth.rst
@@ -122,7 +122,7 @@ export class MongoCredentials {
122122
this.mechanism === AuthMechanism.MONGODB_SCRAM_SHA256) &&
123123
!this.username
124124
) {
125-
throw new MongoDriverError(`Username required for mechanism '${this.mechanism}'`);
125+
throw new MongoMissingCredentialsError(`Username required for mechanism '${this.mechanism}'`);
126126
}
127127

128128
if (
@@ -131,13 +131,15 @@ export class MongoCredentials {
131131
this.mechanism === AuthMechanism.MONGODB_X509
132132
) {
133133
if (this.source != null && this.source !== '$external') {
134+
// TODO(NODE-3483): Replace this with a MongoAuthValidationError
134135
throw new MongoDriverError(
135136
`Invalid source '${this.source}' for mechanism '${this.mechanism}' specified.`
136137
);
137138
}
138139
}
139140

140141
if (this.mechanism === AuthMechanism.MONGODB_PLAIN && this.source == null) {
142+
// TODO(NODE-3483): Replace this with a MongoAuthValidationError
141143
throw new MongoDriverError('PLAIN Authentication Mechanism needs an auth source');
142144
}
143145

@@ -146,6 +148,7 @@ export class MongoCredentials {
146148
Reflect.set(this, 'password', undefined);
147149
return;
148150
}
151+
// TODO(NODE-3483): Replace this with a MongoAuthValidationError
149152
throw new MongoDriverError(`Password not allowed for mechanism MONGODB-X509`);
150153
}
151154
}

src/cmap/auth/mongocr.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import * as crypto from 'crypto';
22
import { AuthProvider, AuthContext } from './auth_provider';
33
import { Callback, ns } from '../../utils';
4-
import { MongoDriverError } from '../../error';
4+
import { MongoMissingCredentialsError } from '../../error';
55

66
export class MongoCR extends AuthProvider {
77
auth(authContext: AuthContext, callback: Callback): void {
88
const { connection, credentials } = authContext;
99
if (!credentials) {
10-
return callback(new MongoDriverError('AuthContext must provide credentials.'));
10+
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
1111
}
1212
const username = credentials.username;
1313
const password = credentials.password;
@@ -24,7 +24,7 @@ export class MongoCR extends AuthProvider {
2424
let md5 = crypto.createHash('md5');
2525

2626
// Generate keys used for authentication
27-
md5.update(username + ':mongo:' + password, 'utf8');
27+
md5.update(`${username}:mongo:${password}`, 'utf8');
2828
const hash_password = md5.digest('hex');
2929

3030
// Final key

src/cmap/auth/mongodb_aws.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import * as url from 'url';
44
import * as BSON from '../../bson';
55
import { AuthProvider, AuthContext } from './auth_provider';
66
import { MongoCredentials } from './mongo_credentials';
7-
import { MongoDriverError } from '../../error';
7+
import {
8+
MongoDriverError,
9+
MongoMissingCredentialsError,
10+
MongoCompatibilityError
11+
} from '../../error';
812
import { maxWireVersion, Callback, ns } from '../../utils';
913
import type { BSONSerializeOptions } from '../../bson';
1014

@@ -32,7 +36,7 @@ export class MongoDBAWS extends AuthProvider {
3236
auth(authContext: AuthContext, callback: Callback): void {
3337
const { connection, credentials } = authContext;
3438
if (!credentials) {
35-
return callback(new MongoDriverError('AuthContext must provide credentials.'));
39+
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
3640
}
3741

3842
if ('kModuleError' in aws4) {
@@ -42,7 +46,9 @@ export class MongoDBAWS extends AuthProvider {
4246

4347
if (maxWireVersion(connection) < 9) {
4448
callback(
45-
new MongoDriverError('MONGODB-AWS authentication requires MongoDB version 4.4 or later')
49+
new MongoCompatibilityError(
50+
'MONGODB-AWS authentication requires MongoDB version 4.4 or later'
51+
)
4652
);
4753
return;
4854
}
@@ -149,7 +155,9 @@ interface AWSCredentials {
149155
function makeTempCredentials(credentials: MongoCredentials, callback: Callback<MongoCredentials>) {
150156
function done(creds: AWSCredentials) {
151157
if (!creds.AccessKeyId || !creds.SecretAccessKey || !creds.Token) {
152-
callback(new MongoDriverError('Could not obtain temporary MONGODB-AWS credentials'));
158+
callback(
159+
new MongoMissingCredentialsError('Could not obtain temporary MONGODB-AWS credentials')
160+
);
153161
return;
154162
}
155163

src/cmap/auth/plain.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { Binary } from '../../bson';
22
import { AuthProvider, AuthContext } from './auth_provider';
3-
import { MongoDriverError } from '../../error';
3+
import { MongoMissingCredentialsError } from '../../error';
44
import { Callback, ns } from '../../utils';
55

66
export class Plain extends AuthProvider {
77
auth(authContext: AuthContext, callback: Callback): void {
88
const { connection, credentials } = authContext;
99
if (!credentials) {
10-
return callback(new MongoDriverError('AuthContext must provide credentials.'));
10+
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
1111
}
1212
const username = credentials.username;
1313
const password = credentials.password;

0 commit comments

Comments
 (0)