diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 0b7ddc9513..4cb7328245 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -52,7 +52,7 @@ else source "$DRIVERS_TOOLS"/.evergreen/csfle/set-temp-creds.sh fi -npm install mongodb-client-encryption@">=2.3.0" +npm install mongodb-client-encryption@">=2.4.0-alpha.0" npm install @mongodb-js/zstd npm install snappy diff --git a/etc/notes/CHANGES_5.0.0.md b/etc/notes/CHANGES_5.0.0.md index 7c48ea8e48..b19d447283 100644 --- a/etc/notes/CHANGES_5.0.0.md +++ b/etc/notes/CHANGES_5.0.0.md @@ -16,9 +16,56 @@ The following is a detailed collection of the changes in the major v5 release of ## Changes +### Optional callback support migrated to `mongodb-legacy` + +If you are a callback user and you are not ready to use promises, support for your workflow has **not** been removed. +We have migrated it to a new package: + +- [`mongodb-legacy` Github](https://github.com/mongodb-js/nodejs-mongodb-legacy#readme) +- [`mongodb-legacy` npm](https://www.npmjs.com/package/mongodb-legacy) + +The package wraps all of the driver's asynchronous operations that previously supported both promises and callbacks. All the wrapped APIs offer callback support via an optional callback argument alongside a Promise return value so projects with mixed usage will continue to work. + +#### Example usage of equivalent callback and promise usage + +After installing the package and modifying imports the following example demonstrates equivalent usages of either `async`/`await` syntax, `.then`/`.catch` chaining, or callbacks: + +```ts +// Just add '-legacy' to my mongodb import +import { MongoClient } from 'mongodb-legacy'; +const client = new MongoClient(); +const db = client.db(); +const collection = db.collection('pets'); + +// Legacy projects may have intermixed API usage: +app.get('/endpoint_async_await', async (req, res) => { + try { + const result = await collection.findOne({}) + res.end(JSON.stringify(result)); + } catch (error) { + res.errorHandling(error) + } +}); + +app.get('/endpoint_promises', (req, res) => { + collection + .findOne({}) + .then(result => res.end(JSON.stringify(result))) + .catch(error => res.errorHandling(error)); +}); + +app.get('/endpoint_callbacks', (req, res) => { + collection.findOne({}, (error, result) => { + if (error) return res.errorHandling(error); + res.end(JSON.stringify(result)); + }); +}); +``` + + ### Dot Notation Typescript Support Removed By Default -**NOTE** This is a **Typescript compile-time only** change. Dot notation in filters sent to MongoDB will still work the same. +**NOTE:** This is a **Typescript compile-time only** change. Dot notation in filters sent to MongoDB will still work the same. Version 4.3.0 introduced Typescript support for dot notation in filter predicates. For example: diff --git a/src/admin.ts b/src/admin.ts index 977de4e885..9e9a64e082 100644 --- a/src/admin.ts +++ b/src/admin.ts @@ -14,7 +14,6 @@ import { ValidateCollectionOperation, ValidateCollectionOptions } from './operations/validate_collection'; -import type { Callback } from './utils'; /** @internal */ export interface AdminPrivate { @@ -57,26 +56,11 @@ export class Admin { * * @param command - The command to execute * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - command(command: Document): Promise; - command(command: Document, options: RunCommandOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - command(command: Document, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - command(command: Document, options: RunCommandOptions, callback: Callback): void; - command( - command: Document, - options?: RunCommandOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = Object.assign({ dbName: 'admin' }, options); - + async command(command: Document, options?: RunCommandOptions): Promise { return executeOperation( this.s.db.s.client, - new RunCommandOperation(this.s.db, command, options), - callback + new RunCommandOperation(this.s.db, command, { dbName: 'admin', ...options }) ); } @@ -84,135 +68,60 @@ export class Admin { * Retrieve the server build information * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - buildInfo(): Promise; - buildInfo(options: CommandOperationOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - buildInfo(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - buildInfo(options: CommandOperationOptions, callback: Callback): void; - buildInfo( - options?: CommandOperationOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - return this.command({ buildinfo: 1 }, options, callback as Callback); + async buildInfo(options?: CommandOperationOptions): Promise { + return this.command({ buildinfo: 1 }, options); } /** * Retrieve the server build information * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - serverInfo(): Promise; - serverInfo(options: CommandOperationOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - serverInfo(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - serverInfo(options: CommandOperationOptions, callback: Callback): void; - serverInfo( - options?: CommandOperationOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - return this.command({ buildinfo: 1 }, options, callback as Callback); + async serverInfo(options?: CommandOperationOptions): Promise { + return this.command({ buildinfo: 1 }, options); } /** * Retrieve this db's server status. * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - serverStatus(): Promise; - serverStatus(options: CommandOperationOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - serverStatus(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - serverStatus(options: CommandOperationOptions, callback: Callback): void; - serverStatus( - options?: CommandOperationOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - return this.command({ serverStatus: 1 }, options, callback as Callback); + async serverStatus(options?: CommandOperationOptions): Promise { + return this.command({ serverStatus: 1 }, options); } /** * Ping the MongoDB server and retrieve results * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - ping(): Promise; - ping(options: CommandOperationOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - ping(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - ping(options: CommandOperationOptions, callback: Callback): void; - ping( - options?: CommandOperationOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - return this.command({ ping: 1 }, options, callback as Callback); + async ping(options?: CommandOperationOptions): Promise { + return this.command({ ping: 1 }, options); } /** * Add a user to the database * * @param username - The username for the new user - * @param password - An optional password for the new user + * @param passwordOrOptions - An optional password for the new user, or the options for the command * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - addUser(username: string): Promise; - addUser(username: string, password: string): Promise; - addUser(username: string, options: AddUserOptions): Promise; - addUser(username: string, password: string, options: AddUserOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - addUser(username: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - addUser(username: string, password: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - addUser(username: string, options: AddUserOptions, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - addUser( - username: string, - password: string, - options: AddUserOptions, - callback: Callback - ): void; - addUser( + async addUser( username: string, - password?: string | AddUserOptions | Callback, - options?: AddUserOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof password === 'function') { - (callback = password), (password = undefined), (options = {}); - } else if (typeof password !== 'string') { - if (typeof options === 'function') { - (callback = options), (options = password), (password = undefined); - } else { - (options = password), (callback = undefined), (password = undefined); - } - } else { - if (typeof options === 'function') (callback = options), (options = {}); - } - - options = Object.assign({ dbName: 'admin' }, options); - + passwordOrOptions?: string | AddUserOptions, + options?: AddUserOptions + ): Promise { + options = + options != null && typeof options === 'object' + ? options + : passwordOrOptions != null && typeof passwordOrOptions === 'object' + ? passwordOrOptions + : undefined; + const password = typeof passwordOrOptions === 'string' ? passwordOrOptions : undefined; return executeOperation( this.s.db.s.client, - new AddUserOperation(this.s.db, username, password, options), - callback + new AddUserOperation(this.s.db, username, password, { dbName: 'admin', ...options }) ); } @@ -221,26 +130,11 @@ export class Admin { * * @param username - The username to remove * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - removeUser(username: string): Promise; - removeUser(username: string, options: RemoveUserOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - removeUser(username: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - removeUser(username: string, options: RemoveUserOptions, callback: Callback): void; - removeUser( - username: string, - options?: RemoveUserOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = Object.assign({ dbName: 'admin' }, options); - + async removeUser(username: string, options?: RemoveUserOptions): Promise { return executeOperation( this.s.db.s.client, - new RemoveUserOperation(this.s.db, username, options), - callback + new RemoveUserOperation(this.s.db, username, { dbName: 'admin', ...options }) ); } @@ -249,30 +143,14 @@ export class Admin { * * @param collectionName - The name of the collection to validate. * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - validateCollection(collectionName: string): Promise; - validateCollection(collectionName: string, options: ValidateCollectionOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - validateCollection(collectionName: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - validateCollection( + async validateCollection( collectionName: string, - options: ValidateCollectionOptions, - callback: Callback - ): void; - validateCollection( - collectionName: string, - options?: ValidateCollectionOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - + options: ValidateCollectionOptions = {} + ): Promise { return executeOperation( this.s.db.s.client, - new ValidateCollectionOperation(this, collectionName, options), - callback + new ValidateCollectionOperation(this, collectionName, options) ); } @@ -280,46 +158,17 @@ export class Admin { * List the available databases * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - listDatabases(): Promise; - listDatabases(options: ListDatabasesOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - listDatabases(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - listDatabases(options: ListDatabasesOptions, callback: Callback): void; - listDatabases( - options?: ListDatabasesOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - - return executeOperation( - this.s.db.s.client, - new ListDatabasesOperation(this.s.db, options), - callback - ); + async listDatabases(options?: ListDatabasesOptions): Promise { + return executeOperation(this.s.db.s.client, new ListDatabasesOperation(this.s.db, options)); } /** * Get ReplicaSet status * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - replSetGetStatus(): Promise; - replSetGetStatus(options: CommandOperationOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - replSetGetStatus(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - replSetGetStatus(options: CommandOperationOptions, callback: Callback): void; - replSetGetStatus( - options?: CommandOperationOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - return this.command({ replSetGetStatus: 1 }, options, callback as Callback); + async replSetGetStatus(options?: CommandOperationOptions): Promise { + return this.command({ replSetGetStatus: 1 }, options); } } diff --git a/src/bulk/common.ts b/src/bulk/common.ts index 1d1ade6e50..566c2464b9 100644 --- a/src/bulk/common.ts +++ b/src/bulk/common.ts @@ -23,7 +23,6 @@ import { Callback, getTopology, hasAtomicOperators, - maybeCallback, MongoDBNamespace, resolveOptions } from '../utils'; @@ -1175,56 +1174,34 @@ export abstract class BulkOperationBase { return batches; } - execute(options?: BulkWriteOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - execute(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - execute(options: BulkWriteOptions | undefined, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - execute( - options?: BulkWriteOptions | Callback, - callback?: Callback - ): Promise | void; - execute( - options?: BulkWriteOptions | Callback, - callback?: Callback - ): Promise | void { - callback = - typeof callback === 'function' - ? callback - : typeof options === 'function' - ? options - : undefined; - return maybeCallback(async () => { - options = options != null && typeof options !== 'function' ? options : {}; - - if (this.s.executed) { - throw new MongoBatchReExecutionError(); - } + async execute(options: BulkWriteOptions = {}): Promise { + if (this.s.executed) { + throw new MongoBatchReExecutionError(); + } - const writeConcern = WriteConcern.fromOptions(options); - if (writeConcern) { - this.s.writeConcern = writeConcern; - } + const writeConcern = WriteConcern.fromOptions(options); + if (writeConcern) { + this.s.writeConcern = writeConcern; + } - // If we have current batch - if (this.isOrdered) { - if (this.s.currentBatch) this.s.batches.push(this.s.currentBatch); - } else { - if (this.s.currentInsertBatch) this.s.batches.push(this.s.currentInsertBatch); - if (this.s.currentUpdateBatch) this.s.batches.push(this.s.currentUpdateBatch); - if (this.s.currentRemoveBatch) this.s.batches.push(this.s.currentRemoveBatch); - } - // If we have no operations in the bulk raise an error - if (this.s.batches.length === 0) { - throw new MongoInvalidArgumentError('Invalid BulkOperation, Batch cannot be empty'); - } + // If we have current batch + if (this.isOrdered) { + if (this.s.currentBatch) this.s.batches.push(this.s.currentBatch); + } else { + if (this.s.currentInsertBatch) this.s.batches.push(this.s.currentInsertBatch); + if (this.s.currentUpdateBatch) this.s.batches.push(this.s.currentUpdateBatch); + if (this.s.currentRemoveBatch) this.s.batches.push(this.s.currentRemoveBatch); + } + // If we have no operations in the bulk raise an error + if (this.s.batches.length === 0) { + throw new MongoInvalidArgumentError('Invalid BulkOperation, Batch cannot be empty'); + } + + this.s.executed = true; + const finalOptions = { ...this.s.options, ...options }; + const operation = new BulkWriteShimOperation(this, finalOptions); - this.s.executed = true; - const finalOptions = { ...this.s.options, ...options }; - const operation = new BulkWriteShimOperation(this, finalOptions); - return executeOperation(this.s.collection.s.db.s.client, operation); - }, callback); + return executeOperation(this.s.collection.s.db.s.client, operation); } /** diff --git a/src/change_stream.ts b/src/change_stream.ts index e346609e09..ee6876acc1 100644 --- a/src/change_stream.ts +++ b/src/change_stream.ts @@ -19,7 +19,7 @@ import type { AggregateOptions } from './operations/aggregate'; import type { CollationOptions, OperationParent } from './operations/command'; import type { ReadPreference } from './read_preference'; import type { ServerSessionId } from './sessions'; -import { Callback, filterOptions, getTopology, maybeCallback, MongoDBNamespace } from './utils'; +import { filterOptions, getTopology, MongoDBNamespace } from './utils'; /** @internal */ const kCursorStream = Symbol('cursorStream'); @@ -637,99 +637,84 @@ export class ChangeStream< } /** Check if there is any document still available in the Change Stream */ - hasNext(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - hasNext(callback: Callback): void; - hasNext(callback?: Callback): Promise | void { + async hasNext(): Promise { this._setIsIterator(); - return maybeCallback(async () => { - // Change streams must resume indefinitely while each resume event succeeds. - // This loop continues until either a change event is received or until a resume attempt - // fails. - // eslint-disable-next-line no-constant-condition - while (true) { + // Change streams must resume indefinitely while each resume event succeeds. + // This loop continues until either a change event is received or until a resume attempt + // fails. + // eslint-disable-next-line no-constant-condition + while (true) { + try { + const hasNext = await this.cursor.hasNext(); + return hasNext; + } catch (error) { try { - const hasNext = await this.cursor.hasNext(); - return hasNext; + await this._processErrorIteratorMode(error); } catch (error) { try { - await this._processErrorIteratorMode(error); - } catch (error) { - try { - await this.close(); - } catch { - // We are not concerned with errors from close() - } - throw error; + await this.close(); + } catch { + // We are not concerned with errors from close() } + throw error; } } - }, callback); + } } /** Get the next available document from the Change Stream. */ - next(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - next(callback: Callback): void; - next(callback?: Callback): Promise | void { + async next(): Promise { this._setIsIterator(); - return maybeCallback(async () => { - // Change streams must resume indefinitely while each resume event succeeds. - // This loop continues until either a change event is received or until a resume attempt - // fails. - // eslint-disable-next-line no-constant-condition - while (true) { + // Change streams must resume indefinitely while each resume event succeeds. + // This loop continues until either a change event is received or until a resume attempt + // fails. + // eslint-disable-next-line no-constant-condition + while (true) { + try { + const change = await this.cursor.next(); + const processedChange = this._processChange(change ?? null); + return processedChange; + } catch (error) { try { - const change = await this.cursor.next(); - const processedChange = this._processChange(change ?? null); - return processedChange; + await this._processErrorIteratorMode(error); } catch (error) { try { - await this._processErrorIteratorMode(error); - } catch (error) { - try { - await this.close(); - } catch { - // We are not concerned with errors from close() - } - throw error; + await this.close(); + } catch { + // We are not concerned with errors from close() } + throw error; } } - }, callback); + } } /** * Try to get the next available document from the Change Stream's cursor or `null` if an empty batch is returned */ - tryNext(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - tryNext(callback: Callback): void; - tryNext(callback?: Callback): Promise | void { + async tryNext(): Promise { this._setIsIterator(); - return maybeCallback(async () => { - // Change streams must resume indefinitely while each resume event succeeds. - // This loop continues until either a change event is received or until a resume attempt - // fails. - // eslint-disable-next-line no-constant-condition - while (true) { + // Change streams must resume indefinitely while each resume event succeeds. + // This loop continues until either a change event is received or until a resume attempt + // fails. + // eslint-disable-next-line no-constant-condition + while (true) { + try { + const change = await this.cursor.tryNext(); + return change ?? null; + } catch (error) { try { - const change = await this.cursor.tryNext(); - return change ?? null; + await this._processErrorIteratorMode(error); } catch (error) { try { - await this._processErrorIteratorMode(error); - } catch (error) { - try { - await this.close(); - } catch { - // We are not concerned with errors from close() - } - throw error; + await this.close(); + } catch { + // We are not concerned with errors from close() } + throw error; } } - }, callback); + } } async *[Symbol.asyncIterator](): AsyncGenerator { @@ -758,20 +743,15 @@ export class ChangeStream< } /** Close the Change Stream */ - close(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - close(callback: Callback): void; - close(callback?: Callback): Promise | void { + async close(): Promise { this[kClosed] = true; - return maybeCallback(async () => { - const cursor = this.cursor; - try { - await cursor.close(); - } finally { - this._endStream(); - } - }, callback); + const cursor = this.cursor; + try { + await cursor.close(); + } finally { + this._endStream(); + } } /** @@ -864,9 +844,7 @@ export class ChangeStream< private _closeEmitterModeWithError(error: AnyError): void { this.emit(ChangeStream.ERROR, error); - this.close(() => { - // nothing to do - }); + this.close().catch(() => null); } /** @internal */ diff --git a/src/collection.ts b/src/collection.ts index 23031d8900..afd15e5a60 100644 --- a/src/collection.ts +++ b/src/collection.ts @@ -82,7 +82,6 @@ import { import { ReadConcern, ReadConcernLike } from './read_concern'; import { ReadPreference, ReadPreferenceLike } from './read_preference'; import { - Callback, checkCollectionName, DEFAULT_PK_FACTORY, MongoDBNamespace, @@ -250,42 +249,18 @@ export class Collection { * * @param doc - The document to insert * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - insertOne(doc: OptionalUnlessRequiredId): Promise>; - insertOne( + async insertOne( doc: OptionalUnlessRequiredId, - options: InsertOneOptions - ): Promise>; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - insertOne( - doc: OptionalUnlessRequiredId, - callback: Callback> - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - insertOne( - doc: OptionalUnlessRequiredId, - options: InsertOneOptions, - callback: Callback> - ): void; - insertOne( - doc: OptionalUnlessRequiredId, - options?: InsertOneOptions | Callback>, - callback?: Callback> - ): Promise> | void { - if (typeof options === 'function') { - callback = options; - options = {}; - } - + options?: InsertOneOptions + ): Promise> { return executeOperation( this.s.db.s.client, new InsertOneOperation( this as TODO_NODE_3286, doc, resolveOptions(this, options) - ) as TODO_NODE_3286, - callback + ) as TODO_NODE_3286 ); } @@ -296,40 +271,18 @@ export class Collection { * * @param docs - The documents to insert * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - insertMany(docs: OptionalUnlessRequiredId[]): Promise>; - insertMany( - docs: OptionalUnlessRequiredId[], - options: BulkWriteOptions - ): Promise>; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - insertMany( - docs: OptionalUnlessRequiredId[], - callback: Callback> - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - insertMany( - docs: OptionalUnlessRequiredId[], - options: BulkWriteOptions, - callback: Callback> - ): void; - insertMany( + async insertMany( docs: OptionalUnlessRequiredId[], - options?: BulkWriteOptions | Callback>, - callback?: Callback> - ): Promise> | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options ? Object.assign({}, options) : { ordered: true }; - + options?: BulkWriteOptions + ): Promise> { return executeOperation( this.s.db.s.client, new InsertManyOperation( this as TODO_NODE_3286, docs, - resolveOptions(this, options) - ) as TODO_NODE_3286, - callback + resolveOptions(this, options ?? { ordered: true }) + ) as TODO_NODE_3286 ); } @@ -344,41 +297,18 @@ export class Collection { * - `deleteOne` * - `deleteMany` * - * Please note that raw operations are no longer accepted as of driver version 4.0. - * * If documents passed in do not contain the **_id** field, * one will be added to each of the documents missing it by the driver, mutating the document. This behavior * can be overridden by setting the **forceServerObjectId** flag. * * @param operations - Bulk operations to perform * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided * @throws MongoDriverError if operations is not an array */ - bulkWrite(operations: AnyBulkWriteOperation[]): Promise; - bulkWrite( - operations: AnyBulkWriteOperation[], - options: BulkWriteOptions - ): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - bulkWrite( + async bulkWrite( operations: AnyBulkWriteOperation[], - callback: Callback - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - bulkWrite( - operations: AnyBulkWriteOperation[], - options: BulkWriteOptions, - callback: Callback - ): void; - bulkWrite( - operations: AnyBulkWriteOperation[], - options?: BulkWriteOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options || { ordered: true }; - + options?: BulkWriteOptions + ): Promise { if (!Array.isArray(operations)) { throw new MongoInvalidArgumentError('Argument "operations" must be an array of documents'); } @@ -388,9 +318,8 @@ export class Collection { new BulkWriteOperation( this as TODO_NODE_3286, operations as TODO_NODE_3286, - resolveOptions(this, options) - ), - callback + resolveOptions(this, options ?? { ordered: true }) + ) ); } @@ -400,38 +329,12 @@ export class Collection { * @param filter - The filter used to select the document to update * @param update - The update operations to be applied to the document * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - updateOne( - filter: Filter, - update: UpdateFilter | Partial - ): Promise; - updateOne( - filter: Filter, - update: UpdateFilter | Partial, - options: UpdateOptions - ): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - updateOne( - filter: Filter, - update: UpdateFilter | Partial, - callback: Callback - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - updateOne( - filter: Filter, - update: UpdateFilter | Partial, - options: UpdateOptions, - callback: Callback - ): void; - updateOne( + async updateOne( filter: Filter, update: UpdateFilter | Partial, - options?: UpdateOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + options?: UpdateOptions + ): Promise { return executeOperation( this.s.db.s.client, new UpdateOneOperation( @@ -439,8 +342,7 @@ export class Collection { filter, update, resolveOptions(this, options) - ) as TODO_NODE_3286, - callback + ) as TODO_NODE_3286 ); } @@ -450,38 +352,12 @@ export class Collection { * @param filter - The filter used to select the document to replace * @param replacement - The Document that replaces the matching document * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - replaceOne( - filter: Filter, - replacement: WithoutId - ): Promise; - replaceOne( - filter: Filter, - replacement: WithoutId, - options: ReplaceOptions - ): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - replaceOne( - filter: Filter, - replacement: WithoutId, - callback: Callback - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - replaceOne( - filter: Filter, - replacement: WithoutId, - options: ReplaceOptions, - callback: Callback - ): void; - replaceOne( + async replaceOne( filter: Filter, replacement: WithoutId, - options?: ReplaceOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + options?: ReplaceOptions + ): Promise { return executeOperation( this.s.db.s.client, new ReplaceOneOperation( @@ -489,8 +365,7 @@ export class Collection { filter, replacement, resolveOptions(this, options) - ), - callback + ) ); } @@ -500,38 +375,12 @@ export class Collection { * @param filter - The filter used to select the documents to update * @param update - The update operations to be applied to the documents * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - updateMany( - filter: Filter, - update: UpdateFilter - ): Promise; - updateMany( - filter: Filter, - update: UpdateFilter, - options: UpdateOptions - ): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - updateMany( - filter: Filter, - update: UpdateFilter, - callback: Callback - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - updateMany( - filter: Filter, - update: UpdateFilter, - options: UpdateOptions, - callback: Callback - ): void; - updateMany( + async updateMany( filter: Filter, update: UpdateFilter, - options?: UpdateOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + options?: UpdateOptions + ): Promise { return executeOperation( this.s.db.s.client, new UpdateManyOperation( @@ -539,8 +388,7 @@ export class Collection { filter, update, resolveOptions(this, options) - ), - callback + ) as TODO_NODE_3286 ); } @@ -549,29 +397,14 @@ export class Collection { * * @param filter - The filter used to select the document to remove * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - deleteOne(filter: Filter): Promise; - deleteOne(filter: Filter, options: DeleteOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - deleteOne(filter: Filter, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - deleteOne( - filter: Filter, - options: DeleteOptions, - callback?: Callback - ): void; - deleteOne( - filter: Filter, - options?: DeleteOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async deleteOne( + filter: Filter = {}, + options: DeleteOptions = {} + ): Promise { return executeOperation( this.s.db.s.client, - new DeleteOneOperation(this as TODO_NODE_3286, filter, resolveOptions(this, options)), - callback + new DeleteOneOperation(this as TODO_NODE_3286, filter, resolveOptions(this, options)) ); } @@ -580,40 +413,14 @@ export class Collection { * * @param filter - The filter used to select the documents to remove * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - deleteMany(filter: Filter): Promise; - deleteMany(filter: Filter, options: DeleteOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - deleteMany(filter: Filter, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - deleteMany( - filter: Filter, - options: DeleteOptions, - callback: Callback - ): void; - deleteMany( - filter: Filter, - options?: DeleteOptions | Callback, - callback?: Callback - ): Promise | void { - if (filter == null) { - filter = {}; - options = {}; - callback = undefined; - } else if (typeof filter === 'function') { - callback = filter as Callback; - filter = {}; - options = {}; - } else if (typeof options === 'function') { - callback = options; - options = {}; - } - + async deleteMany( + filter: Filter = {}, + options: DeleteOptions = {} + ): Promise { return executeOperation( this.s.db.s.client, - new DeleteManyOperation(this as TODO_NODE_3286, filter, resolveOptions(this, options)), - callback + new DeleteManyOperation(this as TODO_NODE_3286, filter, resolveOptions(this, options)) ); } @@ -625,29 +432,15 @@ export class Collection { * * @param newName - New name of of the collection. * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - rename(newName: string): Promise; - rename(newName: string, options: RenameOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - rename(newName: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - rename(newName: string, options: RenameOptions, callback: Callback): void; - rename( - newName: string, - options?: RenameOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async rename(newName: string, options?: RenameOptions): Promise { // Intentionally, we do not inherit options from parent for this operation. return executeOperation( this.s.db.s.client, new RenameOperation(this as TODO_NODE_3286, newName, { ...options, readPreference: ReadPreference.PRIMARY - }) as TODO_NODE_3286, - callback + }) as TODO_NODE_3286 ); } @@ -655,25 +448,11 @@ export class Collection { * Drop the collection from the database, removing it permanently. New accesses will create a new collection. * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - drop(): Promise; - drop(options: DropCollectionOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - drop(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - drop(options: DropCollectionOptions, callback: Callback): void; - drop( - options?: DropCollectionOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - + async drop(options?: DropCollectionOptions): Promise { return executeOperation( this.s.db.s.client, - new DropCollectionOperation(this.s.db, this.collectionName, options), - callback + new DropCollectionOperation(this.s.db, this.collectionName, options) ); } @@ -682,59 +461,21 @@ export class Collection { * * @param filter - Query for find Operation * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - findOne(): Promise | null>; - findOne(filter: Filter): Promise | null>; - findOne(filter: Filter, options: FindOptions): Promise | null>; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - findOne(callback: Callback | null>): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - findOne(filter: Filter, callback: Callback | null>): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - findOne( - filter: Filter, - options: FindOptions, - callback: Callback | null> - ): void; + async findOne(): Promise | null>; + async findOne(filter: Filter): Promise | null>; + async findOne(filter: Filter, options: FindOptions): Promise | null>; // allow an override of the schema. - findOne(): Promise; - findOne(filter: Filter): Promise; - findOne(filter: Filter, options?: FindOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - findOne(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - findOne( - filter: Filter, - options?: FindOptions, - callback?: Callback - ): void; - - findOne( - filter?: Filter | Callback | null>, - options?: FindOptions | Callback | null>, - callback?: Callback | null> - ): Promise | null> | void { - if (callback != null && typeof callback !== 'function') { - throw new MongoInvalidArgumentError( - 'Third parameter to `findOne()` must be a callback or undefined' - ); - } + async findOne(): Promise; + async findOne(filter: Filter): Promise; + async findOne(filter: Filter, options?: FindOptions): Promise; - if (typeof filter === 'function') { - callback = filter; - filter = {}; - options = {}; - } - if (typeof options === 'function') { - callback = options; - options = {}; - } - - const finalFilter = filter ?? {}; - const finalOptions = options ?? {}; - return this.find(finalFilter, finalOptions).limit(-1).batchSize(1).next(callback); + async findOne( + filter: Filter = {}, + options: FindOptions = {} + ): Promise | null> { + return this.find(filter, options).limit(-1).batchSize(1).next(); } /** @@ -745,16 +486,7 @@ export class Collection { find(): FindCursor>; find(filter: Filter, options?: FindOptions): FindCursor>; find(filter: Filter, options?: FindOptions): FindCursor; - find(filter?: Filter, options?: FindOptions): FindCursor> { - if (arguments.length > 2) { - throw new MongoInvalidArgumentError( - 'Method "collection.find()" accepts at most two arguments' - ); - } - if (typeof options === 'function') { - throw new MongoInvalidArgumentError('Argument "options" must not be function'); - } - + find(filter: Filter = {}, options: FindOptions = {}): FindCursor> { return new FindCursor>( this.s.db.s.client, this.s.namespace, @@ -767,24 +499,11 @@ export class Collection { * Returns the options of the collection. * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - options(): Promise; - options(options: OperationOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - options(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - options(options: OperationOptions, callback: Callback): void; - options( - options?: OperationOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async options(options?: OperationOptions): Promise { return executeOperation( this.s.db.s.client, - new OptionsOperation(this as TODO_NODE_3286, resolveOptions(this, options)), - callback + new OptionsOperation(this as TODO_NODE_3286, resolveOptions(this, options)) ); } @@ -792,24 +511,11 @@ export class Collection { * Returns if the collection is a capped collection * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - isCapped(): Promise; - isCapped(options: OperationOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - isCapped(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - isCapped(options: OperationOptions, callback: Callback): void; - isCapped( - options?: OperationOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async isCapped(options?: OperationOptions): Promise { return executeOperation( this.s.db.s.client, - new IsCappedOperation(this as TODO_NODE_3286, resolveOptions(this, options)), - callback + new IsCappedOperation(this as TODO_NODE_3286, resolveOptions(this, options)) ); } @@ -818,7 +524,6 @@ export class Collection { * * @param indexSpec - The field name or index specification to create an index for * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided * * @example * ```ts @@ -842,23 +547,10 @@ export class Collection { * await collection.createIndex(['j', ['k', -1], { l: '2d' }]) * ``` */ - createIndex(indexSpec: IndexSpecification): Promise; - createIndex(indexSpec: IndexSpecification, options: CreateIndexesOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - createIndex(indexSpec: IndexSpecification, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - createIndex( - indexSpec: IndexSpecification, - options: CreateIndexesOptions, - callback: Callback - ): void; - createIndex( + async createIndex( indexSpec: IndexSpecification, - options?: CreateIndexesOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + options?: CreateIndexesOptions + ): Promise { return executeOperation( this.s.db.s.client, new CreateIndexOperation( @@ -866,8 +558,7 @@ export class Collection { this.collectionName, indexSpec, resolveOptions(this, options) - ), - callback + ) ); } @@ -881,7 +572,6 @@ export class Collection { * * @param indexSpecs - An array of index specifications to be created * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided * * @example * ```ts @@ -903,34 +593,18 @@ export class Collection { * ]); * ``` */ - createIndexes(indexSpecs: IndexDescription[]): Promise; - createIndexes(indexSpecs: IndexDescription[], options: CreateIndexesOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - createIndexes(indexSpecs: IndexDescription[], callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - createIndexes( - indexSpecs: IndexDescription[], - options: CreateIndexesOptions, - callback: Callback - ): void; - createIndexes( + async createIndexes( indexSpecs: IndexDescription[], - options?: CreateIndexesOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options ? Object.assign({}, options) : {}; - if (typeof options.maxTimeMS !== 'number') delete options.maxTimeMS; - + options?: CreateIndexesOptions + ): Promise { return executeOperation( this.s.db.s.client, new CreateIndexesOperation( this as TODO_NODE_3286, this.collectionName, indexSpecs, - resolveOptions(this, options) - ), - callback + resolveOptions(this, { ...options, maxTimeMS: undefined }) + ) ); } @@ -939,29 +613,14 @@ export class Collection { * * @param indexName - Name of the index to drop. * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - dropIndex(indexName: string): Promise; - dropIndex(indexName: string, options: DropIndexesOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - dropIndex(indexName: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - dropIndex(indexName: string, options: DropIndexesOptions, callback: Callback): void; - dropIndex( - indexName: string, - options?: DropIndexesOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = resolveOptions(this, options); - - // Run only against primary - options.readPreference = ReadPreference.primary; - + async dropIndex(indexName: string, options?: DropIndexesOptions): Promise { return executeOperation( this.s.db.s.client, - new DropIndexOperation(this as TODO_NODE_3286, indexName, options), - callback + new DropIndexOperation(this as TODO_NODE_3286, indexName, { + ...resolveOptions(this, options), + readPreference: ReadPreference.primary + }) ); } @@ -969,24 +628,11 @@ export class Collection { * Drops all indexes from this collection. * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - dropIndexes(): Promise; - dropIndexes(options: DropIndexesOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - dropIndexes(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - dropIndexes(options: DropIndexesOptions, callback: Callback): void; - dropIndexes( - options?: DropIndexesOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async dropIndexes(options?: DropIndexesOptions): Promise { return executeOperation( this.s.db.s.client, - new DropIndexesOperation(this as TODO_NODE_3286, resolveOptions(this, options)), - callback + new DropIndexesOperation(this as TODO_NODE_3286, resolveOptions(this, options)) ); } @@ -1004,29 +650,14 @@ export class Collection { * * @param indexes - One or more index names to check. * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - indexExists(indexes: string | string[]): Promise; - indexExists(indexes: string | string[], options: IndexInformationOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - indexExists(indexes: string | string[], callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - indexExists( - indexes: string | string[], - options: IndexInformationOptions, - callback: Callback - ): void; - indexExists( + async indexExists( indexes: string | string[], - options?: IndexInformationOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + options?: IndexInformationOptions + ): Promise { return executeOperation( this.s.db.s.client, - new IndexExistsOperation(this as TODO_NODE_3286, indexes, resolveOptions(this, options)), - callback + new IndexExistsOperation(this as TODO_NODE_3286, indexes, resolveOptions(this, options)) ); } @@ -1034,24 +665,11 @@ export class Collection { * Retrieves this collections index info. * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - indexInformation(): Promise; - indexInformation(options: IndexInformationOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - indexInformation(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - indexInformation(options: IndexInformationOptions, callback: Callback): void; - indexInformation( - options?: IndexInformationOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async indexInformation(options?: IndexInformationOptions): Promise { return executeOperation( this.s.db.s.client, - new IndexInformationOperation(this.s.db, this.collectionName, resolveOptions(this, options)), - callback + new IndexInformationOperation(this.s.db, this.collectionName, resolveOptions(this, options)) ); } @@ -1067,23 +685,11 @@ export class Collection { * * @see {@link https://www.mongodb.com/docs/manual/reference/command/count/#behavior|Count: Behavior} * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - estimatedDocumentCount(): Promise; - estimatedDocumentCount(options: EstimatedDocumentCountOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - estimatedDocumentCount(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - estimatedDocumentCount(options: EstimatedDocumentCountOptions, callback: Callback): void; - estimatedDocumentCount( - options?: EstimatedDocumentCountOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); + async estimatedDocumentCount(options?: EstimatedDocumentCountOptions): Promise { return executeOperation( this.s.db.s.client, - new EstimatedDocumentCountOperation(this as TODO_NODE_3286, resolveOptions(this, options)), - callback + new EstimatedDocumentCountOperation(this as TODO_NODE_3286, resolveOptions(this, options)) ); } @@ -1106,50 +712,19 @@ export class Collection { * * @param filter - The filter for the count * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided * * @see https://docs.mongodb.com/manual/reference/operator/query/expr/ * @see https://docs.mongodb.com/manual/reference/operator/query/geoWithin/ * @see https://docs.mongodb.com/manual/reference/operator/query/center/#op._S_center * @see https://docs.mongodb.com/manual/reference/operator/query/centerSphere/#op._S_centerSphere */ - countDocuments(): Promise; - countDocuments(filter: Filter): Promise; - countDocuments(filter: Filter, options: CountDocumentsOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - countDocuments(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - countDocuments(filter: Filter, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - countDocuments( - filter: Filter, - options: CountDocumentsOptions, - callback: Callback - ): void; - countDocuments( - filter?: Document | CountDocumentsOptions | Callback, - options?: CountDocumentsOptions | Callback, - callback?: Callback - ): Promise | void { - if (filter == null) { - (filter = {}), (options = {}), (callback = undefined); - } else if (typeof filter === 'function') { - (callback = filter as Callback), (filter = {}), (options = {}); - } else { - if (arguments.length === 2) { - if (typeof options === 'function') (callback = options), (options = {}); - } - } - - filter ??= {}; + async countDocuments( + filter: Document = {}, + options: CountDocumentsOptions = {} + ): Promise { return executeOperation( this.s.db.s.client, - new CountDocumentsOperation( - this as TODO_NODE_3286, - filter, - resolveOptions(this, options as CountDocumentsOptions) - ), - callback + new CountDocumentsOperation(this as TODO_NODE_3286, filter, resolveOptions(this, options)) ); } @@ -1159,7 +734,6 @@ export class Collection { * @param key - Field of the document to find distinct values for * @param filter - The filter for filtering the set of documents to which we apply the distinct filter. * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ distinct>( key: Key @@ -1173,65 +747,25 @@ export class Collection { filter: Filter, options: DistinctOptions ): Promise[Key]>>>; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - distinct>( - key: Key, - callback: Callback[Key]>>> - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - distinct>( - key: Key, - filter: Filter, - callback: Callback[Key]>>> - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - distinct>( - key: Key, - filter: Filter, - options: DistinctOptions, - callback: Callback[Key]>>> - ): void; // Embedded documents overload distinct(key: string): Promise; distinct(key: string, filter: Filter): Promise; distinct(key: string, filter: Filter, options: DistinctOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - distinct(key: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - distinct(key: string, filter: Filter, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - distinct( - key: string, - filter: Filter, - options: DistinctOptions, - callback: Callback - ): void; - // Implementation - distinct>( - key: Key, - filter?: Filter | DistinctOptions | Callback, - options?: DistinctOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof filter === 'function') { - (callback = filter), (filter = {}), (options = {}); - } else { - if (arguments.length === 3 && typeof options === 'function') { - (callback = options), (options = {}); - } - } - filter ??= {}; + async distinct>( + key: Key, + filter: Filter = {}, + options: DistinctOptions = {} + ): Promise { return executeOperation( this.s.db.s.client, new DistinctOperation( this as TODO_NODE_3286, key as TODO_NODE_3286, filter, - resolveOptions(this, options as DistinctOptions) - ), - callback + resolveOptions(this, options) + ) ); } @@ -1239,24 +773,11 @@ export class Collection { * Retrieve all the indexes on the collection. * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - indexes(): Promise; - indexes(options: IndexInformationOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - indexes(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - indexes(options: IndexInformationOptions, callback: Callback): void; - indexes( - options?: IndexInformationOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async indexes(options?: IndexInformationOptions): Promise { return executeOperation( this.s.db.s.client, - new IndexesOperation(this as TODO_NODE_3286, resolveOptions(this, options)), - callback + new IndexesOperation(this as TODO_NODE_3286, resolveOptions(this, options)) ); } @@ -1264,25 +785,11 @@ export class Collection { * Get all the collection statistics. * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - stats(): Promise; - stats(options: CollStatsOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - stats(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - stats(options: CollStatsOptions, callback: Callback): void; - stats( - options?: CollStatsOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - + async stats(options?: CollStatsOptions): Promise { return executeOperation( this.s.db.s.client, - new CollStatsOperation(this as TODO_NODE_3286, options) as TODO_NODE_3286, - callback + new CollStatsOperation(this as TODO_NODE_3286, options) as TODO_NODE_3286 ); } @@ -1291,36 +798,18 @@ export class Collection { * * @param filter - The filter used to select the document to remove * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - findOneAndDelete(filter: Filter): Promise>; - findOneAndDelete( + async findOneAndDelete( filter: Filter, - options: FindOneAndDeleteOptions - ): Promise>; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - findOneAndDelete(filter: Filter, callback: Callback>): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - findOneAndDelete( - filter: Filter, - options: FindOneAndDeleteOptions, - callback: Callback> - ): void; - findOneAndDelete( - filter: Filter, - options?: FindOneAndDeleteOptions | Callback>, - callback?: Callback> - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + options?: FindOneAndDeleteOptions + ): Promise> { return executeOperation( this.s.db.s.client, new FindOneAndDeleteOperation( this as TODO_NODE_3286, filter, resolveOptions(this, options) - ) as TODO_NODE_3286, - callback + ) as TODO_NODE_3286 ); } @@ -1330,38 +819,12 @@ export class Collection { * @param filter - The filter used to select the document to replace * @param replacement - The Document that replaces the matching document * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - findOneAndReplace( - filter: Filter, - replacement: WithoutId - ): Promise>; - findOneAndReplace( + async findOneAndReplace( filter: Filter, replacement: WithoutId, - options: FindOneAndReplaceOptions - ): Promise>; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - findOneAndReplace( - filter: Filter, - replacement: WithoutId, - callback: Callback> - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - findOneAndReplace( - filter: Filter, - replacement: WithoutId, - options: FindOneAndReplaceOptions, - callback: Callback> - ): void; - findOneAndReplace( - filter: Filter, - replacement: WithoutId, - options?: FindOneAndReplaceOptions | Callback>, - callback?: Callback> - ): Promise> | void { - if (typeof options === 'function') (callback = options), (options = {}); - + options?: FindOneAndReplaceOptions + ): Promise> { return executeOperation( this.s.db.s.client, new FindOneAndReplaceOperation( @@ -1369,8 +832,7 @@ export class Collection { filter, replacement, resolveOptions(this, options) - ) as TODO_NODE_3286, - callback + ) as TODO_NODE_3286 ); } @@ -1380,38 +842,12 @@ export class Collection { * @param filter - The filter used to select the document to update * @param update - Update operations to be performed on the document * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - findOneAndUpdate( - filter: Filter, - update: UpdateFilter - ): Promise>; - findOneAndUpdate( - filter: Filter, - update: UpdateFilter, - options: FindOneAndUpdateOptions - ): Promise>; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - findOneAndUpdate( - filter: Filter, - update: UpdateFilter, - callback: Callback> - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - findOneAndUpdate( - filter: Filter, - update: UpdateFilter, - options: FindOneAndUpdateOptions, - callback: Callback> - ): void; - findOneAndUpdate( + async findOneAndUpdate( filter: Filter, update: UpdateFilter, - options?: FindOneAndUpdateOptions | Callback>, - callback?: Callback> - ): Promise> | void { - if (typeof options === 'function') (callback = options), (options = {}); - + options?: FindOneAndUpdateOptions + ): Promise> { return executeOperation( this.s.db.s.client, new FindOneAndUpdateOperation( @@ -1419,8 +855,7 @@ export class Collection { filter, update, resolveOptions(this, options) - ) as TODO_NODE_3286, - callback + ) as TODO_NODE_3286 ); } @@ -1434,19 +869,11 @@ export class Collection { pipeline: Document[] = [], options?: AggregateOptions ): AggregationCursor { - if (arguments.length > 2) { - throw new MongoInvalidArgumentError( - 'Method "collection.aggregate()" accepts at most two arguments' - ); - } if (!Array.isArray(pipeline)) { throw new MongoInvalidArgumentError( 'Argument "pipeline" must be an array of aggregation stages' ); } - if (typeof options === 'function') { - throw new MongoInvalidArgumentError('Argument "options" must not be function'); - } return new AggregationCursor( this.s.db.s.client, @@ -1542,41 +969,15 @@ export class Collection { * * @param filter - The filter for the count. * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - count(): Promise; - count(filter: Filter): Promise; - count(filter: Filter, options: CountOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - count(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - count(filter: Filter, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - count( - filter: Filter, - options: CountOptions, - callback: Callback - ): Promise | void; - count( - filter?: Filter | CountOptions | Callback, - options?: CountOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof filter === 'function') { - (callback = filter), (filter = {}), (options = {}); - } else { - if (typeof options === 'function') (callback = options), (options = {}); - } - - filter ??= {}; + async count(filter: Filter = {}, options: CountOptions = {}): Promise { return executeOperation( this.s.db.s.client, new CountOperation( MongoDBNamespace.fromString(this.namespace), filter, resolveOptions(this, options) - ), - callback + ) ); } } diff --git a/src/cursor/abstract_cursor.ts b/src/cursor/abstract_cursor.ts index a0662d6c30..2d9ec01a3d 100644 --- a/src/cursor/abstract_cursor.ts +++ b/src/cursor/abstract_cursor.ts @@ -21,7 +21,7 @@ import { ReadConcern, ReadConcernLike } from '../read_concern'; import { ReadPreference, ReadPreferenceLike } from '../read_preference'; import type { Server } from '../sdam/server'; import { ClientSession, maybeClearPinnedConnection } from '../sessions'; -import { Callback, List, maybeCallback, MongoDBNamespace, ns } from '../utils'; +import { Callback, List, MongoDBNamespace, ns } from '../utils'; /** @internal */ const kId = Symbol('id'); @@ -352,60 +352,43 @@ export abstract class AbstractCursor< return new ReadableCursorStream(this); } - hasNext(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - hasNext(callback: Callback): void; - hasNext(callback?: Callback): Promise | void { - return maybeCallback(async () => { - if (this[kId] === Long.ZERO) { - return false; - } + async hasNext(): Promise { + if (this[kId] === Long.ZERO) { + return false; + } - if (this[kDocuments].length !== 0) { - return true; - } + if (this[kDocuments].length !== 0) { + return true; + } - const doc = await nextAsync(this, true); + const doc = await nextAsync(this, true); - if (doc) { - this[kDocuments].unshift(doc); - return true; - } + if (doc) { + this[kDocuments].unshift(doc); + return true; + } - return false; - }, callback); + return false; } /** Get the next available document from the cursor, returns null if no more documents are available. */ - next(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - next(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - next(callback?: Callback): Promise | void; - next(callback?: Callback): Promise | void { - return maybeCallback(async () => { - if (this[kId] === Long.ZERO) { - throw new MongoCursorExhaustedError(); - } + async next(): Promise { + if (this[kId] === Long.ZERO) { + throw new MongoCursorExhaustedError(); + } - return nextAsync(this, true); - }, callback); + return nextAsync(this, true); } /** * Try to get the next available document from the cursor or `null` if an empty batch is returned */ - tryNext(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - tryNext(callback: Callback): void; - tryNext(callback?: Callback): Promise | void { - return maybeCallback(async () => { - if (this[kId] === Long.ZERO) { - throw new MongoCursorExhaustedError(); - } + async tryNext(): Promise { + if (this[kId] === Long.ZERO) { + throw new MongoCursorExhaustedError(); + } - return nextAsync(this, false); - }, callback); + return nextAsync(this, false); } /** @@ -414,36 +397,23 @@ export abstract class AbstractCursor< * If the iterator returns `false`, iteration will stop. * * @param iterator - The iteration callback. - * @param callback - The end callback. */ - forEach(iterator: (doc: TSchema) => boolean | void): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - forEach(iterator: (doc: TSchema) => boolean | void, callback: Callback): void; - forEach( - iterator: (doc: TSchema) => boolean | void, - callback?: Callback - ): Promise | void { + async forEach(iterator: (doc: TSchema) => boolean | void): Promise { if (typeof iterator !== 'function') { throw new MongoInvalidArgumentError('Argument "iterator" must be a function'); } - return maybeCallback(async () => { - for await (const document of this) { - const result = iterator(document); - if (result === false) { - break; - } + for await (const document of this) { + const result = iterator(document); + if (result === false) { + break; } - }, callback); + } } - close(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - close(callback: Callback): void; - close(callback?: Callback): Promise | void { + async close(): Promise { const needsToEmitClosed = !this[kClosed]; this[kClosed] = true; - - return maybeCallback(async () => cleanupCursorAsync(this, { needsToEmitClosed }), callback); + await cleanupCursorAsync(this, { needsToEmitClosed }); } /** @@ -451,20 +421,13 @@ export abstract class AbstractCursor< * is enough memory to store the results. Note that the array only contains partial * results when this cursor had been previously accessed. In that case, * cursor.rewind() can be used to reset the cursor. - * - * @param callback - The result callback. */ - toArray(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - toArray(callback: Callback): void; - toArray(callback?: Callback): Promise | void { - return maybeCallback(async () => { - const array = []; - for await (const document of this) { - array.push(document); - } - return array; - }, callback); + async toArray(): Promise { + const array = []; + for await (const document of this) { + array.push(document); + } + return array; } /** @@ -903,7 +866,10 @@ class ReadableCursorStream extends Readable { } override _destroy(error: Error | null, callback: (error?: Error | null) => void): void { - this._cursor.close(err => process.nextTick(callback, err || error)); + this._cursor.close().then( + () => callback(error), + closeError => callback(closeError) + ); } private _readNext() { diff --git a/src/cursor/aggregation_cursor.ts b/src/cursor/aggregation_cursor.ts index 981989902f..f57969d39b 100644 --- a/src/cursor/aggregation_cursor.ts +++ b/src/cursor/aggregation_cursor.ts @@ -77,25 +77,14 @@ export class AggregationCursor extends AbstractCursor { } /** Execute the explain for the cursor */ - explain(): Promise; - explain(verbosity: ExplainVerbosityLike): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - explain(callback: Callback): void; - explain( - verbosity?: ExplainVerbosityLike | Callback, - callback?: Callback - ): Promise | void { - if (typeof verbosity === 'function') (callback = verbosity), (verbosity = true); - if (verbosity == null) verbosity = true; - + async explain(verbosity?: ExplainVerbosityLike): Promise { return executeOperation( this.client, new AggregateOperation(this.namespace, this[kPipeline], { ...this[kOptions], // NOTE: order matters here, we may need to refine this ...this.cursorOptions, - explain: verbosity - }), - callback + explain: verbosity ?? true + }) ); } diff --git a/src/cursor/find_cursor.ts b/src/cursor/find_cursor.ts index 49f4f95cb2..ff4cd6ddf0 100644 --- a/src/cursor/find_cursor.ts +++ b/src/cursor/find_cursor.ts @@ -42,12 +42,12 @@ export class FindCursor extends AbstractCursor { constructor( client: MongoClient, namespace: MongoDBNamespace, - filter: Document | undefined, + filter: Document = {}, options: FindOptions = {} ) { super(client, namespace, options); - this[kFilter] = filter || {}; + this[kFilter] = filter; this[kBuiltOptions] = options; if (options.sort != null) { @@ -101,7 +101,8 @@ export class FindCursor extends AbstractCursor { limit && limit > 0 && numReturned + batchSize > limit ? limit - numReturned : batchSize; if (batchSize <= 0) { - return this.close(callback); + this.close().finally(() => callback()); + return; } } @@ -121,58 +122,32 @@ export class FindCursor extends AbstractCursor { * Get the count of documents for this cursor * @deprecated Use `collection.estimatedDocumentCount` or `collection.countDocuments` instead */ - count(): Promise; - /** @deprecated Use `collection.estimatedDocumentCount` or `collection.countDocuments` instead. */ - count(options: CountOptions): Promise; - /** @deprecated Use `collection.estimatedDocumentCount` or `collection.countDocuments` instead. Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - count(callback: Callback): void; - /** @deprecated Use `collection.estimatedDocumentCount` or `collection.countDocuments` instead. Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - count(options: CountOptions, callback: Callback): void; - count( - options?: CountOptions | Callback, - callback?: Callback - ): Promise | void { + async count(options?: CountOptions): Promise { emitWarningOnce( 'cursor.count is deprecated and will be removed in the next major version, please use `collection.estimatedDocumentCount` or `collection.countDocuments` instead ' ); if (typeof options === 'boolean') { throw new MongoInvalidArgumentError('Invalid first parameter to count'); } - - if (typeof options === 'function') (callback = options), (options = {}); - options = options ?? {}; - return executeOperation( this.client, new CountOperation(this.namespace, this[kFilter], { ...this[kBuiltOptions], // NOTE: order matters here, we may need to refine this ...this.cursorOptions, ...options - }), - callback + }) ); } /** Execute the explain for the cursor */ - explain(): Promise; - explain(verbosity?: ExplainVerbosityLike): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - explain(callback: Callback): void; - explain( - verbosity?: ExplainVerbosityLike | Callback, - callback?: Callback - ): Promise | void { - if (typeof verbosity === 'function') (callback = verbosity), (verbosity = true); - if (verbosity == null) verbosity = true; - + async explain(verbosity?: ExplainVerbosityLike): Promise { return executeOperation( this.client, new FindOperation(undefined, this.namespace, this[kFilter], { ...this[kBuiltOptions], // NOTE: order matters here, we may need to refine this ...this.cursorOptions, - explain: verbosity - }), - callback + explain: verbosity ?? true + }) ); } diff --git a/src/db.ts b/src/db.ts index 4133d491c5..67c49dd96e 100644 --- a/src/db.ts +++ b/src/db.ts @@ -39,13 +39,7 @@ import { import { DbStatsOperation, DbStatsOptions } from './operations/stats'; import { ReadConcern } from './read_concern'; import { ReadPreference, ReadPreferenceLike } from './read_preference'; -import { - Callback, - DEFAULT_PK_FACTORY, - filterOptions, - MongoDBNamespace, - resolveOptions -} from './utils'; +import { DEFAULT_PK_FACTORY, filterOptions, MongoDBNamespace, resolveOptions } from './utils'; import { WriteConcern, WriteConcernOptions } from './write_concern'; // Allowed parameters @@ -220,35 +214,15 @@ export class Db { * * @param name - The name of the collection to create * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - createCollection( + async createCollection( name: string, options?: CreateCollectionOptions - ): Promise>; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - createCollection( - name: string, - callback: Callback> - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - createCollection( - name: string, - options: CreateCollectionOptions | undefined, - callback: Callback> - ): void; - createCollection( - name: string, - options?: CreateCollectionOptions | Callback, - callback?: Callback - ): Promise> | void { - if (typeof options === 'function') (callback = options), (options = {}); - + ): Promise> { return executeOperation( this.s.client, - new CreateCollectionOperation(this, name, resolveOptions(this, options)) as TODO_NODE_3286, - callback - ) as TODO_NODE_3286; + new CreateCollectionOperation(this, name, resolveOptions(this, options)) as TODO_NODE_3286 + ); } /** @@ -259,27 +233,10 @@ export class Db { * * @param command - The command to run * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - command(command: Document): Promise; - command(command: Document, options: RunCommandOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - command(command: Document, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - command(command: Document, options: RunCommandOptions, callback: Callback): void; - command( - command: Document, - options?: RunCommandOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async command(command: Document, options?: RunCommandOptions): Promise { // Intentionally, we do not inherit options from parent for this operation. - return executeOperation( - this.s.client, - new RunCommandOperation(this, command, options ?? {}), - callback - ); + return executeOperation(this.s.client, new RunCommandOperation(this, command, options)); } /** @@ -292,16 +249,6 @@ export class Db { pipeline: Document[] = [], options?: AggregateOptions ): AggregationCursor { - if (arguments.length > 2) { - throw new MongoInvalidArgumentError('Method "db.aggregate()" accepts at most two arguments'); - } - if (typeof pipeline === 'function') { - throw new MongoInvalidArgumentError('Argument "pipeline" must not be function'); - } - if (typeof options === 'function') { - throw new MongoInvalidArgumentError('Argument "options" must not be function'); - } - return new AggregationCursor( this.s.client, this.s.namespace, @@ -328,31 +275,18 @@ export class Db { if (typeof options === 'function') { throw new MongoInvalidArgumentError('The callback form of this helper has been removed.'); } - const finalOptions = resolveOptions(this, options); - return new Collection(this, name, finalOptions); + return new Collection(this, name, resolveOptions(this, options)); } /** * Get all the db statistics. * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - stats(): Promise; - stats(options: DbStatsOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - stats(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - stats(options: DbStatsOptions, callback: Callback): void; - stats( - options?: DbStatsOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); + async stats(options?: DbStatsOptions): Promise { return executeOperation( this.s.client, - new DbStatsOperation(this, resolveOptions(this, options)), - callback + new DbStatsOperation(this, resolveOptions(this, options)) ); } @@ -392,52 +326,20 @@ export class Db { * @param fromCollection - Name of current collection to rename * @param toCollection - New name of of the collection * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - renameCollection( - fromCollection: string, - toCollection: string - ): Promise>; - renameCollection( - fromCollection: string, - toCollection: string, - options: RenameOptions - ): Promise>; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - renameCollection( + async renameCollection( fromCollection: string, toCollection: string, - callback: Callback> - ): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - renameCollection( - fromCollection: string, - toCollection: string, - options: RenameOptions, - callback: Callback> - ): void; - renameCollection( - fromCollection: string, - toCollection: string, - options?: RenameOptions | Callback>, - callback?: Callback> - ): Promise> | void { - if (typeof options === 'function') (callback = options), (options = {}); - + options?: RenameOptions + ): Promise> { // Intentionally, we do not inherit options from parent for this operation. - options = { ...options, readPreference: ReadPreference.PRIMARY }; - - // Add return new collection - options.new_collection = true; - return executeOperation( this.s.client, new RenameOperation( this.collection(fromCollection) as TODO_NODE_3286, toCollection, - options - ) as TODO_NODE_3286, - callback + { ...options, new_collection: true, readPreference: ReadPreference.primary } + ) as TODO_NODE_3286 ); } @@ -446,25 +348,11 @@ export class Db { * * @param name - Name of collection to drop * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - dropCollection(name: string): Promise; - dropCollection(name: string, options: DropCollectionOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - dropCollection(name: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - dropCollection(name: string, options: DropCollectionOptions, callback: Callback): void; - dropCollection( - name: string, - options?: DropCollectionOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async dropCollection(name: string, options?: DropCollectionOptions): Promise { return executeOperation( this.s.client, - new DropCollectionOperation(this, name, resolveOptions(this, options)), - callback + new DropCollectionOperation(this, name, resolveOptions(this, options)) ); } @@ -472,24 +360,11 @@ export class Db { * Drop a database, removing it permanently from the server. * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - dropDatabase(): Promise; - dropDatabase(options: DropDatabaseOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - dropDatabase(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - dropDatabase(options: DropDatabaseOptions, callback: Callback): void; - dropDatabase( - options?: DropDatabaseOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async dropDatabase(options?: DropDatabaseOptions): Promise { return executeOperation( this.s.client, - new DropDatabaseOperation(this, resolveOptions(this, options)), - callback + new DropDatabaseOperation(this, resolveOptions(this, options)) ); } @@ -497,24 +372,11 @@ export class Db { * Fetch all collections for the current db. * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - collections(): Promise; - collections(options: ListCollectionsOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - collections(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - collections(options: ListCollectionsOptions, callback: Callback): void; - collections( - options?: ListCollectionsOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async collections(options?: ListCollectionsOptions): Promise { return executeOperation( this.s.client, - new CollectionsOperation(this, resolveOptions(this, options)), - callback + new CollectionsOperation(this, resolveOptions(this, options)) ); } @@ -524,35 +386,15 @@ export class Db { * @param name - Name of the collection to create the index on. * @param indexSpec - Specify the field to index, or an index specification * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - createIndex(name: string, indexSpec: IndexSpecification): Promise; - createIndex( + async createIndex( name: string, indexSpec: IndexSpecification, - options: CreateIndexesOptions - ): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - createIndex(name: string, indexSpec: IndexSpecification, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - createIndex( - name: string, - indexSpec: IndexSpecification, - options: CreateIndexesOptions, - callback: Callback - ): void; - createIndex( - name: string, - indexSpec: IndexSpecification, - options?: CreateIndexesOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + options?: CreateIndexesOptions + ): Promise { return executeOperation( this.s.client, - new CreateIndexOperation(this, name, indexSpec, resolveOptions(this, options)), - callback + new CreateIndexOperation(this, name, indexSpec, resolveOptions(this, options)) ); } @@ -560,49 +402,24 @@ export class Db { * Add a user to the database * * @param username - The username for the new user - * @param password - An optional password for the new user + * @param passwordOrOptions - An optional password for the new user, or the options for the command * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - addUser(username: string): Promise; - addUser(username: string, password: string): Promise; - addUser(username: string, options: AddUserOptions): Promise; - addUser(username: string, password: string, options: AddUserOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - addUser(username: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - addUser(username: string, password: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - addUser(username: string, options: AddUserOptions, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - addUser( - username: string, - password: string, - options: AddUserOptions, - callback: Callback - ): void; - addUser( + async addUser( username: string, - password?: string | AddUserOptions | Callback, - options?: AddUserOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof password === 'function') { - (callback = password), (password = undefined), (options = {}); - } else if (typeof password !== 'string') { - if (typeof options === 'function') { - (callback = options), (options = password), (password = undefined); - } else { - (options = password), (callback = undefined), (password = undefined); - } - } else { - if (typeof options === 'function') (callback = options), (options = {}); - } - + passwordOrOptions?: string | AddUserOptions, + options?: AddUserOptions + ): Promise { + options = + options != null && typeof options === 'object' + ? options + : passwordOrOptions != null && typeof passwordOrOptions === 'object' + ? passwordOrOptions + : undefined; + const password = typeof passwordOrOptions === 'string' ? passwordOrOptions : undefined; return executeOperation( this.s.client, - new AddUserOperation(this, username, password, resolveOptions(this, options)), - callback + new AddUserOperation(this, username, password, resolveOptions(this, options)) ); } @@ -611,25 +428,11 @@ export class Db { * * @param username - The username to remove * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - removeUser(username: string): Promise; - removeUser(username: string, options: RemoveUserOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - removeUser(username: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - removeUser(username: string, options: RemoveUserOptions, callback: Callback): void; - removeUser( - username: string, - options?: RemoveUserOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async removeUser(username: string, options?: RemoveUserOptions): Promise { return executeOperation( this.s.client, - new RemoveUserOperation(this, username, resolveOptions(this, options)), - callback + new RemoveUserOperation(this, username, resolveOptions(this, options)) ); } @@ -638,32 +441,14 @@ export class Db { * * @param level - The new profiling level (off, slow_only, all). * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - setProfilingLevel(level: ProfilingLevel): Promise; - setProfilingLevel( - level: ProfilingLevel, - options: SetProfilingLevelOptions - ): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - setProfilingLevel(level: ProfilingLevel, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - setProfilingLevel( - level: ProfilingLevel, - options: SetProfilingLevelOptions, - callback: Callback - ): void; - setProfilingLevel( + async setProfilingLevel( level: ProfilingLevel, - options?: SetProfilingLevelOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + options?: SetProfilingLevelOptions + ): Promise { return executeOperation( this.s.client, - new SetProfilingLevelOperation(this, level, resolveOptions(this, options)), - callback + new SetProfilingLevelOperation(this, level, resolveOptions(this, options)) ); } @@ -671,24 +456,11 @@ export class Db { * Retrieve the current profiling Level for MongoDB * * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - profilingLevel(): Promise; - profilingLevel(options: ProfilingLevelOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - profilingLevel(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - profilingLevel(options: ProfilingLevelOptions, callback: Callback): void; - profilingLevel( - options?: ProfilingLevelOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async profilingLevel(options?: ProfilingLevelOptions): Promise { return executeOperation( this.s.client, - new ProfilingLevelOperation(this, resolveOptions(this, options)), - callback + new ProfilingLevelOperation(this, resolveOptions(this, options)) ); } @@ -697,29 +469,11 @@ export class Db { * * @param name - The name of the collection. * @param options - Optional settings for the command - * @param callback - An optional callback, a Promise will be returned if none is provided */ - indexInformation(name: string): Promise; - indexInformation(name: string, options: IndexInformationOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - indexInformation(name: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - indexInformation( - name: string, - options: IndexInformationOptions, - callback: Callback - ): void; - indexInformation( - name: string, - options?: IndexInformationOptions | Callback, - callback?: Callback - ): Promise | void { - if (typeof options === 'function') (callback = options), (options = {}); - + async indexInformation(name: string, options?: IndexInformationOptions): Promise { return executeOperation( this.s.client, - new IndexInformationOperation(this, name, resolveOptions(this, options)), - callback + new IndexInformationOperation(this, name, resolveOptions(this, options)) ); } diff --git a/src/gridfs/download.ts b/src/gridfs/download.ts index 9e96151478..0053ecc9a0 100644 --- a/src/gridfs/download.ts +++ b/src/gridfs/download.ts @@ -182,30 +182,22 @@ export class GridFSBucketReadStream extends Readable implements NodeJS.ReadableS * Marks this stream as aborted (will never push another `data` event) * and kills the underlying cursor. Will emit the 'end' event, and then * the 'close' event once the cursor is successfully killed. - * - * @param callback - called when the cursor is successfully closed or an error occurred. */ - abort(callback?: Callback): void { + async abort(): Promise { this.push(null); this.destroyed = true; if (this.s.cursor) { - this.s.cursor.close().then( - () => { - this.emit(GridFSBucketReadStream.CLOSE); - callback?.(); - }, - error => { - this.emit(GridFSBucketReadStream.CLOSE); - callback?.(error); - } - ); + try { + await this.s.cursor.close(); + } finally { + this.emit(GridFSBucketReadStream.CLOSE); + } } else { if (!this.s.init) { // If not initialized, fire close event because we will never // get a cursor this.emit(GridFSBucketReadStream.CLOSE); } - callback && callback(); } } } diff --git a/src/gridfs/index.ts b/src/gridfs/index.ts index 301df170fb..8471859a9e 100644 --- a/src/gridfs/index.ts +++ b/src/gridfs/index.ts @@ -6,7 +6,6 @@ import { MongoRuntimeError } from '../error'; import { Filter, TypedEventEmitter } from '../mongo_types'; import type { ReadPreference } from '../read_preference'; import type { Sort } from '../sort'; -import { Callback, maybeCallback } from '../utils'; import { WriteConcern, WriteConcernOptions } from '../write_concern'; import type { FindOptions } from './../operations/find'; import { @@ -139,28 +138,21 @@ export class GridFSBucket extends TypedEventEmitter { * * @param id - The id of the file doc */ - delete(id: ObjectId): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - delete(id: ObjectId, callback: Callback): void; - delete(id: ObjectId, callback?: Callback): Promise | void { - return maybeCallback(async () => { - const { deletedCount } = await this.s._filesCollection.deleteOne({ _id: id }); - - // Delete orphaned chunks before returning FileNotFound - await this.s._chunksCollection.deleteMany({ files_id: id }); - - if (deletedCount === 0) { - // TODO(NODE-3483): Replace with more appropriate error - // Consider creating new error MongoGridFSFileNotFoundError - throw new MongoRuntimeError(`File not found for id ${id}`); - } - }, callback); + async delete(id: ObjectId): Promise { + const { deletedCount } = await this.s._filesCollection.deleteOne({ _id: id }); + + // Delete orphaned chunks before returning FileNotFound + await this.s._chunksCollection.deleteMany({ files_id: id }); + + if (deletedCount === 0) { + // TODO(NODE-3483): Replace with more appropriate error + // Consider creating new error MongoGridFSFileNotFoundError + throw new MongoRuntimeError(`File not found for id ${id}`); + } } /** Convenience wrapper around find on the files collection */ - find(filter?: Filter, options?: FindOptions): FindCursor { - filter ??= {}; - options = options ?? {}; + find(filter: Filter = {}, options: FindOptions = {}): FindCursor { return this.s._filesCollection.find(filter, options); } @@ -200,28 +192,18 @@ export class GridFSBucket extends TypedEventEmitter { * @param id - the id of the file to rename * @param filename - new name for the file */ - rename(id: ObjectId, filename: string): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - rename(id: ObjectId, filename: string, callback: Callback): void; - rename(id: ObjectId, filename: string, callback?: Callback): Promise | void { - return maybeCallback(async () => { - const filter = { _id: id }; - const update = { $set: { filename } }; - const { matchedCount } = await this.s._filesCollection.updateOne(filter, update); - if (matchedCount === 0) { - throw new MongoRuntimeError(`File with id ${id} not found`); - } - }, callback); + async rename(id: ObjectId, filename: string): Promise { + const filter = { _id: id }; + const update = { $set: { filename } }; + const { matchedCount } = await this.s._filesCollection.updateOne(filter, update); + if (matchedCount === 0) { + throw new MongoRuntimeError(`File with id ${id} not found`); + } } /** Removes this bucket's files collection, followed by its chunks collection. */ - drop(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - drop(callback: Callback): void; - drop(callback?: Callback): Promise | void { - return maybeCallback(async () => { - await this.s._filesCollection.drop(); - await this.s._chunksCollection.drop(); - }, callback); + async drop(): Promise { + await this.s._filesCollection.drop(); + await this.s._chunksCollection.drop(); } } diff --git a/src/gridfs/upload.ts b/src/gridfs/upload.ts index e36c026d51..a5dabc564d 100644 --- a/src/gridfs/upload.ts +++ b/src/gridfs/upload.ts @@ -4,7 +4,7 @@ import type { Document } from '../bson'; import { ObjectId } from '../bson'; import type { Collection } from '../collection'; import { AnyError, MongoAPIError, MONGODB_ERROR_CODES, MongoError } from '../error'; -import { Callback, maybeCallback } from '../utils'; +import type { Callback } from '../utils'; import type { WriteConcernOptions } from '../write_concern'; import { WriteConcern } from './../write_concern'; import type { GridFSFile } from './download'; @@ -144,27 +144,20 @@ export class GridFSBucketWriteStream extends Writable implements NodeJS.Writable /** * Places this write stream into an aborted state (all future writes fail) * and deletes all chunks that have already been written. - * - * @param callback - called when chunks are successfully removed or error occurred */ - abort(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - abort(callback: Callback): void; - abort(callback?: Callback): Promise | void { - return maybeCallback(async () => { - if (this.state.streamEnd) { - // TODO(NODE-3485): Replace with MongoGridFSStreamClosed - throw new MongoAPIError('Cannot abort a stream that has already completed'); - } + async abort(): Promise { + if (this.state.streamEnd) { + // TODO(NODE-3485): Replace with MongoGridFSStreamClosed + throw new MongoAPIError('Cannot abort a stream that has already completed'); + } - if (this.state.aborted) { - // TODO(NODE-3485): Replace with MongoGridFSStreamClosed - throw new MongoAPIError('Cannot call abort() on a stream twice'); - } + if (this.state.aborted) { + // TODO(NODE-3485): Replace with MongoGridFSStreamClosed + throw new MongoAPIError('Cannot call abort() on a stream twice'); + } - this.state.aborted = true; - await this.chunks.deleteMany({ files_id: this.id }); - }, callback); + this.state.aborted = true; + await this.chunks.deleteMany({ files_id: this.id }); } /** diff --git a/src/mongo_client.ts b/src/mongo_client.ts index a34767758e..391ab3959c 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -24,15 +24,7 @@ import { readPreferenceServerSelector } from './sdam/server_selection'; import type { SrvPoller } from './sdam/srv_polling'; import { Topology, TopologyEvents } from './sdam/topology'; import { ClientSession, ClientSessionOptions, ServerSessionPool } from './sessions'; -import { - Callback, - ClientMetadata, - HostAddress, - maybeCallback, - MongoDBNamespace, - ns, - resolveOptions -} from './utils'; +import { ClientMetadata, HostAddress, MongoDBNamespace, ns, resolveOptions } from './utils'; import type { W, WriteConcern, WriteConcernSettings } from './write_concern'; /** @public */ @@ -412,79 +404,60 @@ export class MongoClient extends TypedEventEmitter { * * @see docs.mongodb.org/manual/reference/connection-string/ */ - connect(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - connect(callback: Callback): void; - connect(callback?: Callback): Promise | void { - if (callback && typeof callback !== 'function') { - throw new MongoInvalidArgumentError('Method `connect` only accepts a callback'); + async connect(): Promise { + if (this.topology && this.topology.isConnected()) { + return this; } - return maybeCallback(async () => { - if (this.topology && this.topology.isConnected()) { - return this; - } - - const options = this[kOptions]; + const options = this[kOptions]; - if (typeof options.srvHost === 'string') { - const hosts = await resolveSRVRecord(options); + if (typeof options.srvHost === 'string') { + const hosts = await resolveSRVRecord(options); - for (const [index, host] of hosts.entries()) { - options.hosts[index] = host; - } + for (const [index, host] of hosts.entries()) { + options.hosts[index] = host; } + } - const topology = new Topology(options.hosts, options); - // Events can be emitted before initialization is complete so we have to - // save the reference to the topology on the client ASAP if the event handlers need to access it - this.topology = topology; - topology.client = this; + const topology = new Topology(options.hosts, options); + // Events can be emitted before initialization is complete so we have to + // save the reference to the topology on the client ASAP if the event handlers need to access it + this.topology = topology; + topology.client = this; - topology.once(Topology.OPEN, () => this.emit('open', this)); + topology.once(Topology.OPEN, () => this.emit('open', this)); - for (const event of MONGO_CLIENT_EVENTS) { - topology.on(event, (...args: any[]) => this.emit(event, ...(args as any))); - } + for (const event of MONGO_CLIENT_EVENTS) { + topology.on(event, (...args: any[]) => this.emit(event, ...(args as any))); + } - const topologyConnect = async () => { - try { - await promisify(callback => topology.connect(options, callback))(); - } catch (error) { - topology.close({ force: true }); - throw error; - } - }; - - if (this.autoEncrypter) { - const initAutoEncrypter = promisify(callback => this.autoEncrypter?.init(callback)); - await initAutoEncrypter(); - await topologyConnect(); - await options.encrypter.connectInternalClient(); - } else { - await topologyConnect(); + const topologyConnect = async () => { + try { + await promisify(callback => topology.connect(options, callback))(); + } catch (error) { + topology.close({ force: true }); + throw error; } + }; - return this; - }, callback); + if (this.autoEncrypter) { + const initAutoEncrypter = promisify(callback => this.autoEncrypter?.init(callback)); + await initAutoEncrypter(); + await topologyConnect(); + await options.encrypter.connectInternalClient(); + } else { + await topologyConnect(); + } + + return this; } /** - * Close the db and its underlying connections + * Close the client and its underlying connections * * @param force - Force close, emitting no events - * @param callback - An optional callback, a Promise will be returned if none is provided */ - close(): Promise; - close(force: boolean): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - close(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - close(force: boolean, callback: Callback): void; - close( - forceOrCallback?: boolean | Callback, - callback?: Callback - ): Promise | void { + async close(force = false): Promise { // There's no way to set hasBeenClosed back to false Object.defineProperty(this.s, 'hasBeenClosed', { value: true, @@ -493,58 +466,50 @@ export class MongoClient extends TypedEventEmitter { writable: false }); - if (typeof forceOrCallback === 'function') { - callback = forceOrCallback; - } - - const force = typeof forceOrCallback === 'boolean' ? forceOrCallback : false; + const activeSessionEnds = Array.from(this.s.activeSessions, session => session.endSession()); + this.s.activeSessions.clear(); - return maybeCallback(async () => { - const activeSessionEnds = Array.from(this.s.activeSessions, session => session.endSession()); - this.s.activeSessions.clear(); + await Promise.all(activeSessionEnds); - await Promise.all(activeSessionEnds); + if (this.topology == null) { + return; + } - if (this.topology == null) { - return; + // If we would attempt to select a server and get nothing back we short circuit + // to avoid the server selection timeout. + const selector = readPreferenceServerSelector(ReadPreference.primaryPreferred); + const topologyDescription = this.topology.description; + const serverDescriptions = Array.from(topologyDescription.servers.values()); + const servers = selector(topologyDescription, serverDescriptions); + if (servers.length !== 0) { + const endSessions = Array.from(this.s.sessionPool.sessions, ({ id }) => id); + if (endSessions.length !== 0) { + await this.db('admin') + .command( + { endSessions }, + { readPreference: ReadPreference.primaryPreferred, noResponse: true } + ) + .catch(() => null); // outcome does not matter } + } - // If we would attempt to select a server and get nothing back we short circuit - // to avoid the server selection timeout. - const selector = readPreferenceServerSelector(ReadPreference.primaryPreferred); - const topologyDescription = this.topology.description; - const serverDescriptions = Array.from(topologyDescription.servers.values()); - const servers = selector(topologyDescription, serverDescriptions); - if (servers.length !== 0) { - const endSessions = Array.from(this.s.sessionPool.sessions, ({ id }) => id); - if (endSessions.length !== 0) { - await this.db('admin') - .command( - { endSessions }, - { readPreference: ReadPreference.primaryPreferred, noResponse: true } - ) - .catch(() => null); // outcome does not matter + // clear out references to old topology + const topology = this.topology; + this.topology = undefined; + + await new Promise((resolve, reject) => { + topology.close({ force }, error => { + if (error) return reject(error); + const { encrypter } = this[kOptions]; + if (encrypter) { + return encrypter.close(this, force, error => { + if (error) return reject(error); + resolve(); + }); } - } - - // clear out references to old topology - const topology = this.topology; - this.topology = undefined; - - await new Promise((resolve, reject) => { - topology.close({ force }, error => { - if (error) return reject(error); - const { encrypter } = this[kOptions]; - if (encrypter) { - return encrypter.close(this, force, error => { - if (error) return reject(error); - resolve(); - }); - } - resolve(); - }); + resolve(); }); - }, callback); + }); } /** @@ -579,34 +544,12 @@ export class MongoClient extends TypedEventEmitter { * * @see https://docs.mongodb.org/manual/reference/connection-string/ */ - static connect(url: string): Promise; - static connect(url: string, options: MongoClientOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - static connect(url: string, callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - static connect(url: string, options: MongoClientOptions, callback: Callback): void; - static connect( - url: string, - options?: MongoClientOptions | Callback, - callback?: Callback - ): Promise | void { - callback = - typeof callback === 'function' - ? callback - : typeof options === 'function' - ? options - : undefined; - - return maybeCallback(async () => { - options = typeof options !== 'function' ? options : undefined; - const client = new this(url, options); - return client.connect(); - }, callback); + static async connect(url: string, options?: MongoClientOptions): Promise { + const client = new this(url, options); + return client.connect(); } /** Starts a new session on the server */ - startSession(): ClientSession; - startSession(options: ClientSessionOptions): ClientSession; startSession(options?: ClientSessionOptions): ClientSession { const session = new ClientSession( this, @@ -630,10 +573,10 @@ export class MongoClient extends TypedEventEmitter { * @param options - Optional settings for the command * @param callback - An callback to execute with an implicitly created session */ - withSession(callback: WithSessionCallback): Promise; - withSession(options: ClientSessionOptions, callback: WithSessionCallback): Promise; - withSession( - optionsOrOperation?: ClientSessionOptions | WithSessionCallback, + async withSession(callback: WithSessionCallback): Promise; + async withSession(options: ClientSessionOptions, callback: WithSessionCallback): Promise; + async withSession( + optionsOrOperation: ClientSessionOptions | WithSessionCallback, callback?: WithSessionCallback ): Promise { const options = { @@ -652,17 +595,15 @@ export class MongoClient extends TypedEventEmitter { const session = this.startSession(options); - return maybeCallback(async () => { + try { + await withSessionCallback(session); + } finally { try { - await withSessionCallback(session); - } finally { - try { - await session.endSession(); - } catch { - // We are not concerned with errors from endSession() - } + await session.endSession(); + } catch { + // We are not concerned with errors from endSession() } - }, null); + } } /** diff --git a/src/sessions.ts b/src/sessions.ts index ddc0e53f5a..9e42795229 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -37,7 +37,6 @@ import { isPromiseLike, List, maxWireVersion, - maybeCallback, now, uuidV4 } from './utils'; @@ -247,47 +246,32 @@ export class ClientSession extends TypedEventEmitter { * Ends this session on the server * * @param options - Optional settings. Currently reserved for future use - * @param callback - Optional callback for completion of this operation */ - endSession(): Promise; - endSession(options: EndSessionOptions): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - endSession(callback: Callback): void; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - endSession(options: EndSessionOptions, callback: Callback): void; - endSession( - options?: EndSessionOptions | Callback, - callback?: Callback - ): void | Promise { - if (typeof options === 'function') (callback = options), (options = {}); - const finalOptions = { force: true, ...options }; - - return maybeCallback(async () => { - try { - if (this.inTransaction()) { - await this.abortTransaction(); - } - if (!this.hasEnded) { - const serverSession = this[kServerSession]; - if (serverSession != null) { - // release the server session back to the pool - this.sessionPool.release(serverSession); - // Make sure a new serverSession never makes it onto this ClientSession - Object.defineProperty(this, kServerSession, { - value: ServerSession.clone(serverSession), - writable: false - }); - } - // mark the session as ended, and emit a signal - this.hasEnded = true; - this.emit('ended', this); + async endSession(options?: EndSessionOptions): Promise { + try { + if (this.inTransaction()) { + await this.abortTransaction(); + } + if (!this.hasEnded) { + const serverSession = this[kServerSession]; + if (serverSession != null) { + // release the server session back to the pool + this.sessionPool.release(serverSession); + // Make sure a new serverSession never makes it onto this ClientSession + Object.defineProperty(this, kServerSession, { + value: ServerSession.clone(serverSession), + writable: false + }); } - } catch { - // spec indicates that we should ignore all errors for `endSessions` - } finally { - maybeClearPinnedConnection(this, finalOptions); + // mark the session as ended, and emit a signal + this.hasEnded = true; + this.emit('ended', this); } - }, callback); + } catch { + // spec indicates that we should ignore all errors for `endSessions` + } finally { + maybeClearPinnedConnection(this, { force: true, ...options }); + } } /** @@ -421,26 +405,16 @@ export class ClientSession extends TypedEventEmitter { /** * Commits the currently active transaction in this session. - * - * @param callback - An optional callback, a Promise will be returned if none is provided */ - commitTransaction(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - commitTransaction(callback: Callback): void; - commitTransaction(callback?: Callback): Promise | void { - return maybeCallback(async () => endTransactionAsync(this, 'commitTransaction'), callback); + async commitTransaction(): Promise { + return endTransactionAsync(this, 'commitTransaction'); } /** * Aborts the currently active transaction in this session. - * - * @param callback - An optional callback, a Promise will be returned if none is provided */ - abortTransaction(): Promise; - /** @deprecated Callbacks are deprecated and will be removed in the next major version. See [mongodb-legacy](https://github.com/mongodb-js/nodejs-mongodb-legacy) for migration assistance */ - abortTransaction(callback: Callback): void; - abortTransaction(callback?: Callback): Promise | void { - return maybeCallback(async () => endTransactionAsync(this, 'abortTransaction'), callback); + async abortTransaction(): Promise { + return endTransactionAsync(this, 'abortTransaction'); } /** @@ -471,7 +445,7 @@ export class ClientSession extends TypedEventEmitter { * @param options - optional settings for the transaction * @returns A raw command response or undefined */ - withTransaction( + async withTransaction( fn: WithTransactionCallback, options?: TransactionOptions ): Promise { diff --git a/test/integration/change-streams/change_stream.test.ts b/test/integration/change-streams/change_stream.test.ts index 05074716af..213a5bd628 100644 --- a/test/integration/change-streams/change_stream.test.ts +++ b/test/integration/change-streams/change_stream.test.ts @@ -749,16 +749,14 @@ describe('Change Streams', function () { const errRegex = /ChangeStream cannot be used as an iterator/; - // These all throw synchronously so it should be safe to not await the results - expect(() => { - changeStream.next(); - }).to.throw(errRegex); - expect(() => { - changeStream.hasNext(); - }).to.throw(errRegex); - expect(() => { - changeStream.tryNext(); - }).to.throw(errRegex); + const nextError = await changeStream.next().catch(error => error); + expect(nextError.message).to.match(errRegex); + + const hasNextError = await changeStream.hasNext().catch(error => error); + expect(hasNextError.message).to.match(errRegex); + + const tryNextError = await changeStream.tryNext().catch(error => error); + expect(tryNextError.message).to.match(errRegex); } }); diff --git a/test/integration/change-streams/change_streams.prose.test.ts b/test/integration/change-streams/change_streams.prose.test.ts index 531776adeb..152b89fbc5 100644 --- a/test/integration/change-streams/change_streams.prose.test.ts +++ b/test/integration/change-streams/change_streams.prose.test.ts @@ -37,7 +37,7 @@ function triggerResumableError( } const stub = sinon.stub(changeStream.cursor, 'close'); - stub.callsFake(function () { + stub.callsFake(async function () { stub.wrappedMethod.call(this); stub.restore(); onClose(); @@ -50,7 +50,7 @@ function triggerResumableError( return; } - const nextStub = sinon.stub(changeStream.cursor, 'next').callsFake(function (callback) { + const nextStub = sinon.stub(changeStream.cursor, 'next').callsFake(async function () { callback(new MongoNetworkError('error triggered from test')); nextStub.restore(); }); diff --git a/test/integration/collection-management/collection.test.ts b/test/integration/collection-management/collection.test.ts index d7fba71231..5b4cac76ac 100644 --- a/test/integration/collection-management/collection.test.ts +++ b/test/integration/collection-management/collection.test.ts @@ -241,15 +241,14 @@ describe('Collection', function () { }); }); - it('should throw error due to illegal update', function (done) { - db.createCollection('shouldThrowErrorDueToIllegalUpdate', {}, (err, coll) => { - expect(() => coll.update({}, null)).to.throw(/Document must be a valid JavaScript object/); - expect(() => coll.update(null, null)).to.throw( - /Selector must be a valid JavaScript object/ - ); + it('should throw error due to illegal update', async function () { + const coll = await db.createCollection('shouldThrowErrorDueToIllegalUpdate', {}); - done(); - }); + const filterError = await coll.updateOne(null, {}).catch(error => error); + expect(filterError.message).to.match(/Selector must be a valid JavaScript object/); + + const updateError = await coll.updateOne({}, null).catch(error => error); + expect(updateError.message).to.match(/Document must be a valid JavaScript object/); }); const selectorTests = [ diff --git a/test/integration/crud/find_and_modify.test.js b/test/integration/crud/find_and_modify.test.js index c2e3607384..2735d0a95e 100644 --- a/test/integration/crud/find_and_modify.test.js +++ b/test/integration/crud/find_and_modify.test.js @@ -308,16 +308,14 @@ describe('Find and Modify', function () { } }); - it('should not allow atomic operators for findOneAndReplace', { - metadata: { requires: { topology: 'single' } }, - test: async function () { - const client = this.configuration.newClient(); - const db = client.db('fakeDb'); - const collection = db.collection('test'); - expect(() => { - collection.findOneAndReplace({ a: 1 }, { $set: { a: 14 } }); - }).to.throw(/must not contain atomic operators/); - await client.close(); - } + it('should not allow atomic operators for findOneAndReplace', async function () { + const client = this.configuration.newClient(); + const db = client.db('fakeDb'); + const collection = db.collection('test'); + const error = await collection + .findOneAndReplace({ a: 1 }, { $set: { a: 14 } }) + .catch(error => error); + expect(error.message).to.match(/must not contain atomic operators/); + await client.close(); }); }); diff --git a/test/integration/crud/find_cursor_methods.test.js b/test/integration/crud/find_cursor_methods.test.js index 278ddeca14..9ead78b794 100644 --- a/test/integration/crud/find_cursor_methods.test.js +++ b/test/integration/crud/find_cursor_methods.test.js @@ -205,48 +205,32 @@ describe('Find Cursor', function () { }); context('#clone', function () { - it('should clone a find cursor', function (done) { + it('should clone a find cursor', async function () { const coll = client.db().collection('abstract_cursor'); const cursor = coll.find({}); - this.defer(() => cursor.close()); - - cursor.toArray((err, docs) => { - expect(err).to.not.exist; - expect(docs).to.have.length(6); - expect(cursor).property('closed').to.be.true; - const clonedCursor = cursor.clone(); - this.defer(() => clonedCursor.close()); + const docsFromOriginal = await cursor.toArray(); + expect(docsFromOriginal).to.have.length(6); + expect(cursor).property('closed').to.be.true; - clonedCursor.toArray((err, docs) => { - expect(err).to.not.exist; - expect(docs).to.have.length(6); - expect(clonedCursor).property('closed').to.be.true; - done(); - }); - }); + const clonedCursor = cursor.clone(); + const docsFromCloned = await clonedCursor.toArray(); + expect(docsFromCloned).to.have.length(6); + expect(cursor).property('closed').to.be.true; }); - it('should clone an aggregate cursor', function (done) { + it('should clone an aggregate cursor', async function () { const coll = client.db().collection('abstract_cursor'); const cursor = coll.aggregate([{ $match: {} }]); - this.defer(() => cursor.close()); - - cursor.toArray((err, docs) => { - expect(err).to.not.exist; - expect(docs).to.have.length(6); - expect(cursor).property('closed').to.be.true; - const clonedCursor = cursor.clone(); - this.defer(() => clonedCursor.close()); + const docsFromOriginal = await cursor.toArray(); + expect(docsFromOriginal).to.have.length(6); + expect(cursor).property('closed').to.be.true; - clonedCursor.toArray((err, docs) => { - expect(err).to.not.exist; - expect(docs).to.have.length(6); - expect(clonedCursor).property('closed').to.be.true; - done(); - }); - }); + const clonedCursor = cursor.clone(); + const docsFromCloned = await clonedCursor.toArray(); + expect(docsFromCloned).to.have.length(6); + expect(cursor).property('closed').to.be.true; }); }); diff --git a/test/integration/crud/insert.test.js b/test/integration/crud/insert.test.js index 4602a0af4e..99cc5bb3c9 100644 --- a/test/integration/crud/insert.test.js +++ b/test/integration/crud/insert.test.js @@ -17,7 +17,8 @@ const { MaxKey, Code, MongoBulkWriteError, - ReturnDocument + ReturnDocument, + MongoInvalidArgumentError } = require('../../mongodb'); /** @@ -91,25 +92,14 @@ describe('crud - insert', function () { }); }); - it('Should correctly return failing Promise when no document array passed into insertMany', function (done) { - const configuration = this.configuration; - let url = configuration.url(); - url = - url.indexOf('?') !== -1 - ? f('%s&%s', url, 'maxPoolSize=100') - : f('%s?%s', url, 'maxPoolSize=100'); - - const client = configuration.newClient(url); - client.connect().then(() => { - this.defer(() => client.close()); - - const db = client.db(configuration.db); - expect(() => { - db.collection('insertMany_Promise_error').insertMany({ a: 1 }); - }).to.throw(/Argument "docs" must be an array of documents/); - - done(); - }); + it('rejects when insertMany is passed a non array object', async function () { + const db = client.db(); + const error = await db + .collection('insertMany_Promise_error') + .insertMany({ a: 1 }) + .catch(error => error); + expect(error).to.be.instanceOf(MongoInvalidArgumentError); + expect(error.message).to.match(/must be an array/); }); describe('collection.insert()', function () { diff --git a/test/integration/crud/misc_cursors.test.js b/test/integration/crud/misc_cursors.test.js index 463be72d11..e0cc7a77d5 100644 --- a/test/integration/crud/misc_cursors.test.js +++ b/test/integration/crud/misc_cursors.test.js @@ -1671,64 +1671,26 @@ describe('Cursor', function () { } }); - it('removes session wheen cloning a find cursor', function (done) { - const configuration = this.configuration; - client.connect((err, client) => { - expect(err).to.not.exist; - - const db = client.db(configuration.db); - db.createCollection('clone_find_cursor_session', (err, collection) => { - expect(err).to.not.exist; + it('removes session when cloning an find cursor', async function () { + const collection = await client.db().collection('test'); - collection.insertOne({ a: 1 }, configuration.writeConcernMax(), err => { - expect(err).to.not.exist; + const cursor = collection.find({}); + const clonedCursor = cursor.clone(); - const cursor = collection.find(); - const clonedCursor = cursor.clone(); - cursor.toArray(err => { - expect(err).to.not.exist; - clonedCursor.toArray(err => { - expect(err).to.not.exist; - client.close(); - done(); - }); - }); - }); - }); - }); + expect(cursor).to.have.property('session'); + expect(clonedCursor).to.have.property('session'); + expect(cursor.session).to.not.equal(clonedCursor.session); }); - it('removes session wheen cloning an aggregation cursor', { - metadata: { - requires: { topology: ['single', 'replicaset', 'sharded'] } - }, - - test: function (done) { - const configuration = this.configuration; - client.connect((err, client) => { - expect(err).to.not.exist; - - const db = client.db(configuration.db); - db.createCollection('clone_aggregation_cursor_session', (err, collection) => { - expect(err).to.not.exist; + it('removes session when cloning an aggregation cursor', async function () { + const collection = await client.db().collection('test'); - collection.insertOne({ a: 1 }, configuration.writeConcernMax(), err => { - expect(err).to.not.exist; + const cursor = collection.aggregate([{ $match: {} }]); + const clonedCursor = cursor.clone(); - const cursor = collection.aggregate([{ $match: { a: 1 } }]); - const clonedCursor = cursor.clone(); - cursor.toArray(err => { - expect(err).to.not.exist; - clonedCursor.toArray(err => { - expect(err).to.not.exist; - client.close(); - done(); - }); - }); - }); - }); - }); - } + expect(cursor).to.have.property('session'); + expect(clonedCursor).to.have.property('session'); + expect(cursor.session).to.not.equal(clonedCursor.session); }); it('destroying a stream stops it', { diff --git a/test/integration/node-specific/operation_examples.test.ts b/test/integration/node-specific/operation_examples.test.ts index eb092ce853..b0de3fc127 100644 --- a/test/integration/node-specific/operation_examples.test.ts +++ b/test/integration/node-specific/operation_examples.test.ts @@ -1,13 +1,13 @@ import { expect } from 'chai'; import { format as f } from 'util'; -import { Code, enumToString, ProfilingLevel, ReturnDocument } from '../../mongodb'; +import { Code, enumToString, MongoClient, ProfilingLevel, ReturnDocument } from '../../mongodb'; import { skipBrokenAuthTestBeforeEachHook } from '../../tools/runner/hooks/configuration'; import { sleep as delay } from '../../tools/utils'; import { setupDatabase } from '../shared'; describe('Operations', function () { - let client; + let client: MongoClient; beforeEach(async function () { client = this.configuration.newClient(); }); @@ -1572,47 +1572,17 @@ describe('Operations', function () { * example-class Collection * example-method remove */ - it('shouldRemoveAllDocumentsNoSafeWithPromises', { - metadata: { requires: { topology: ['single'] } }, - - test: function () { - const configuration = this.configuration; - const client = configuration.newClient({ maxPoolSize: 1 }); - - return client.connect().then(function (client) { - const db = client.db(configuration.db); - // LINE var MongoClient = require('mongodb').MongoClient, - // LINE test = require('assert'); - // LINE const client = new MongoClient('mongodb://localhost:27017/test'); - // LINE client.connect().then(() => { - // LINE var db = client.db('test); - // REPLACE configuration.writeConcernMax() WITH {w:1} - // REMOVE-LINE done(); - // BEGIN - - // Fetch a collection to insert document into - const collection = db.collection('remove_all_documents_no_safe_with_promise'); - - // Insert a bunch of documents - return collection - .insertMany([{ a: 1 }, { b: 2 }], { writeConcern: { w: 1 } }) - .then(function (result) { - expect(result).to.exist; - - // Remove all the document - return collection.deleteMany(); - }) - .then(function () { - // Fetch all results - return collection.find().toArray(); - }) - .then(function (items) { - expect(items.length).to.equal(0); - return client.close(); - }); - }); - // END - } + it('deleteMany() deletes all documents in collection', async function () { + const db = client.db(); + // Fetch a collection to insert document into + const collection = db.collection('remove_all_documents_no_safe_with_promise'); + + // Insert a bunch of documents + const result = await collection.insertMany([{ a: 1 }, { b: 2 }], { writeConcern: { w: 1 } }); + expect(result).to.exist; + await collection.deleteMany(); + const items = await collection.find().toArray(); + expect(items).to.have.lengthOf(0); }); /** diff --git a/test/integration/transactions/transactions.test.ts b/test/integration/transactions/transactions.test.ts index a10312f1e5..2ee418dec1 100644 --- a/test/integration/transactions/transactions.test.ts +++ b/test/integration/transactions/transactions.test.ts @@ -4,6 +4,7 @@ import { ClientSession, Collection, MongoClient, + MongoInvalidArgumentError, MongoNetworkError, ServerSessionPool } from '../../mongodb'; @@ -24,23 +25,31 @@ describe('Transactions', function () { await client.close(); }); - it('should provide a useful error if a Promise is not returned', { - metadata: { - requires: { topology: ['replicaset', 'sharded'], mongodb: '>=4.1.5', serverless: 'forbid' } + it( + 'should provide a useful error if a Promise is not returned', + { + requires: { + topology: ['replicaset', 'sharded'], + mongodb: '>=4.1.5', + serverless: 'forbid' + } }, - test: function (done) { - function fnThatDoesntReturnPromise() { + async function () { + function fnThatDoesNotReturnPromise() { return false; } - // @ts-expect-error: Testing that a non promise returning function is handled correctly - expect(() => session.withTransaction(fnThatDoesntReturnPromise)).to.throw( - /must return a Promise/ - ); + const result = await session + // @ts-expect-error: testing a function that does not return a promise + .withTransaction(fnThatDoesNotReturnPromise) + .catch(error => error); - session.endSession(done); + expect(result).to.be.instanceOf(MongoInvalidArgumentError); + expect(result.message).to.match(/must return a Promise/); + + await session.endSession(); } - }); + ); it('should return readable error if promise rejected with no reason', { metadata: { diff --git a/test/types/community/bulk/bulk-operation-base.test-d.ts b/test/types/community/bulk/bulk-operation-base.test-d.ts index 29564ff393..cc2e5ecb59 100644 --- a/test/types/community/bulk/bulk-operation-base.test-d.ts +++ b/test/types/community/bulk/bulk-operation-base.test-d.ts @@ -1,13 +1,11 @@ import { expectType } from 'tsd'; import { - AnyError, Batch, BatchType, BulkOperationBase, BulkWriteOptions, BulkWriteResult, - Callback, DeleteStatement, Document, MongoClient, @@ -51,32 +49,3 @@ function extendedPromiseBasedBulkExecute( } expectType>(extendedPromiseBasedBulkExecute()); - -expectType( - bulkOperation.execute((error, bulkWriteResult) => { - expectType(error); - expectType(bulkWriteResult); - }) -); - -expectType( - bulkOperation.execute(options, (error, bulkWriteResult) => { - expectType(error); - expectType(bulkWriteResult); - }) -); - -// ensure we can use the bulk operation execute in a callback based wrapper function -function extendedCallbackBasedBulkExecute( - callback: Callback, - optionalOptions?: BulkWriteOptions -): void { - bulkOperation.execute(optionalOptions, callback); -} - -expectType( - extendedCallbackBasedBulkExecute((error, bulkWriteResult) => { - expectType(error); - expectType(bulkWriteResult); - }) -); diff --git a/test/types/community/client.test-d.ts b/test/types/community/client.test-d.ts index 613bf6095d..54aaf0f22c 100644 --- a/test/types/community/client.test-d.ts +++ b/test/types/community/client.test-d.ts @@ -4,7 +4,6 @@ import { GridFSBucket, MongoClient, MongoClientOptions, - MongoError, MongoNetworkError, MongoParseError, ReadPreference, @@ -37,25 +36,11 @@ const options: MongoClientOptions = { directConnection: false }; -MongoClient.connect(connectionString, options, (err, client?: MongoClient) => { - if (err || !client) throw err; - const db = client.db('test'); - db.collection('test_crud'); - // Let's close the db - client.close(); -}); - export async function testFunc(): Promise { const testClient: MongoClient = await MongoClient.connect(connectionString); return testClient; } -MongoClient.connect(connectionString, err => { - if (err instanceof MongoError) { - expectType(err.hasErrorLabel('label')); - } -}); - expectType>(MongoClient.connect(connectionString, options)); // TLS @@ -82,16 +67,6 @@ export function gridTest(bucket: GridFSBucket): void { openUploadStream.on('close', () => {}); openUploadStream.on('end', () => {}); expectType>(openUploadStream.abort()); // $ExpectType void - expectType( - openUploadStream.abort(() => { - openUploadStream.removeAllListeners(); - }) - ); - openUploadStream.abort(error => { - error; // $ExpectType MongoError - }); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - openUploadStream.abort((error, result) => {}); } // Client-Side Field Level Encryption diff --git a/test/types/community/collection/distinct.test-d.ts b/test/types/community/collection/distinct.test-d.ts index 5bc87e0131..8d0ffac48b 100644 --- a/test/types/community/collection/distinct.test-d.ts +++ b/test/types/community/collection/distinct.test-d.ts @@ -18,32 +18,10 @@ expectType(await collection.distinct('test')); expectType(await collection.distinct('test', { foo: 1 })); expectType(await collection.distinct('test', { foo: 1 }, { maxTimeMS: 400 })); -collection.distinct('_id', (err, fields) => { - // callbacks always have the second argument undefined - // incase of error - expectType(fields); -}); -collection.distinct('_id', { foo: 1 }, (err, fields) => { - expectType(fields); -}); -collection.distinct('_id', { foo: 1 }, { maxTimeMS: 400 }, (err, fields) => { - expectType(fields); -}); - expectType(await collection.distinct('_id')); expectType(await collection.distinct('_id', { foo: 1 })); expectType(await collection.distinct('_id', { foo: 1 }, { maxTimeMS: 400 })); -collection.distinct('nested.num', (err, fields) => { - expectType(fields); -}); -collection.distinct('nested.num', { foo: 1 }, (err, fields) => { - expectType(fields); -}); -collection.distinct('nested.num', { foo: 1 }, { maxTimeMS: 400 }, (err, fields) => { - expectType(fields); -}); - expectType(await collection.distinct('nested.num')); expectType(await collection.distinct('nested.num', { foo: 1 })); expectType(await collection.distinct('nested.num', { foo: 1 }, { maxTimeMS: 400 })); diff --git a/test/types/community/collection/findX.test-d.ts b/test/types/community/collection/findX.test-d.ts index e0ccd4eb92..216239be9f 100644 --- a/test/types/community/collection/findX.test-d.ts +++ b/test/types/community/collection/findX.test-d.ts @@ -4,7 +4,6 @@ import type { Filter } from '../../../../src'; import { Collection, Db, - Document, FindCursor, FindOptions, MongoClient, @@ -19,13 +18,9 @@ const db = client.db('test'); const collection = db.collection('test.find'); // Locate all the entries using find -collection.find({}).toArray((_err, fields) => { - expectType[] | undefined>(fields); - if (fields) { - expectType(fields[0]._id); - expectNotType(fields[0]._id); - } -}); +const fields = await collection.find({}).toArray(); +expectType(fields[0]._id); +expectNotType(fields[0]._id); // test with collection type interface TestModel { @@ -86,21 +81,6 @@ interface Bag { const collectionBag = db.collection('bag'); -const cursor: FindCursor> = collectionBag.find({ color: 'black' }); - -cursor.toArray((_err, bags) => { - expectType[] | undefined>(bags); -}); - -cursor.forEach( - bag => { - expectType>(bag); - }, - () => { - return null; - } -); - expectType | null>( await collectionBag.findOne({ color: 'red' }, { projection: { cost: 1 } }) ); @@ -253,14 +233,6 @@ const typedDb = client.db('test2') as TypedDb; const person = typedDb.collection('people').findOne({}); expectType | null>>(person); -typedDb.collection('people').findOne({}, function (_err, person) { - expectType | null | undefined>(person); // null is if nothing is found, undefined is when there is an error defined -}); - -typedDb.collection('things').findOne({}, function (_err, thing) { - expectType | null | undefined>(thing); -}); - interface SchemaWithTypicalId { _id: ObjectId; name: string; diff --git a/test/types/community/db/createCollection.test-d.ts b/test/types/community/db/createCollection.test-d.ts index 9e932fd5cb..0830804bb9 100644 --- a/test/types/community/db/createCollection.test-d.ts +++ b/test/types/community/db/createCollection.test-d.ts @@ -1,13 +1,6 @@ import { expectType } from 'tsd'; -import { - AnyError, - Callback, - Collection, - CreateCollectionOptions, - MongoClient, - ObjectId -} from '../../../mongodb'; +import { Collection, CreateCollectionOptions, MongoClient, ObjectId } from '../../../mongodb'; const client = new MongoClient(''); const db = client.db('test'); @@ -50,33 +43,3 @@ function extendedPromiseBasedCreateCollection( } expectType>>(extendedPromiseBasedCreateCollection('test')); - -expectType( - db.createCollection('test', (err, collection) => { - expectType(err); - expectType | undefined>(collection); - }) -); - -expectType( - db.createCollection('test', options, (err, collection) => { - expectType(err); - expectType | undefined>(collection); - }) -); - -// ensure we can use the create collection in a callback based wrapper function -function extendedCallbackBasedCreateCollection( - name: string, - callback: Callback>, - optionalOptions?: CreateCollectionOptions -): void { - db.createCollection(name, optionalOptions, callback); -} - -expectType( - extendedCallbackBasedCreateCollection('test', (err, collection) => { - expectType(err); - expectType | undefined>(collection); - }) -); diff --git a/test/types/indexes_test-d.ts b/test/types/indexes_test-d.ts index 430559a5fc..34ae9d4a18 100644 --- a/test/types/indexes_test-d.ts +++ b/test/types/indexes_test-d.ts @@ -1,6 +1,6 @@ import { expectType } from 'tsd'; -import { AnyError, Document, MongoClient } from '../../src'; +import { Document, MongoClient } from '../../src'; const client = new MongoClient(''); const db = client.db('test'); @@ -14,14 +14,3 @@ expectType>(collection.indexes({})); for (const index of await collection.indexes()) { expectType(index); } - -// Callback variant testing -collection.indexes((err, indexes) => { - expectType(err); - expectType(indexes); -}); - -collection.indexes({}, (err, indexes) => { - expectType(err); - expectType(indexes); -});