diff --git a/src/index.ts b/src/index.ts index 8106b6cdc1..e02dbf3753 100644 --- a/src/index.ts +++ b/src/index.ts @@ -511,7 +511,6 @@ export type { CollationOptions, CommandOperation, CommandOperationOptions, - ModernizedCommandOperation, OperationParent } from './operations/command'; export type { CountOptions } from './operations/count'; @@ -544,12 +543,7 @@ export type { export type { InsertManyResult, InsertOneOptions, InsertOneResult } from './operations/insert'; export type { CollectionInfo, ListCollectionsOptions } from './operations/list_collections'; export type { ListDatabasesOptions, ListDatabasesResult } from './operations/list_databases'; -export type { - AbstractOperation, - Hint, - ModernizedOperation, - OperationOptions -} from './operations/operation'; +export type { AbstractOperation, Hint, OperationOptions } from './operations/operation'; export type { ProfilingLevelOptions } from './operations/profiling_level'; export type { RemoveUserOptions } from './operations/remove_user'; export type { RenameOptions } from './operations/rename'; diff --git a/src/mongo_client.ts b/src/mongo_client.ts index 54562147f0..1ff310822d 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -44,7 +44,7 @@ import { } from './operations/client_bulk_write/common'; import { ClientBulkWriteExecutor } from './operations/client_bulk_write/executor'; import { executeOperation } from './operations/execute_operation'; -import { ModernizedOperation } from './operations/operation'; +import { AbstractOperation } from './operations/operation'; import type { ReadConcern, ReadConcernLevel, ReadConcernLike } from './read_concern'; import { ReadPreference, type ReadPreferenceMode } from './read_preference'; import { type AsyncDisposable, configureResourceManagement } from './resource_management'; @@ -792,7 +792,7 @@ export class MongoClient extends TypedEventEmitter implements const endSessions = Array.from(this.s.sessionPool.sessions, ({ id }) => id); if (endSessions.length !== 0) { try { - class EndSessionsOperation extends ModernizedOperation { + class EndSessionsOperation extends AbstractOperation { override ns = MongoDBNamespace.fromString('admin.$cmd'); override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override buildCommand(_connection: Connection, _session?: ClientSession): Document { diff --git a/src/operations/aggregate.ts b/src/operations/aggregate.ts index ce78641dec..3d5731d4c5 100644 --- a/src/operations/aggregate.ts +++ b/src/operations/aggregate.ts @@ -6,11 +6,7 @@ import { MongoInvalidArgumentError } from '../error'; import { type ExplainOptions } from '../explain'; import { maxWireVersion, type MongoDBNamespace } from '../utils'; import { WriteConcern } from '../write_concern'; -import { - type CollationOptions, - type CommandOperationOptions, - ModernizedCommandOperation -} from './command'; +import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects, type Hint } from './operation'; /** @internal */ @@ -53,7 +49,7 @@ export interface AggregateOptions extends Omit { +export class AggregateOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse; override options: AggregateOptions; target: string | typeof DB_AGGREGATE_COLLECTION; diff --git a/src/operations/client_bulk_write/client_bulk_write.ts b/src/operations/client_bulk_write/client_bulk_write.ts index cbfc04b0ba..6f9af73534 100644 --- a/src/operations/client_bulk_write/client_bulk_write.ts +++ b/src/operations/client_bulk_write/client_bulk_write.ts @@ -2,7 +2,7 @@ import { type Connection } from '../../cmap/connection'; import { ClientBulkWriteCursorResponse } from '../../cmap/wire_protocol/responses'; import type { ClientSession } from '../../sessions'; import { MongoDBNamespace } from '../../utils'; -import { ModernizedCommandOperation } from '../command'; +import { CommandOperation } from '../command'; import { Aspect, defineAspects } from '../operation'; import { type ClientBulkWriteCommand, type ClientBulkWriteCommandBuilder } from './command_builder'; import { type ClientBulkWriteOptions } from './common'; @@ -11,7 +11,7 @@ import { type ClientBulkWriteOptions } from './common'; * Executes a single client bulk write operation within a potential batch. * @internal */ -export class ClientBulkWriteOperation extends ModernizedCommandOperation { +export class ClientBulkWriteOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = ClientBulkWriteCursorResponse; commandBuilder: ClientBulkWriteCommandBuilder; diff --git a/src/operations/command.ts b/src/operations/command.ts index 223a5a57fc..a4a2d1fbf9 100644 --- a/src/operations/command.ts +++ b/src/operations/command.ts @@ -1,6 +1,5 @@ import { type Connection } from '..'; import type { BSONSerializeOptions, Document } from '../bson'; -import { type MongoDBResponseConstructor } from '../cmap/wire_protocol/responses'; import { MongoInvalidArgumentError } from '../error'; import { decorateWithExplain, @@ -10,13 +9,13 @@ import { } from '../explain'; import { ReadConcern } from '../read_concern'; import type { ReadPreference } from '../read_preference'; -import type { Server, ServerCommandOptions } from '../sdam/server'; +import type { ServerCommandOptions } from '../sdam/server'; import type { ClientSession } from '../sessions'; import { type TimeoutContext } from '../timeout'; import { commandSupportsReadConcern, MongoDBNamespace } from '../utils'; import { WriteConcern, type WriteConcernOptions } from '../write_concern'; import type { ReadConcernLike } from './../read_concern'; -import { AbstractOperation, Aspect, ModernizedOperation, type OperationOptions } from './operation'; +import { AbstractOperation, Aspect, type OperationOptions } from './operation'; /** @public */ export interface CollationOptions { @@ -117,109 +116,6 @@ export abstract class CommandOperation extends AbstractOperation { return super.canRetryWrite; } - public async executeCommand( - server: Server, - session: ClientSession | undefined, - cmd: Document, - timeoutContext: TimeoutContext, - responseType: T | undefined - ): Promise>; - - public async executeCommand( - server: Server, - session: ClientSession | undefined, - cmd: Document, - timeoutContext: TimeoutContext - ): Promise; - - async executeCommand( - server: Server, - session: ClientSession | undefined, - cmd: Document, - timeoutContext: TimeoutContext, - responseType?: MongoDBResponseConstructor - ): Promise { - this.server = server; - - const options = { - ...this.options, - ...this.bsonOptions, - timeoutContext, - readPreference: this.readPreference, - session - }; - - const inTransaction = this.session && this.session.inTransaction(); - - if (this.readConcern && commandSupportsReadConcern(cmd) && !inTransaction) { - Object.assign(cmd, { readConcern: this.readConcern }); - } - - if (this.writeConcern && this.hasAspect(Aspect.WRITE_OPERATION) && !inTransaction) { - WriteConcern.apply(cmd, this.writeConcern); - } - - if ( - options.collation && - typeof options.collation === 'object' && - !this.hasAspect(Aspect.SKIP_COLLATION) - ) { - Object.assign(cmd, { collation: options.collation }); - } - - if (typeof options.maxTimeMS === 'number') { - cmd.maxTimeMS = options.maxTimeMS; - } - - if (this.hasAspect(Aspect.EXPLAINABLE) && this.explain) { - cmd = decorateWithExplain(cmd, this.explain); - } - - return await server.command(this.ns, cmd, options, responseType); - } -} - -/** @internal */ -export abstract class ModernizedCommandOperation extends ModernizedOperation { - override options: CommandOperationOptions; - readConcern?: ReadConcern; - writeConcern?: WriteConcern; - explain?: Explain; - - constructor(parent?: OperationParent, options?: CommandOperationOptions) { - super(options); - this.options = options ?? {}; - - // NOTE: this was explicitly added for the add/remove user operations, it's likely - // something we'd want to reconsider. Perhaps those commands can use `Admin` - // as a parent? - const dbNameOverride = options?.dbName || options?.authdb; - if (dbNameOverride) { - this.ns = new MongoDBNamespace(dbNameOverride, '$cmd'); - } else { - this.ns = parent - ? parent.s.namespace.withCollection('$cmd') - : new MongoDBNamespace('admin', '$cmd'); - } - - this.readConcern = ReadConcern.fromOptions(options); - this.writeConcern = WriteConcern.fromOptions(options); - - if (this.hasAspect(Aspect.EXPLAINABLE)) { - this.explain = Explain.fromOptions(options); - if (this.explain) validateExplainTimeoutOptions(this.options, this.explain); - } else if (options?.explain != null) { - throw new MongoInvalidArgumentError(`Option "explain" is not supported on this command`); - } - } - - override get canRetryWrite(): boolean { - if (this.hasAspect(Aspect.EXPLAINABLE)) { - return this.explain == null; - } - return super.canRetryWrite; - } - abstract buildCommandDocument(connection: Connection, session?: ClientSession): Document; override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions { diff --git a/src/operations/count.ts b/src/operations/count.ts index 1bf0396dab..08b4c9c66a 100644 --- a/src/operations/count.ts +++ b/src/operations/count.ts @@ -4,7 +4,7 @@ import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import type { Collection } from '../collection'; import type { ClientSession } from '../sessions'; import type { MongoDBNamespace } from '../utils'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; /** @public */ @@ -22,7 +22,7 @@ export interface CountOptions extends CommandOperationOptions { } /** @internal */ -export class CountOperation extends ModernizedCommandOperation { +export class CountOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: CountOptions; collectionName?: string; diff --git a/src/operations/create_collection.ts b/src/operations/create_collection.ts index 955058ad4f..8c35dfedcc 100644 --- a/src/operations/create_collection.ts +++ b/src/operations/create_collection.ts @@ -12,7 +12,7 @@ import type { PkFactory } from '../mongo_client'; import type { ClientSession } from '../sessions'; import { TimeoutContext } from '../timeout'; import { maxWireVersion } from '../utils'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { executeOperation } from './execute_operation'; import { CreateIndexesOperation } from './indexes'; import { Aspect, defineAspects } from './operation'; @@ -112,7 +112,7 @@ const INVALID_QE_VERSION = 'Driver support of Queryable Encryption is incompatible with server. Upgrade server to use Queryable Encryption.'; /** @internal */ -export class CreateCollectionOperation extends ModernizedCommandOperation { +export class CreateCollectionOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: CreateCollectionOptions; db: Db; diff --git a/src/operations/delete.ts b/src/operations/delete.ts index aff4130e8b..9f97f487be 100644 --- a/src/operations/delete.ts +++ b/src/operations/delete.ts @@ -5,11 +5,7 @@ import { MongoCompatibilityError, MongoServerError } from '../error'; import type { ClientSession } from '../sessions'; import { type MongoDBCollectionNamespace, type MongoDBNamespace } from '../utils'; import { type WriteConcernOptions } from '../write_concern'; -import { - type CollationOptions, - type CommandOperationOptions, - ModernizedCommandOperation -} from './command'; +import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects, type Hint } from './operation'; /** @public */ @@ -45,7 +41,7 @@ export interface DeleteStatement { } /** @internal */ -export class DeleteOperation extends ModernizedCommandOperation { +export class DeleteOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: DeleteOptions; statements: DeleteStatement[]; diff --git a/src/operations/distinct.ts b/src/operations/distinct.ts index ff8ee796ec..1236fcf17a 100644 --- a/src/operations/distinct.ts +++ b/src/operations/distinct.ts @@ -2,7 +2,7 @@ import { type Document } from '../bson'; import { type Connection } from '../cmap/connection'; import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import type { Collection } from '../collection'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; /** @public */ @@ -25,7 +25,7 @@ export type DistinctOptions = CommandOperationOptions & { * Return a list of distinct values for the given key across a collection. * @internal */ -export class DistinctOperation extends ModernizedCommandOperation { +export class DistinctOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: DistinctOptions; collection: Collection; diff --git a/src/operations/drop.ts b/src/operations/drop.ts index c46e1444fc..afb7c5ff06 100644 --- a/src/operations/drop.ts +++ b/src/operations/drop.ts @@ -6,7 +6,7 @@ import type { Db } from '../db'; import { MONGODB_ERROR_CODES } from '../error'; import type { ClientSession } from '../sessions'; import { TimeoutContext } from '../timeout'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { executeOperation } from './execute_operation'; import { Aspect, defineAspects } from './operation'; @@ -17,7 +17,7 @@ export interface DropCollectionOptions extends CommandOperationOptions { } /** @internal */ -export class DropCollectionOperation extends ModernizedCommandOperation { +export class DropCollectionOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: DropCollectionOptions; @@ -107,7 +107,7 @@ export async function dropCollections( export type DropDatabaseOptions = CommandOperationOptions; /** @internal */ -export class DropDatabaseOperation extends ModernizedCommandOperation { +export class DropDatabaseOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: DropDatabaseOptions; diff --git a/src/operations/estimated_document_count.ts b/src/operations/estimated_document_count.ts index 47e6d39c16..b32ab76f2d 100644 --- a/src/operations/estimated_document_count.ts +++ b/src/operations/estimated_document_count.ts @@ -3,7 +3,7 @@ import type { Document } from '../bson'; import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import type { Collection } from '../collection'; import type { ClientSession } from '../sessions'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; /** @public */ @@ -17,7 +17,7 @@ export interface EstimatedDocumentCountOptions extends CommandOperationOptions { } /** @internal */ -export class EstimatedDocumentCountOperation extends ModernizedCommandOperation { +export class EstimatedDocumentCountOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: EstimatedDocumentCountOptions; collectionName: string; diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index 51a276995f..61d943e642 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -27,18 +27,15 @@ import type { ClientSession } from '../sessions'; import { TimeoutContext } from '../timeout'; import { abortable, supportsRetryableWrites } from '../utils'; import { AggregateOperation } from './aggregate'; -import { AbstractOperation, Aspect, ModernizedOperation } from './operation'; +import { AbstractOperation, Aspect } from './operation'; const MMAPv1_RETRY_WRITES_ERROR_CODE = MONGODB_ERROR_CODES.IllegalOperation; const MMAPv1_RETRY_WRITES_ERROR_MESSAGE = 'This MongoDB deployment does not support retryable writes. Please add retryWrites=false to your connection string.'; -type ResultTypeFromOperation = - TOperation extends ModernizedOperation - ? ReturnType - : TOperation extends AbstractOperation - ? K - : never; +type ResultTypeFromOperation = ReturnType< + TOperation['handleOk'] +>; /** * Executes the given operation with provided arguments. @@ -235,8 +232,6 @@ async function tryOperation { +export class FindOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse; /** diff --git a/src/operations/find_and_modify.ts b/src/operations/find_and_modify.ts index aaa07b136a..b8c573e3ad 100644 --- a/src/operations/find_and_modify.ts +++ b/src/operations/find_and_modify.ts @@ -8,7 +8,7 @@ import type { ClientSession } from '../sessions'; import { formatSort, type Sort, type SortForCmd } from '../sort'; import { decorateWithCollation, hasAtomicOperators } from '../utils'; import { type WriteConcern, type WriteConcernSettings } from '../write_concern'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; /** @public */ @@ -120,7 +120,7 @@ function configureFindAndModifyCmdBaseUpdateOpts( } /** @internal */ -export class FindAndModifyOperation extends ModernizedCommandOperation { +export class FindAndModifyOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: FindOneAndReplaceOptions | FindOneAndUpdateOptions | FindOneAndDeleteOptions; collection: Collection; diff --git a/src/operations/get_more.ts b/src/operations/get_more.ts index f9397f9a11..4e94020cd7 100644 --- a/src/operations/get_more.ts +++ b/src/operations/get_more.ts @@ -5,7 +5,7 @@ import { MongoRuntimeError } from '../error'; import type { Server, ServerCommandOptions } from '../sdam/server'; import { type TimeoutContext } from '../timeout'; import { maxWireVersion, type MongoDBNamespace } from '../utils'; -import { Aspect, defineAspects, ModernizedOperation, type OperationOptions } from './operation'; +import { AbstractOperation, Aspect, defineAspects, type OperationOptions } from './operation'; /** @internal */ export interface GetMoreOptions extends OperationOptions { @@ -37,7 +37,7 @@ export interface GetMoreCommand { } /** @internal */ -export class GetMoreOperation extends ModernizedOperation { +export class GetMoreOperation extends AbstractOperation { override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse; cursorId: Long; override options: GetMoreOptions; diff --git a/src/operations/indexes.ts b/src/operations/indexes.ts index 15252e53b7..ed761d2977 100644 --- a/src/operations/indexes.ts +++ b/src/operations/indexes.ts @@ -8,8 +8,8 @@ import { type OneOrMore } from '../mongo_types'; import { isObject, maxWireVersion, type MongoDBNamespace } from '../utils'; import { type CollationOptions, + CommandOperation, type CommandOperationOptions, - ModernizedCommandOperation, type OperationParent } from './command'; import { Aspect, defineAspects } from './operation'; @@ -242,7 +242,7 @@ type ResolvedIndexDescription = Omit & { }; /** @internal */ -export class CreateIndexesOperation extends ModernizedCommandOperation { +export class CreateIndexesOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: CreateIndexesOptions; collectionName: string; @@ -328,7 +328,7 @@ export class CreateIndexesOperation extends ModernizedCommandOperation export type DropIndexesOptions = CommandOperationOptions; /** @internal */ -export class DropIndexOperation extends ModernizedCommandOperation { +export class DropIndexOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: DropIndexesOptions; collection: Collection; @@ -359,7 +359,7 @@ export type ListIndexesOptions = AbstractCursorOptions & { }; /** @internal */ -export class ListIndexesOperation extends ModernizedCommandOperation { +export class ListIndexesOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse; /** * @remarks WriteConcern can still be present on the options because diff --git a/src/operations/insert.ts b/src/operations/insert.ts index b26a32466d..85269c8f92 100644 --- a/src/operations/insert.ts +++ b/src/operations/insert.ts @@ -7,10 +7,10 @@ import { MongoServerError } from '../error'; import type { InferIdType } from '../mongo_types'; import type { ClientSession } from '../sessions'; import { maybeAddIdToDocuments, type MongoDBNamespace } from '../utils'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; /** @internal */ -export class InsertOperation extends ModernizedCommandOperation { +export class InsertOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: BulkWriteOptions; diff --git a/src/operations/kill_cursors.ts b/src/operations/kill_cursors.ts index f5089dfbaa..87184e4da0 100644 --- a/src/operations/kill_cursors.ts +++ b/src/operations/kill_cursors.ts @@ -6,7 +6,7 @@ import type { Server, ServerCommandOptions } from '../sdam/server'; import type { ClientSession } from '../sessions'; import { type TimeoutContext } from '../timeout'; import { type MongoDBNamespace } from '../utils'; -import { Aspect, defineAspects, ModernizedOperation, type OperationOptions } from './operation'; +import { AbstractOperation, Aspect, defineAspects, type OperationOptions } from './operation'; /** * https://www.mongodb.com/docs/manual/reference/command/killCursors/ @@ -18,7 +18,7 @@ interface KillCursorsCommand { comment?: unknown; } -export class KillCursorsOperation extends ModernizedOperation { +export class KillCursorsOperation extends AbstractOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; cursorId: Long; diff --git a/src/operations/list_collections.ts b/src/operations/list_collections.ts index 869c15383c..a96266e413 100644 --- a/src/operations/list_collections.ts +++ b/src/operations/list_collections.ts @@ -5,7 +5,7 @@ import { type CursorTimeoutContext, type CursorTimeoutMode } from '../cursor/abs import type { Db } from '../db'; import { type Abortable } from '../mongo_types'; import { maxWireVersion } from '../utils'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; /** @public */ @@ -26,7 +26,7 @@ export interface ListCollectionsOptions } /** @internal */ -export class ListCollectionsOperation extends ModernizedCommandOperation { +export class ListCollectionsOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse; /** * @remarks WriteConcern can still be present on the options because diff --git a/src/operations/list_databases.ts b/src/operations/list_databases.ts index 2b7dcabf60..1dc72d54bf 100644 --- a/src/operations/list_databases.ts +++ b/src/operations/list_databases.ts @@ -4,7 +4,7 @@ import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import type { Db } from '../db'; import type { ClientSession } from '../sessions'; import { maxWireVersion, MongoDBNamespace } from '../utils'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; /** @public */ @@ -26,7 +26,7 @@ export interface ListDatabasesOptions extends CommandOperationOptions { } /** @internal */ -export class ListDatabasesOperation extends ModernizedCommandOperation { +export class ListDatabasesOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: ListDatabasesOptions; diff --git a/src/operations/operation.ts b/src/operations/operation.ts index 0804ec6486..0541175fea 100644 --- a/src/operations/operation.ts +++ b/src/operations/operation.ts @@ -87,12 +87,6 @@ export abstract class AbstractOperation { Command name should be stateless (should not use 'this' keyword) */ abstract get commandName(): string; - abstract execute( - server: Server, - session: ClientSession | undefined, - timeoutContext: TimeoutContext - ): Promise; - hasAspect(aspect: symbol): boolean { const ctor = this.constructor as { aspects?: Set }; if (ctor.aspects == null) { @@ -126,21 +120,8 @@ export abstract class AbstractOperation { get canRetryWrite(): boolean { return this.hasAspect(Aspect.RETRYABLE) && this.hasAspect(Aspect.WRITE_OPERATION); } -} - -/** @internal */ -export abstract class ModernizedOperation extends AbstractOperation { abstract SERVER_COMMAND_RESPONSE_TYPE: typeof MongoDBResponse; - /** this will never be used - but we must implement it to satisfy AbstractOperation's interface */ - override execute( - _server: Server, - _session: ClientSession | undefined, - _timeoutContext: TimeoutContext - ): Promise { - throw new Error('cannot execute!!'); - } - /** * Build a raw command document. */ diff --git a/src/operations/profiling_level.ts b/src/operations/profiling_level.ts index 90b310b8af..d3493fe575 100644 --- a/src/operations/profiling_level.ts +++ b/src/operations/profiling_level.ts @@ -3,7 +3,7 @@ import { type Connection } from '../cmap/connection'; import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import type { Db } from '../db'; import { MongoUnexpectedServerResponseError } from '../error'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; /** @public */ export type ProfilingLevelOptions = CommandOperationOptions; @@ -15,7 +15,7 @@ class ProfilingLevelResponse extends MongoDBResponse { } /** @internal */ -export class ProfilingLevelOperation extends ModernizedCommandOperation { +export class ProfilingLevelOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = ProfilingLevelResponse; override options: ProfilingLevelOptions; diff --git a/src/operations/remove_user.ts b/src/operations/remove_user.ts index e0c73d29aa..7b06b1b8cb 100644 --- a/src/operations/remove_user.ts +++ b/src/operations/remove_user.ts @@ -2,14 +2,14 @@ import { type Document } from '../bson'; import { type Connection } from '../cmap/connection'; import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import type { Db } from '../db'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; /** @public */ export type RemoveUserOptions = CommandOperationOptions; /** @internal */ -export class RemoveUserOperation extends ModernizedCommandOperation { +export class RemoveUserOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: RemoveUserOptions; username: string; diff --git a/src/operations/rename.ts b/src/operations/rename.ts index 64c751f426..0ba34c2baf 100644 --- a/src/operations/rename.ts +++ b/src/operations/rename.ts @@ -4,7 +4,7 @@ import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import { Collection } from '../collection'; import type { ClientSession } from '../sessions'; import { MongoDBNamespace } from '../utils'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; /** @public */ @@ -16,7 +16,7 @@ export interface RenameOptions extends CommandOperationOptions { } /** @internal */ -export class RenameOperation extends ModernizedCommandOperation { +export class RenameOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; collection: Collection; newName: string; diff --git a/src/operations/run_command.ts b/src/operations/run_command.ts index fd40bc3062..9f3e505f7e 100644 --- a/src/operations/run_command.ts +++ b/src/operations/run_command.ts @@ -2,7 +2,7 @@ import { type Abortable } from '..'; import type { BSONSerializeOptions, Document } from '../bson'; import { type Connection } from '../cmap/connection'; import { CursorResponse, MongoDBResponse } from '../cmap/wire_protocol/responses'; -import { ModernizedOperation } from '../operations/operation'; +import { AbstractOperation } from '../operations/operation'; import type { ReadPreferenceLike } from '../read_preference'; import type { ServerCommandOptions } from '../sdam/server'; import type { ClientSession } from '../sessions'; @@ -32,7 +32,7 @@ export type RunCommandOptions = { Abortable; /** @internal */ -export class RunCommandOperation extends ModernizedOperation { +export class RunCommandOperation extends AbstractOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; command: Document; override options: RunCommandOptions; diff --git a/src/operations/search_indexes/create.ts b/src/operations/search_indexes/create.ts index 4fde15b8ff..6d91ec3f35 100644 --- a/src/operations/search_indexes/create.ts +++ b/src/operations/search_indexes/create.ts @@ -5,7 +5,7 @@ import type { Collection } from '../../collection'; import type { ServerCommandOptions } from '../../sdam/server'; import type { ClientSession } from '../../sessions'; import { type TimeoutContext } from '../../timeout'; -import { ModernizedOperation } from '../operation'; +import { AbstractOperation } from '../operation'; /** * @public @@ -22,7 +22,7 @@ export interface SearchIndexDescription extends Document { } /** @internal */ -export class CreateSearchIndexesOperation extends ModernizedOperation { +export class CreateSearchIndexesOperation extends AbstractOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; private readonly collection: Collection; private readonly descriptions: ReadonlyArray; diff --git a/src/operations/search_indexes/drop.ts b/src/operations/search_indexes/drop.ts index acbe3de9c6..e9132a7a74 100644 --- a/src/operations/search_indexes/drop.ts +++ b/src/operations/search_indexes/drop.ts @@ -6,10 +6,10 @@ import { MONGODB_ERROR_CODES, MongoServerError } from '../../error'; import type { ServerCommandOptions } from '../../sdam/server'; import type { ClientSession } from '../../sessions'; import { type TimeoutContext } from '../../timeout'; -import { ModernizedOperation } from '../operation'; +import { AbstractOperation } from '../operation'; /** @internal */ -export class DropSearchIndexOperation extends ModernizedOperation { +export class DropSearchIndexOperation extends AbstractOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; private readonly collection: Collection; diff --git a/src/operations/search_indexes/update.ts b/src/operations/search_indexes/update.ts index b4d5738ffd..af9d881082 100644 --- a/src/operations/search_indexes/update.ts +++ b/src/operations/search_indexes/update.ts @@ -5,10 +5,10 @@ import type { Collection } from '../../collection'; import type { ServerCommandOptions } from '../../sdam/server'; import type { ClientSession } from '../../sessions'; import { type TimeoutContext } from '../../timeout'; -import { ModernizedOperation } from '../operation'; +import { AbstractOperation } from '../operation'; /** @internal */ -export class UpdateSearchIndexOperation extends ModernizedOperation { +export class UpdateSearchIndexOperation extends AbstractOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; private readonly collection: Collection; private readonly name: string; diff --git a/src/operations/set_profiling_level.ts b/src/operations/set_profiling_level.ts index e3460bbfce..3b9ead5c3a 100644 --- a/src/operations/set_profiling_level.ts +++ b/src/operations/set_profiling_level.ts @@ -4,7 +4,7 @@ import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import type { Db } from '../db'; import { MongoInvalidArgumentError } from '../error'; import { enumToString } from '../utils'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; const levelValues = new Set(['off', 'slow_only', 'all']); @@ -22,7 +22,7 @@ export type ProfilingLevel = (typeof ProfilingLevel)[keyof typeof ProfilingLevel export type SetProfilingLevelOptions = CommandOperationOptions; /** @internal */ -export class SetProfilingLevelOperation extends ModernizedCommandOperation { +export class SetProfilingLevelOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: SetProfilingLevelOptions; level: ProfilingLevel; diff --git a/src/operations/stats.ts b/src/operations/stats.ts index 399bb9c531..ede37c6339 100644 --- a/src/operations/stats.ts +++ b/src/operations/stats.ts @@ -2,7 +2,7 @@ import type { Document } from '../bson'; import { type Connection } from '../cmap/connection'; import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import type { Db } from '../db'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; /** @public */ @@ -12,7 +12,7 @@ export interface DbStatsOptions extends CommandOperationOptions { } /** @internal */ -export class DbStatsOperation extends ModernizedCommandOperation { +export class DbStatsOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: DbStatsOptions; diff --git a/src/operations/update.ts b/src/operations/update.ts index e7c9b7c3cf..089390fcf7 100644 --- a/src/operations/update.ts +++ b/src/operations/update.ts @@ -10,11 +10,7 @@ import { type MongoDBCollectionNamespace, type MongoDBNamespace } from '../utils'; -import { - type CollationOptions, - type CommandOperationOptions, - ModernizedCommandOperation -} from './command'; +import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects, type Hint } from './operation'; /** @public */ @@ -74,7 +70,7 @@ export interface UpdateStatement { * @internal * UpdateOperation is used in bulk write, while UpdateOneOperation and UpdateManyOperation are only used in the collections API */ -export class UpdateOperation extends ModernizedCommandOperation { +export class UpdateOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: UpdateOptions & { ordered?: boolean }; statements: UpdateStatement[]; diff --git a/src/operations/validate_collection.ts b/src/operations/validate_collection.ts index dd1bd6fecc..06977178e4 100644 --- a/src/operations/validate_collection.ts +++ b/src/operations/validate_collection.ts @@ -4,7 +4,7 @@ import { type Document } from '../bson'; import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import { MongoUnexpectedServerResponseError } from '../error'; import type { ClientSession } from '../sessions'; -import { type CommandOperationOptions, ModernizedCommandOperation } from './command'; +import { CommandOperation, type CommandOperationOptions } from './command'; /** @public */ export interface ValidateCollectionOptions extends CommandOperationOptions { @@ -13,7 +13,7 @@ export interface ValidateCollectionOptions extends CommandOperationOptions { } /** @internal */ -export class ValidateCollectionOperation extends ModernizedCommandOperation { +export class ValidateCollectionOperation extends CommandOperation { override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; override options: ValidateCollectionOptions; collectionName: string; diff --git a/src/sdam/server.ts b/src/sdam/server.ts index 9e7c20af84..8488344d5d 100644 --- a/src/sdam/server.ts +++ b/src/sdam/server.ts @@ -7,7 +7,6 @@ import { type ConnectionPoolOptions } from '../cmap/connection_pool'; import { PoolClearedError } from '../cmap/errors'; -import { type MongoDBResponseConstructor } from '../cmap/wire_protocol/responses'; import { APM_EVENTS, CLOSED, @@ -27,7 +26,6 @@ import { MONGODB_ERROR_CODES, MongoError, MongoErrorLabel, - MongoInvalidArgumentError, MongoNetworkError, MongoNetworkTimeoutError, MongoRuntimeError, @@ -39,7 +37,7 @@ import type { ServerApi } from '../mongo_client'; import { type Abortable, TypedEventEmitter } from '../mongo_types'; import { AggregateOperation } from '../operations/aggregate'; import type { GetMoreOptions } from '../operations/get_more'; -import { type ModernizedOperation } from '../operations/operation'; +import { type AbstractOperation } from '../operations/operation'; import type { ClientSession } from '../sessions'; import { type TimeoutContext } from '../timeout'; import { isTransactionCommand } from '../transactions'; @@ -48,7 +46,6 @@ import { type EventEmitterWithState, makeStateMachine, maxWireVersion, - type MongoDBNamespace, noop, squashError, supportsRetryableWrites @@ -281,8 +278,8 @@ export class Server extends TypedEventEmitter { } } - public async modernCommand( - operation: ModernizedOperation, + public async command( + operation: AbstractOperation, timeoutContext: TimeoutContext ): Promise> { if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) { @@ -295,7 +292,7 @@ export class Server extends TypedEventEmitter { this.incrementOperationCount(); if (conn == null) { try { - conn = await this.pool.checkOut({ timeoutContext }); + conn = await this.pool.checkOut({ timeoutContext, signal: operation.options.signal }); } catch (checkoutError) { this.decrementOperationCount(); if (!(checkoutError instanceof PoolClearedError)) this.handleError(checkoutError); @@ -385,106 +382,6 @@ export class Server extends TypedEventEmitter { } } - public async command( - ns: MongoDBNamespace, - command: Document, - options: ServerCommandOptions, - responseType: T | undefined - ): Promise>; - - public async command( - ns: MongoDBNamespace, - command: Document, - options: ServerCommandOptions - ): Promise; - - public async command( - ns: MongoDBNamespace, - cmd: Document, - { ...options }: ServerCommandOptions, - responseType?: MongoDBResponseConstructor - ): Promise { - if (ns.db == null || typeof ns === 'string') { - throw new MongoInvalidArgumentError('Namespace must not be a string'); - } - - if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) { - throw new MongoServerClosedError(); - } - - options.directConnection = this.topology.s.options.directConnection; - - if (this.description.iscryptd) { - options.omitMaxTimeMS = true; - } - - const session = options.session; - let conn = session?.pinnedConnection; - - this.incrementOperationCount(); - if (conn == null) { - try { - conn = await this.pool.checkOut(options); - if (this.loadBalanced && isPinnableCommand(cmd, session)) { - session?.pin(conn); - } - } catch (checkoutError) { - this.decrementOperationCount(); - if (!(checkoutError instanceof PoolClearedError)) this.handleError(checkoutError); - throw checkoutError; - } - } - - let reauthPromise: Promise | null = null; - - try { - try { - const res = await conn.command(ns, cmd, options, responseType); - throwIfWriteConcernError(res); - return res; - } catch (commandError) { - throw this.decorateCommandError(conn, cmd, options, commandError); - } - } catch (operationError) { - if ( - operationError instanceof MongoError && - operationError.code === MONGODB_ERROR_CODES.Reauthenticate - ) { - reauthPromise = this.pool.reauthenticate(conn); - reauthPromise.then(undefined, error => { - reauthPromise = null; - squashError(error); - }); - - await abortable(reauthPromise, options); - reauthPromise = null; // only reachable if reauth succeeds - - try { - const res = await conn.command(ns, cmd, options, responseType); - throwIfWriteConcernError(res); - return res; - } catch (commandError) { - throw this.decorateCommandError(conn, cmd, options, commandError); - } - } else { - throw operationError; - } - } finally { - this.decrementOperationCount(); - if (session?.pinnedConnection !== conn) { - if (reauthPromise != null) { - // The reauth promise only exists if it hasn't thrown. - const checkBackIn = () => { - this.pool.checkIn(conn); - }; - void reauthPromise.then(checkBackIn, checkBackIn); - } else { - this.pool.checkIn(conn); - } - } - } - } - /** * Handle SDAM error * @internal diff --git a/test/integration/crud/abstract_operation.test.ts b/test/integration/crud/abstract_operation.test.ts index cce3ac9ec3..74d3c88d4e 100644 --- a/test/integration/crud/abstract_operation.test.ts +++ b/test/integration/crud/abstract_operation.test.ts @@ -1,9 +1,7 @@ import { expect } from 'chai'; -import * as sinon from 'sinon'; -import { executeOperation, Long, Server } from '../../mongodb'; +import { Long } from '../../mongodb'; import * as mongodb from '../../mongodb'; -import { topologyWithPlaceholderClient } from '../../tools/utils'; describe('abstract operation', function () { describe('command name getter', function () { @@ -13,23 +11,11 @@ describe('abstract operation', function () { correctCommandName: string; } - const WrapperSubclasses = [ - 'RunAdminCommandOperation', - 'RunCommandOperation', - 'OptionsOperation', - 'IsCappedOperation', - 'BulkWriteOperation', - 'IndexOperation', - 'CollectionsOperation' - ]; - - const sameServerOnlyOperationSubclasses = ['GetMoreOperation', 'KillCursorsOperation']; + let client: mongodb.MongoClient; + let db: mongodb.Db; + let admin: mongodb.Admin; + let collection: mongodb.Collection; - let client; - let db; - let admin; - let collection; - let constructorServer; const subclassArray: AbstractOperationSubclasses[] = [ { subclassCreator: () => @@ -55,13 +41,17 @@ describe('abstract operation', function () { }, { subclassCreator: () => - new mongodb.DeleteOneOperation(collection, [{ q: { a: 1 }, limit: 1 }], {}), + new mongodb.DeleteOneOperation(collection.fullNamespace, [{ q: { a: 1 }, limit: 1 }], {}), subclassType: mongodb.DeleteOneOperation, correctCommandName: 'delete' }, { subclassCreator: () => - new mongodb.DeleteManyOperation(collection, [{ q: { a: 1 }, limit: 1 }], {}), + new mongodb.DeleteManyOperation( + collection.fullNamespace, + [{ q: { a: 1 }, limit: 1 }], + {} + ), subclassType: mongodb.DeleteManyOperation, correctCommandName: 'delete' }, @@ -117,7 +107,7 @@ describe('abstract operation', function () { new mongodb.GetMoreOperation( collection.fullNamespace, Long.fromNumber(1), - constructorServer, + {} as any as mongodb.Server, {} ), subclassType: mongodb.GetMoreOperation, @@ -155,7 +145,7 @@ describe('abstract operation', function () { new mongodb.KillCursorsOperation( Long.fromNumber(1), collection.fullNamespace, - constructorServer, + {} as any as mongodb.Server, {} ), subclassType: mongodb.KillCursorsOperation, @@ -236,17 +226,20 @@ describe('abstract operation', function () { correctCommandName: 'update' }, { - subclassCreator: () => new mongodb.UpdateOneOperation(collection, { a: 1 }, { $a: 2 }, {}), + subclassCreator: () => + new mongodb.UpdateOneOperation(collection.fullNamespace, { a: 1 }, { $a: 2 }, {}), subclassType: mongodb.UpdateOneOperation, correctCommandName: 'update' }, { - subclassCreator: () => new mongodb.UpdateManyOperation(collection, { a: 1 }, { $a: 2 }, {}), + subclassCreator: () => + new mongodb.UpdateManyOperation(collection.fullNamespace, { a: 1 }, { $a: 2 }, {}), subclassType: mongodb.UpdateManyOperation, correctCommandName: 'update' }, { - subclassCreator: () => new mongodb.ReplaceOneOperation(collection, { a: 1 }, { b: 1 }, {}), + subclassCreator: () => + new mongodb.ReplaceOneOperation(collection.fullNamespace, { a: 1 }, { b: 1 }, {}), subclassType: mongodb.ReplaceOneOperation, correctCommandName: 'update' }, @@ -262,20 +255,11 @@ describe('abstract operation', function () { db = client.db('foo'); admin = client.db().admin(); collection = db.collection('bar'); - constructorServer = new Server( - topologyWithPlaceholderClient([], {} as any), - new mongodb.ServerDescription('a:1'), - {} as any - ); + await client.connect(); }); afterEach(async function () { - db = undefined; - collection = undefined; - constructorServer = undefined; - admin = undefined; await client.close(); - sinon.restore(); }); for (const { subclassCreator, subclassType, correctCommandName } of subclassArray) { @@ -285,25 +269,31 @@ describe('abstract operation', function () { expect(subclassInstance.commandName).to.equal(correctCommandName); }); - if (!WrapperSubclasses.includes(subclassType.name.toString())) { - it(`operation.commandName equals key in command document`, async function () { - const subclassInstance = subclassCreator(); - if (subclassInstance instanceof mongodb.ModernizedOperation) { - return; - } - const yieldDoc = - subclassType.name === 'ProfilingLevelOperation' ? { ok: 1, was: 1 } : { ok: 1 }; - const cmdCallerStub = sinon.stub(Server.prototype, 'command').resolves(yieldDoc); - if (sameServerOnlyOperationSubclasses.includes(subclassType.name.toString())) { - await subclassInstance.execute(constructorServer, client.session); - } else { - await executeOperation(client, subclassInstance); + if (subclassType !== mongodb.RunCommandOperation) { + it( + `operation.commandName is a key in the command document`, + { + requires: { topology: 'single' } + }, + async function () { + const session = client.startSession(); + const pool = Array.from(client.topology.s.servers.values())[0].pool; + const timeoutContext = mongodb.TimeoutContext.create({ + waitQueueTimeoutMS: 1000, + serverSelectionTimeoutMS: 1000 + }); + const connection = await pool.checkOut({ + timeoutContext + }); + + try { + const command = subclassCreator().buildCommand(connection, session); + expect(command).to.have.property(subclassCreator().commandName); + } finally { + pool.checkIn(connection); + } } - expect(cmdCallerStub).to.have.been.calledWith( - sinon.match.any, - sinon.match.hasOwn(subclassInstance.commandName) - ); - }); + ); } }); } diff --git a/test/integration/retryable-writes/non-server-retryable_writes.test.ts b/test/integration/retryable-writes/non-server-retryable_writes.test.ts index 453928e622..cc04931e7a 100644 --- a/test/integration/retryable-writes/non-server-retryable_writes.test.ts +++ b/test/integration/retryable-writes/non-server-retryable_writes.test.ts @@ -32,7 +32,7 @@ describe('Non Server Retryable Writes', function () { 'returns the original error with a PoolRequstedRetry label after encountering a WriteConcernError', { requires: { topology: 'replicaset' } }, async () => { - const serverCommandStub = sinon.stub(Server.prototype, 'modernCommand'); + const serverCommandStub = sinon.stub(Server.prototype, 'command'); serverCommandStub.onCall(0).rejects(new PoolClearedError('error')); serverCommandStub.onCall(1).returns( Promise.reject( diff --git a/test/integration/retryable-writes/retryable_writes.spec.prose.test.ts b/test/integration/retryable-writes/retryable_writes.spec.prose.test.ts index 827455804d..c1754b29b0 100644 --- a/test/integration/retryable-writes/retryable_writes.spec.prose.test.ts +++ b/test/integration/retryable-writes/retryable_writes.spec.prose.test.ts @@ -275,7 +275,7 @@ describe('Retryable Writes Spec Prose', () => { 'when a retry attempt fails with an error labeled NoWritesPerformed, drivers MUST return the original error', { requires: { topology: 'replicaset', mongodb: '>=4.2.9' } }, async () => { - const serverCommandStub = sinon.stub(Server.prototype, 'modernCommand'); + const serverCommandStub = sinon.stub(Server.prototype, 'command'); serverCommandStub.onCall(0).rejects( new MongoWriteConcernError({ errorLabels: ['RetryableWriteError'], diff --git a/test/integration/server-selection/operation_count.test.ts b/test/integration/server-selection/operation_count.test.ts index 451515e35d..d02c18d02a 100644 --- a/test/integration/server-selection/operation_count.test.ts +++ b/test/integration/server-selection/operation_count.test.ts @@ -70,7 +70,7 @@ describe('Server Operation Count Tests', function () { it('is zero after a successful command', loadBalancedTestMetadata, async function () { const server = Array.from(client.topology.s.servers.values())[0]; expect(server.s.operationCount).to.equal(0); - const commandSpy = sinon.spy(server, 'modernCommand'); + const commandSpy = sinon.spy(server, 'command'); await collection.findOne({ count: 1 }); @@ -84,7 +84,7 @@ describe('Server Operation Count Tests', function () { const server = Array.from(client.topology.s.servers.values())[0]; expect(server.s.operationCount).to.equal(0); - const commandSpy = sinon.spy(server, 'modernCommand'); + const commandSpy = sinon.spy(server, 'command'); const error = await collection.findOne({ count: 1 }).catch(e => e); @@ -104,7 +104,7 @@ describe('Server Operation Count Tests', function () { sinon .stub(ConnectionPool.prototype, 'checkOut') .rejects(new Error('unable to checkout connection')); - const commandSpy = sinon.spy(server, 'modernCommand'); + const commandSpy = sinon.spy(server, 'command'); const error = await collection.findOne({ count: 1 }).catch(e => e); @@ -120,7 +120,7 @@ describe('Server Operation Count Tests', function () { it('is zero after a successful command', testMetadata, async function () { const server = Array.from(client.topology.s.servers.values())[0]; expect(server.s.operationCount).to.equal(0); - const commandSpy = sinon.spy(server, 'modernCommand'); + const commandSpy = sinon.spy(server, 'command'); const incrementSpy = sinon.spy(server, 'incrementOperationCount'); const decrementSpy = sinon.spy(server, 'decrementOperationCount'); @@ -147,7 +147,7 @@ describe('Server Operation Count Tests', function () { const server = Array.from(client.topology.s.servers.values())[0]; expect(server.s.operationCount).to.equal(0); - const commandSpy = sinon.spy(server, 'modernCommand'); + const commandSpy = sinon.spy(server, 'command'); const error = await collection.insertOne({ count: 1 }).catch(e => e); @@ -171,7 +171,7 @@ describe('Server Operation Count Tests', function () { sinon .stub(ConnectionPool.prototype, 'checkOut') .rejects(new Error('unable to checkout connection')); - const commandSpy = sinon.spy(server, 'modernCommand'); + const commandSpy = sinon.spy(server, 'command'); const error = await collection.insertOne({ count: 1 }).catch(e => e); diff --git a/test/unit/assorted/server_discovery_and_monitoring.spec.test.ts b/test/unit/assorted/server_discovery_and_monitoring.spec.test.ts index be7ff7ef45..d4df5685f7 100644 --- a/test/unit/assorted/server_discovery_and_monitoring.spec.test.ts +++ b/test/unit/assorted/server_discovery_and_monitoring.spec.test.ts @@ -15,6 +15,7 @@ import { MongoNetworkTimeoutError, MongoServerError, ns, + RunCommandOperation, Server, SERVER_CLOSED, SERVER_DESCRIPTION_CHANGED, @@ -344,7 +345,9 @@ async function executeSDAMTest(testData: SDAMTest) { const server = client.topology.s.servers.get(appError.address); // Run a dummy command to encounter the error - const res = server.command.bind(server)(ns('admin.$cmd'), { ping: 1 }, {}); + const res = server.command.bind(server)( + new RunCommandOperation(ns('admin.$cmd'), { ping: 1 }, {}) + ); const thrownError = await res.catch(error => error); // Restore the stub before asserting anything in case of errors diff --git a/test/unit/error.test.ts b/test/unit/error.test.ts index 9366816ba3..355b1dd000 100644 --- a/test/unit/error.test.ts +++ b/test/unit/error.test.ts @@ -30,6 +30,7 @@ import { NODE_IS_RECOVERING_ERROR_MESSAGE, ns, PoolClosedError as MongoPoolClosedError, + RunCommandOperation, setDifference, TimeoutContext, type TopologyDescription, @@ -405,14 +406,15 @@ describe('MongoErrors', () => { serverSelectionTimeoutMS: 0, waitQueueTimeoutMS: 0 }); + const op = new RunCommandOperation( + ns('db1'), + Object.assign({}, RAW_USER_WRITE_CONCERN_CMD), + {} + ); return replSet .connect() .then(topology => topology.selectServer('primary', { timeoutContext })) - .then(server => - server.command(ns('db1'), Object.assign({}, RAW_USER_WRITE_CONCERN_CMD), { - timeoutContext - }) - ) + .then(server => server.command(op, timeoutContext)) .then( () => expect.fail('expected command to fail'), err => { @@ -455,23 +457,26 @@ describe('MongoErrors', () => { waitQueueTimeoutMS: 0 }); + const op = new RunCommandOperation( + ns('db1'), + Object.assign({}, RAW_USER_WRITE_CONCERN_CMD), + {} + ); topology.selectServer('primary', { timeoutContext }).then(server => { - server - .command(ns('db1'), Object.assign({}, RAW_USER_WRITE_CONCERN_CMD), { timeoutContext }) - .then(expect.fail, err => { - let _err; - try { - expect(err).to.be.an.instanceOf(MongoWriteConcernError); - expect(err.result).to.exist; - expect(err.result.writeConcernError).to.deep.equal( - RAW_USER_WRITE_CONCERN_ERROR_INFO.writeConcernError - ); - } catch (e) { - _err = e; - } finally { - cleanup(_err); - } - }); + server.command(op, timeoutContext).then(expect.fail, err => { + let _err; + try { + expect(err).to.be.an.instanceOf(MongoWriteConcernError); + expect(err.result).to.exist; + expect(err.result.writeConcernError).to.deep.equal( + RAW_USER_WRITE_CONCERN_ERROR_INFO.writeConcernError + ); + } catch (e) { + _err = e; + } finally { + cleanup(_err); + } + }); }, expect.fail); }); }); diff --git a/test/unit/sdam/topology.test.ts b/test/unit/sdam/topology.test.ts index 1c099ce1ba..60c4dcf2de 100644 --- a/test/unit/sdam/topology.test.ts +++ b/test/unit/sdam/topology.test.ts @@ -14,6 +14,8 @@ import { MongoServerSelectionError, ns, ReadPreference, + RunCommandOperation, + RunCursorCommandOperation, Server, SrvPoller, SrvPollingEvent, @@ -121,7 +123,7 @@ describe('Topology (unit)', function () { }) .then(server => { server - .command(ns('admin.$cmd'), { ping: 1 }, { socketTimeoutMS: 250, timeoutContext: ctx }) + .command(new RunCursorCommandOperation(ns('admin.$cmd'), { ping: 1 }, {}), ctx) .then( () => expect.fail('expected command to fail'), err => { @@ -235,7 +237,10 @@ describe('Topology (unit)', function () { waitQueueTimeoutMS: 0 }); const err = await server - .command(ns('test.test'), { insert: { a: 42 } }, { timeoutContext }) + .command( + new RunCommandOperation(ns('test.test'), { insert: { a: 42 } }, {}), + timeoutContext + ) .then( () => null, e => e @@ -270,7 +275,10 @@ describe('Topology (unit)', function () { }); const err = await server - .command(ns('test.test'), { insert: { a: 42 } }, { timeoutContext }) + .command( + new RunCommandOperation(ns('test.test'), { insert: { a: 42 } }, {}), + timeoutContext + ) .then( () => null, e => e @@ -303,7 +311,10 @@ describe('Topology (unit)', function () { server.on('descriptionReceived', sd => (serverDescription = sd)); const err = await server - .command(ns('test.test'), { insert: { a: 42 } }, { timeoutContext }) + .command( + new RunCommandOperation(ns('test.test'), { insert: { a: 42 } }, {}), + timeoutContext + ) .then( () => null, e => e