Skip to content

refactor(NODE-3402): implement MongoAPIError and its children #2891

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

Merged
merged 56 commits into from
Jul 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
ef40065
refactor: Replace relevant instances of MongoDriverError with MongoIn…
W-A-James Jul 2, 2021
787d276
refactor: Replace MongoDriverError with MongoCompatibilityError where…
W-A-James Jul 6, 2021
c9d22b6
refactor: Replace MongoDriverError with MongoMissingDependencyError w…
W-A-James Jul 6, 2021
42fbfaa
refactor: Replace MongoDriverError with MongoMissingCredentialsError …
W-A-James Jul 6, 2021
d5fca03
style: Fix formatting
W-A-James Jul 7, 2021
7234de8
refactor: Replace missed MongoDriverError instances
W-A-James Jul 7, 2021
cd7aceb
refactor: Replace some MongoDriverError instances
W-A-James Jul 7, 2021
a388c9e
refactor: Add doc comments to new errors and prevent direct instantia…
W-A-James Jul 7, 2021
dea1309
refactor: Add comments to mark needed changes
W-A-James Jul 7, 2021
7ce1575
refactor: Replace appropriate errors in src/db.ts with MongoInvalidAr…
W-A-James Jul 7, 2021
3de1994
refactor: Replace missed errors with children of MongoAPIError
W-A-James Jul 7, 2021
a48fbb6
refactor: Replace missed MongoDriverError instances (wip)
W-A-James Jul 8, 2021
c360d8a
chore: Add note to mark code for removal
W-A-James Jul 8, 2021
dba97c3
Replace missed MongoDriverError instances
W-A-James Jul 8, 2021
70285c7
refactor: Replace missed MongoDriverError instances
W-A-James Jul 8, 2021
8c7a8ae
chore: Import MongoCompatibilityError to ensure lint passes
W-A-James Jul 8, 2021
5673a23
refactor: Change error messages for MongoInvalidArgumentError instanc…
W-A-James Jul 12, 2021
617025d
style: Make TODO comments more descriptive
W-A-James Jul 12, 2021
e6153e9
chore: update comment
W-A-James Jul 12, 2021
5f8415e
refactor: Ensure comment formatting is standardized
W-A-James Jul 12, 2021
3bc7354
chore: Add ticket numbers to TODO comments
W-A-James Jul 13, 2021
8996a24
refactor: Capitalize start of error message
W-A-James Jul 13, 2021
3ff9e9e
style: Ensure that option name in error message is enclosed in double…
W-A-James Jul 13, 2021
39a6ece
test: (wip) Start working through and resolving test failures resulti…
W-A-James Jul 13, 2021
7e45ed8
test: Fix test failures
W-A-James Jul 14, 2021
06199a2
test: Fix test failures
W-A-James Jul 14, 2021
2fc2e7f
test: Fix test failures
W-A-James Jul 14, 2021
711f82f
style: Fix typo
W-A-James Jul 14, 2021
f5742d3
test: fix import
W-A-James Jul 14, 2021
6adf5a9
refactor: Address error messages and small formatting tweaks
W-A-James Jul 14, 2021
c9cb50e
test: Fix test failures
W-A-James Jul 14, 2021
f307730
refactor: change error message to be consistent with current API
W-A-James Jul 15, 2021
3ce25d9
fix: Address PR comments
W-A-James Jul 15, 2021
7800390
refactor: Rollback some errors to MongoDriverError and add TODO comment
W-A-James Jul 15, 2021
45c6d9f
chore: Add comment to keep track of errors to be replaced
W-A-James Jul 16, 2021
7249625
chore: Add comment to keep track of errors to be replaced
W-A-James Jul 16, 2021
a208511
chore: Change comment for future reference
W-A-James Jul 16, 2021
f136909
refactor: Replace string concatenation with template strings
W-A-James Jul 16, 2021
5644570
chore: Remove broken link in comment
W-A-James Jul 20, 2021
8394b1f
refactor: Replace relevant instances of MongoDriverError with MongoIn…
W-A-James Jul 20, 2021
7cece10
chore: Replace TODO PR links
W-A-James Jul 22, 2021
ae19478
refactor: Change error message
W-A-James Jul 22, 2021
6425956
refactor: revert to MongoDriverError
W-A-James Jul 22, 2021
82e753c
chore: Update TODOs/FIXMEs
W-A-James Jul 22, 2021
34109ac
refactor: Change MongoCompatibilityError to MongoInvalidArgumentError
W-A-James Jul 22, 2021
132ccfa
chore: fix TODO comments
W-A-James Jul 22, 2021
5ffc576
refactor: reformat error messages
W-A-James Jul 22, 2021
84c7e6a
docs: update doc comment for MongoAPIError
W-A-James Jul 22, 2021
59dcb70
chore: replace instances of MongoInvalidArgumentError in internal fun…
W-A-James Jul 23, 2021
5e29692
chore: Roll back to use MongoDriverError
W-A-James Jul 23, 2021
ccac2cd
chore: Roll back to use MongoDriverError
W-A-James Jul 23, 2021
b1642b4
chore: Roll back to use MongoDriverError
W-A-James Jul 23, 2021
c77d1b4
chore: change TODO comment
W-A-James Jul 23, 2021
f8e1345
chore: Roll back to MongoDriverError since this is not an APIError
W-A-James Jul 23, 2021
2a1515f
chore: rollback message format to prevent merge conflict with NODE-3404
W-A-James Jul 23, 2021
bc8dff1
chore: remove unused import
W-A-James Jul 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 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 All @@ -1146,7 +1147,7 @@ export abstract class BulkOperationBase {
}

// otherwise an unknown operation was provided
throw new MongoDriverError(
throw new MongoInvalidArgumentError(
'bulkWrite only supports insertOne, updateOne, updateMany, deleteOne, deleteMany'
);
}
Expand Down Expand Up @@ -1198,7 +1199,9 @@ export abstract class BulkOperationBase {
}
// If we have no operations in the bulk raise an error
if (this.s.batches.length === 0) {
const emptyBatchError = new MongoDriverError('Invalid BulkOperation, Batch cannot be empty');
const emptyBatchError = new MongoInvalidArgumentError(
'Invalid BulkOperation, Batch cannot be empty'
);
return handleEarlyError(emptyBatchError, callback);
}

Expand Down
7 changes: 4 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,8 @@ 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(
// TODO(NODE-3483): Change this to MongoBSONError
throw new MongoInvalidArgumentError(
`Document is larger than the maximum size ${this.s.maxBsonObjectSize}`
);

Expand Down Expand Up @@ -68,7 +69,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
7 changes: 4 additions & 3 deletions src/bulk/unordered.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,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 UnorderedBulkOperation extends BulkOperationBase {
Expand Down Expand Up @@ -36,7 +36,8 @@ export class UnorderedBulkOperation extends BulkOperationBase {

// Throw error if the doc is bigger than the max BSON size
if (bsonSize >= this.s.maxBsonObjectSize) {
throw new MongoDriverError(
// TODO(NODE-3483): Change this to MongoBSONError
throw new MongoInvalidArgumentError(
`Document is larger than the maximum size ${this.s.maxBsonObjectSize}`
);
}
Expand Down Expand Up @@ -79,7 +80,7 @@ export class UnorderedBulkOperation 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.operations.push(document);
Expand Down
4 changes: 3 additions & 1 deletion src/change_stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,9 @@ export class ChangeStream<TSchema extends Document = Document> extends TypedEven
} else if (parent instanceof MongoClient) {
this.type = CHANGE_DOMAIN_TYPES.CLUSTER;
} else {
// TODO(NODE-3404): Replace this with MongoChangeStreamError
throw new MongoDriverError(
'parent provided to ChangeStream constructor is not an instance of Collection, Db, or MongoClient'
'Parent provided to ChangeStream constructor must an instance of Collection, Db, or MongoClient'
);
}

Expand Down Expand Up @@ -364,6 +365,7 @@ export class ChangeStream<TSchema extends Document = Document> extends TypedEven
*/
stream(options?: CursorStreamOptions): Readable {
this.streamOptions = options;
// TODO(NODE-3404): Replace this with MongoChangeStreamError
if (!this.cursor) throw new MongoDriverError(NO_CURSOR_ERROR);
return this.cursor.stream(options);
}
Expand Down
1 change: 1 addition & 0 deletions src/cmap/auth/auth_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export class AuthProvider {
* @param callback - The callback to return the result from the authentication
*/
auth(context: AuthContext, callback: Callback): void {
// TODO(NODE-3485): Replace this with MongoMethodOverrideError
callback(new MongoDriverError('`auth` method must be overridden by subclass'));
}
}
17 changes: 13 additions & 4 deletions src/cmap/auth/gssapi.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { AuthProvider, AuthContext } from './auth_provider';
import { MongoDriverError, MongoError } from '../../error';
import {
MongoDriverError,
MongoInvalidArgumentError,
MongoMissingCredentialsError,
MongoError,
MongoMissingDependencyError
} from '../../error';
import { Kerberos, KerberosClient } from '../../deps';
import { Callback, ns } from '../../utils';
import type { Document } from '../../bson';
Expand All @@ -15,7 +21,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 +34,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 Expand Up @@ -66,7 +75,7 @@ function makeKerberosClient(authContext: AuthContext, callback: Callback<Kerbero
const { credentials } = authContext;
if (!hostAddress || typeof hostAddress.host !== 'string' || !credentials) {
return callback(
new MongoDriverError('Connection must have host and port and credentials defined.')
new MongoInvalidArgumentError('Connection must have host and port and credentials defined.')
);
}

Expand Down
7 changes: 5 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 All @@ -131,13 +131,15 @@ export class MongoCredentials {
this.mechanism === AuthMechanism.MONGODB_X509
) {
if (this.source != null && this.source !== '$external') {
// TODO(NODE-3483): Replace this with a MongoAuthValidationError
throw new MongoDriverError(
`Invalid source '${this.source}' for mechanism '${this.mechanism}' specified.`
);
}
}

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

Expand All @@ -146,6 +148,7 @@ export class MongoCredentials {
Reflect.set(this, 'password', undefined);
return;
}
// TODO(NODE-3483): Replace this with a MongoAuthValidationError
throw new MongoDriverError(`Password not allowed for mechanism MONGODB-X509`);
}
}
Expand Down
6 changes: 3 additions & 3 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 All @@ -24,7 +24,7 @@ export class MongoCR extends AuthProvider {
let md5 = crypto.createHash('md5');

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

// Final key
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
Loading