Skip to content

refactor(NODE-3402): Implement MongoAPIError and its children #2883

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

Closed
25 changes: 13 additions & 12 deletions src/bulk/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
AnyError,
MONGODB_ERROR_CODES,
MongoServerError,
MongoDriverError
MongoDriverError,
MongoInvalidArgumentError
} from '../error';
import {
applyRetryableWrites,
Expand Down Expand Up @@ -753,7 +754,7 @@ export class FindOperators {
/** Add a single update operation to the bulk operation */
updateOne(updateDocument: Document): BulkOperationBase {
if (!hasAtomicOperators(updateDocument)) {
throw new MongoDriverError('Update document requires atomic operators');
throw new MongoInvalidArgumentError('Update document requires atomic operators');
}

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

const currentOp = buildCurrentOp(this.bulkOperation);
Expand Down Expand Up @@ -1049,7 +1050,7 @@ export abstract class BulkOperationBase {
*/
find(selector: Document): FindOperators {
if (!selector) {
throw new MongoDriverError('Bulk find operation must specify a selector');
throw new MongoInvalidArgumentError('Bulk find operation must specify a selector');
}

// Save a current selector
Expand Down Expand Up @@ -1083,51 +1084,51 @@ export abstract class BulkOperationBase {
if ('replaceOne' in op || 'updateOne' in op || 'updateMany' in op) {
if ('replaceOne' in op) {
if ('q' in op.replaceOne) {
throw new MongoDriverError('Raw operations are not allowed');
throw new MongoInvalidArgumentError('Raw operations are not allowed');
}
const updateStatement = makeUpdateStatement(
op.replaceOne.filter,
op.replaceOne.replacement,
{ ...op.replaceOne, multi: false }
);
if (hasAtomicOperators(updateStatement.u)) {
throw new MongoDriverError('Replacement document must not use atomic operators');
throw new MongoInvalidArgumentError('Replacement document must not use atomic operators');
}
return this.addToOperationsList(BatchType.UPDATE, updateStatement);
}

if ('updateOne' in op) {
if ('q' in op.updateOne) {
throw new MongoDriverError('Raw operations are not allowed');
throw new MongoInvalidArgumentError('Raw operations are not allowed');
}
const updateStatement = makeUpdateStatement(op.updateOne.filter, op.updateOne.update, {
...op.updateOne,
multi: false
});
if (!hasAtomicOperators(updateStatement.u)) {
throw new MongoDriverError('Update document requires atomic operators');
throw new MongoInvalidArgumentError('Update document requires atomic operators');
}
return this.addToOperationsList(BatchType.UPDATE, updateStatement);
}

if ('updateMany' in op) {
if ('q' in op.updateMany) {
throw new MongoDriverError('Raw operations are not allowed');
throw new MongoInvalidArgumentError('Raw operations are not allowed');
}
const updateStatement = makeUpdateStatement(op.updateMany.filter, op.updateMany.update, {
...op.updateMany,
multi: true
});
if (!hasAtomicOperators(updateStatement.u)) {
throw new MongoDriverError('Update document requires atomic operators');
throw new MongoInvalidArgumentError('Update document requires atomic operators');
}
return this.addToOperationsList(BatchType.UPDATE, updateStatement);
}
}

if ('deleteOne' in op) {
if ('q' in op.deleteOne) {
throw new MongoDriverError('Raw operations are not allowed');
throw new MongoInvalidArgumentError('Raw operations are not allowed');
}
return this.addToOperationsList(
BatchType.DELETE,
Expand All @@ -1137,7 +1138,7 @@ export abstract class BulkOperationBase {

if ('deleteMany' in op) {
if ('q' in op.deleteMany) {
throw new MongoDriverError('Raw operations are not allowed');
throw new MongoInvalidArgumentError('Raw operations are not allowed');
}
return this.addToOperationsList(
BatchType.DELETE,
Expand Down
6 changes: 3 additions & 3 deletions src/bulk/ordered.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Document } from '../bson';
import type { Collection } from '../collection';
import type { UpdateStatement } from '../operations/update';
import type { DeleteStatement } from '../operations/delete';
import { MongoDriverError } from '../error';
import { MongoInvalidArgumentError } from '../error';

/** @public */
export class OrderedBulkOperation extends BulkOperationBase {
Expand All @@ -26,7 +26,7 @@ export class OrderedBulkOperation extends BulkOperationBase {

// Throw error if the doc is bigger than the max BSON size
if (bsonSize >= this.s.maxBsonObjectSize)
throw new MongoDriverError(
throw new MongoInvalidArgumentError(
`Document is larger than the maximum size ${this.s.maxBsonObjectSize}`
);

Expand Down Expand Up @@ -68,7 +68,7 @@ export class OrderedBulkOperation extends BulkOperationBase {

// We have an array of documents
if (Array.isArray(document)) {
throw new MongoDriverError('Operation passed in cannot be an Array');
throw new MongoInvalidArgumentError('Operation passed in cannot be an Array');
}

this.s.currentBatch.originalIndexes.push(this.s.currentIndex);
Expand Down
12 changes: 9 additions & 3 deletions src/change_stream.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import Denque = require('denque');
import { MongoError, AnyError, isResumableError, MongoDriverError } from './error';
import {
MongoError,
AnyError,
isResumableError,
MongoDriverError,
MongoInvalidArgumentError
} from './error';
import { AggregateOperation, AggregateOptions } from './operations/aggregate';
import {
maxWireVersion,
Expand Down Expand Up @@ -255,7 +261,7 @@ export class ChangeStream<TSchema extends Document = Document> extends TypedEven
} else if (parent instanceof MongoClient) {
this.type = CHANGE_DOMAIN_TYPES.CLUSTER;
} else {
throw new MongoDriverError(
throw new MongoInvalidArgumentError(
'parent provided to ChangeStream constructor is not an instance of Collection, Db, or MongoClient'
);
}
Expand Down Expand Up @@ -357,7 +363,7 @@ export class ChangeStream<TSchema extends Document = Document> extends TypedEven
*/
stream(options?: CursorStreamOptions): Readable {
this.streamOptions = options;
if (!this.cursor) throw new MongoDriverError(NO_CURSOR_ERROR);
if (!this.cursor) throw new MongoInvalidArgumentError(NO_CURSOR_ERROR);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this should be under MongoInvalidArgumentError since the user isn't providing the cursor in this function, nor in the constructor. I feel like it might fall under MongoChangeStreamError which is covered in NODE-3404.

return this.cursor.stream(options);
}

Expand Down
14 changes: 11 additions & 3 deletions src/cmap/auth/gssapi.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { AuthProvider, AuthContext } from './auth_provider';
import { MongoDriverError, MongoError } from '../../error';
import {
MongoDriverError,
MongoMissingCredentialsError,
MongoError,
MongoMissingDependencyError
} from '../../error';
import { Kerberos, KerberosClient } from '../../deps';
import { Callback, ns } from '../../utils';
import type { Document } from '../../bson';
Expand All @@ -15,7 +20,10 @@ import * as dns from 'dns';
export class GSSAPI extends AuthProvider {
auth(authContext: AuthContext, callback: Callback): void {
const { connection, credentials } = authContext;
if (credentials == null) return callback(new MongoDriverError('credentials required'));
if (credentials == null)
return callback(
new MongoMissingCredentialsError('credentials required for gssapi authentication')
);
const { username } = credentials;
function externalCommand(
command: Document,
Expand All @@ -25,7 +33,7 @@ export class GSSAPI extends AuthProvider {
}
makeKerberosClient(authContext, (err, client) => {
if (err) return callback(err);
if (client == null) return callback(new MongoDriverError('gssapi client missing'));
if (client == null) return callback(new MongoMissingDependencyError('gssapi client missing'));
client.step('', (err, payload) => {
if (err) return callback(err);

Expand Down
4 changes: 2 additions & 2 deletions src/cmap/auth/mongo_credentials.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Resolves the default auth mechanism according to

import type { Document } from '../../bson';
import { MongoDriverError } from '../../error';
import { MongoDriverError, MongoMissingCredentialsError } from '../../error';
import { AuthMechanism } from './defaultAuthProviders';

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

if (
Expand Down
4 changes: 2 additions & 2 deletions src/cmap/auth/mongocr.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as crypto from 'crypto';
import { AuthProvider, AuthContext } from './auth_provider';
import { Callback, ns } from '../../utils';
import { MongoDriverError } from '../../error';
import { MongoMissingCredentialsError } from '../../error';

export class MongoCR extends AuthProvider {
auth(authContext: AuthContext, callback: Callback): void {
const { connection, credentials } = authContext;
if (!credentials) {
return callback(new MongoDriverError('AuthContext must provide credentials.'));
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
}
const username = credentials.username;
const password = credentials.password;
Expand Down
16 changes: 12 additions & 4 deletions src/cmap/auth/mongodb_aws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import * as url from 'url';
import * as BSON from '../../bson';
import { AuthProvider, AuthContext } from './auth_provider';
import { MongoCredentials } from './mongo_credentials';
import { MongoDriverError } from '../../error';
import {
MongoDriverError,
MongoMissingCredentialsError,
MongoCompatibilityError
} from '../../error';
import { maxWireVersion, Callback, ns } from '../../utils';
import type { BSONSerializeOptions } from '../../bson';

Expand Down Expand Up @@ -32,7 +36,7 @@ export class MongoDBAWS extends AuthProvider {
auth(authContext: AuthContext, callback: Callback): void {
const { connection, credentials } = authContext;
if (!credentials) {
return callback(new MongoDriverError('AuthContext must provide credentials.'));
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
}

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

if (maxWireVersion(connection) < 9) {
callback(
new MongoDriverError('MONGODB-AWS authentication requires MongoDB version 4.4 or later')
new MongoCompatibilityError(
'MONGODB-AWS authentication requires MongoDB version 4.4 or later'
)
);
return;
}
Expand Down Expand Up @@ -149,7 +155,9 @@ interface AWSCredentials {
function makeTempCredentials(credentials: MongoCredentials, callback: Callback<MongoCredentials>) {
function done(creds: AWSCredentials) {
if (!creds.AccessKeyId || !creds.SecretAccessKey || !creds.Token) {
callback(new MongoDriverError('Could not obtain temporary MONGODB-AWS credentials'));
callback(
new MongoMissingCredentialsError('Could not obtain temporary MONGODB-AWS credentials')
);
return;
}

Expand Down
4 changes: 2 additions & 2 deletions src/cmap/auth/plain.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Binary } from '../../bson';
import { AuthProvider, AuthContext } from './auth_provider';
import { MongoDriverError } from '../../error';
import { MongoMissingCredentialsError } from '../../error';
import { Callback, ns } from '../../utils';

export class Plain extends AuthProvider {
auth(authContext: AuthContext, callback: Callback): void {
const { connection, credentials } = authContext;
if (!credentials) {
return callback(new MongoDriverError('AuthContext must provide credentials.'));
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
}
const username = credentials.username;
const password = credentials.password;
Expand Down
24 changes: 16 additions & 8 deletions src/cmap/auth/scram.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import * as crypto from 'crypto';
import { Binary, Document } from '../../bson';
import { AnyError, MongoDriverError, MongoServerError } from '../../error';
import {
AnyError,
MongoDriverError,
MongoServerError,
MongoInvalidArgumentError,
MongoMissingCredentialsError
} from '../../error';
import { AuthProvider, AuthContext } from './auth_provider';
import { Callback, ns, emitWarning } from '../../utils';
import type { MongoCredentials } from './mongo_credentials';
Expand Down Expand Up @@ -103,10 +109,12 @@ function makeFirstMessage(
function executeScram(cryptoMethod: CryptoMethod, authContext: AuthContext, callback: Callback) {
const { connection, credentials } = authContext;
if (!credentials) {
return callback(new MongoDriverError('AuthContext must provide credentials.'));
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
}
if (!authContext.nonce) {
return callback(new MongoDriverError('AuthContext must contain a valid nonce property'));
return callback(
new MongoInvalidArgumentError('AuthContext must contain a valid nonce property')
);
}
const nonce = authContext.nonce;
const db = credentials.source;
Expand All @@ -131,10 +139,10 @@ function continueScramConversation(
const connection = authContext.connection;
const credentials = authContext.credentials;
if (!credentials) {
return callback(new MongoDriverError('AuthContext must provide credentials.'));
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
}
if (!authContext.nonce) {
return callback(new MongoDriverError('Unable to continue SCRAM without valid nonce'));
return callback(new MongoInvalidArgumentError('Unable to continue SCRAM without valid nonce'));
}
const nonce = authContext.nonce;

Expand Down Expand Up @@ -240,15 +248,15 @@ function parsePayload(payload: string) {

function passwordDigest(username: string, password: string) {
if (typeof username !== 'string') {
throw new MongoDriverError('username must be a string');
throw new MongoInvalidArgumentError('username must be a string');
}

if (typeof password !== 'string') {
throw new MongoDriverError('password must be a string');
throw new MongoInvalidArgumentError('password must be a string');
}

if (password.length === 0) {
throw new MongoDriverError('password cannot be empty');
throw new MongoInvalidArgumentError('password cannot be empty');
}

const md5 = crypto.createHash('md5');
Expand Down
6 changes: 3 additions & 3 deletions src/cmap/auth/x509.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AuthProvider, AuthContext } from './auth_provider';
import { MongoDriverError } from '../../error';
import { MongoMissingCredentialsError } from '../../error';
import type { Document } from '../../bson';
import { Callback, ns } from '../../utils';
import type { MongoCredentials } from './mongo_credentials';
Expand All @@ -9,7 +9,7 @@ export class X509 extends AuthProvider {
prepare(handshakeDoc: HandshakeDocument, authContext: AuthContext, callback: Callback): void {
const { credentials } = authContext;
if (!credentials) {
return callback(new MongoDriverError('AuthContext must provide credentials.'));
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
}
Object.assign(handshakeDoc, {
speculativeAuthenticate: x509AuthenticateCommand(credentials)
Expand All @@ -22,7 +22,7 @@ export class X509 extends AuthProvider {
const connection = authContext.connection;
const credentials = authContext.credentials;
if (!credentials) {
return callback(new MongoDriverError('AuthContext must provide credentials.'));
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
}
const response = authContext.response;

Expand Down
Loading