From c5f859df73973c2f0be05ac81d6174e4c4fe7a57 Mon Sep 17 00:00:00 2001 From: Daria Pardue Date: Wed, 3 Sep 2025 16:03:26 -0400 Subject: [PATCH 1/8] remove pre-4.2 logic in sessions --- src/sessions.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/sessions.ts b/src/sessions.ts index abd63468da2..075f8c04a1d 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -42,7 +42,6 @@ import { commandSupportsReadConcern, isPromiseLike, List, - maxWireVersion, MongoDBNamespace, noop, now, @@ -51,8 +50,6 @@ import { } from './utils'; import { WriteConcern, type WriteConcernOptions, type WriteConcernSettings } from './write_concern'; -const minWireVersionForShardedTransactions = 8; - /** @public */ export interface ClientSessionOptions { /** Whether causal consistency should be enabled on this session */ @@ -405,17 +402,6 @@ export class ClientSession this.unpin(); } - const topologyMaxWireVersion = maxWireVersion(this.client.topology); - if ( - isSharded(this.client.topology) && - topologyMaxWireVersion != null && - topologyMaxWireVersion < minWireVersionForShardedTransactions - ) { - throw new MongoCompatibilityError( - 'Transactions are not supported on sharded clusters in MongoDB < 4.2.' - ); - } - this.commitAttempted = false; // increment txnNumber this.incrementTransactionNumber(); From 9e210082694208dc9845abb7df37f2760677a37b Mon Sep 17 00:00:00 2001 From: Daria Pardue Date: Wed, 3 Sep 2025 16:08:12 -0400 Subject: [PATCH 2/8] remove pre-4.2 logic from connection --- src/cmap/connection.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/cmap/connection.ts b/src/cmap/connection.ts index 2e39bf40749..25ef58dbbec 100644 --- a/src/cmap/connection.ts +++ b/src/cmap/connection.ts @@ -284,7 +284,6 @@ export class Connection extends TypedEventEmitter { private get supportsOpMsg(): boolean { return ( this.description != null && - maxWireVersion(this) >= 6 && !this.description.__nodejs_mock_server__ ); } @@ -880,12 +879,6 @@ export class CryptoConnection extends Connection { return await super.command(ns, cmd, options, responseType); } - if (serverWireVersion < 8) { - throw new MongoCompatibilityError( - 'Auto-encryption requires a minimum MongoDB version of 4.2' - ); - } - // Save sort or indexKeys based on the command being run // the encrypt API serializes our JS objects to BSON to pass to the native code layer // and then deserializes the encrypted result, the protocol level components From 73347be4e12435dc96135dca6e142b968468da21 Mon Sep 17 00:00:00 2001 From: Daria Pardue Date: Wed, 3 Sep 2025 16:17:51 -0400 Subject: [PATCH 3/8] remove pre-4.2 logic from change streams, aggregate, and server --- src/cursor/change_stream_cursor.ts | 5 ++--- src/operations/aggregate.ts | 8 +------- src/sdam/server.ts | 2 +- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/cursor/change_stream_cursor.ts b/src/cursor/change_stream_cursor.ts index 73a256cdeea..8b56e2d355a 100644 --- a/src/cursor/change_stream_cursor.ts +++ b/src/cursor/change_stream_cursor.ts @@ -93,7 +93,7 @@ export class ChangeStreamCursor< } else { options.resumeAfter = this.resumeToken; } - } else if (this.startAtOperationTime != null && maxWireVersion(this.server) >= 7) { + } else if (this.startAtOperationTime != null) { options.startAtOperationTime = this.startAtOperationTime; } @@ -145,8 +145,7 @@ export class ChangeStreamCursor< if ( this.startAtOperationTime == null && this.changeStreamCursorOptions.resumeAfter == null && - this.changeStreamCursorOptions.startAfter == null && - this.maxWireVersion >= 7 + this.changeStreamCursorOptions.startAfter == null ) { this.startAtOperationTime = response.operationTime; } diff --git a/src/operations/aggregate.ts b/src/operations/aggregate.ts index 620ee4ea601..5171111a117 100644 --- a/src/operations/aggregate.ts +++ b/src/operations/aggregate.ts @@ -4,14 +4,13 @@ import { CursorResponse, ExplainedCursorResponse } from '../cmap/wire_protocol/r import { type CursorTimeoutMode } from '../cursor/abstract_cursor'; import { MongoInvalidArgumentError } from '../error'; import { type ExplainOptions } from '../explain'; -import { maxWireVersion, type MongoDBNamespace } from '../utils'; +import { type MongoDBNamespace } from '../utils'; import { WriteConcern } from '../write_concern'; import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects, type Hint } from './operation'; /** @internal */ export const DB_AGGREGATE_COLLECTION = 1 as const; -const MIN_WIRE_VERSION_$OUT_READ_CONCERN_SUPPORT = 8; /** @public */ export interface AggregateOptions extends Omit { @@ -109,13 +108,8 @@ export class AggregateOperation extends CommandOperation { override buildCommandDocument(connection: Connection): Document { const options = this.options; - const serverWireVersion = maxWireVersion(connection); const command: Document = { aggregate: this.target, pipeline: this.pipeline }; - if (this.hasWriteStage && serverWireVersion < MIN_WIRE_VERSION_$OUT_READ_CONCERN_SUPPORT) { - this.readConcern = undefined; - } - if (this.hasWriteStage && this.writeConcern) { WriteConcern.apply(command, this.writeConcern); } diff --git a/src/sdam/server.ts b/src/sdam/server.ts index 8488344d5d9..b1f7c0e537a 100644 --- a/src/sdam/server.ts +++ b/src/sdam/server.ts @@ -414,7 +414,7 @@ export class Server extends TypedEventEmitter { } else { if (isSDAMUnrecoverableError(error)) { if (shouldHandleStateChangeError(this, error)) { - const shouldClearPool = maxWireVersion(this) <= 7 || isNodeShuttingDownError(error); + const shouldClearPool = isNodeShuttingDownError(error); if (this.loadBalanced && connection && shouldClearPool) { this.pool.clear({ serviceId: connection.serviceId }); } From 1ee6708f9768e03fe527f18fcef729d82c5eca9d Mon Sep 17 00:00:00 2001 From: Daria Pardue Date: Fri, 12 Sep 2025 14:23:25 -0400 Subject: [PATCH 4/8] feat: deprecate ServerCapabilities on topology --- src/sdam/topology.ts | 21 ++++++++++++--------- src/utils.ts | 5 ----- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/sdam/topology.ts b/src/sdam/topology.ts index 7b4775709a1..8973286817c 100644 --- a/src/sdam/topology.ts +++ b/src/sdam/topology.ts @@ -1104,7 +1104,10 @@ function isStaleServerDescription( ); } -/** @public */ +/** + * @public + * @deprecated This class will be removed as dead code. + */ export class ServerCapabilities { maxWireVersion: number; minWireVersion: number; @@ -1115,26 +1118,26 @@ export class ServerCapabilities { } get hasAggregationCursor(): boolean { - return this.maxWireVersion >= 1; + return true; } get hasWriteCommands(): boolean { - return this.maxWireVersion >= 2; + return true; } get hasTextSearch(): boolean { - return this.minWireVersion >= 0; + return true; } get hasAuthCommands(): boolean { - return this.maxWireVersion >= 1; + return true; } get hasListCollectionsCommand(): boolean { - return this.maxWireVersion >= 3; + return true; } get hasListIndexesCommand(): boolean { - return this.maxWireVersion >= 3; + return true; } get supportsSnapshotReads(): boolean { @@ -1142,10 +1145,10 @@ export class ServerCapabilities { } get commandsTakeWriteConcern(): boolean { - return this.maxWireVersion >= 5; + return true; } get commandsTakeCollation(): boolean { - return this.maxWireVersion >= 5; + return true; } } diff --git a/src/utils.ts b/src/utils.ts index cab65ce58fa..0702b2a8111 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -211,13 +211,8 @@ export function decorateWithCollation( target: MongoClient | Db | Collection, options: AnyOptions ): void { - const capabilities = getTopology(target).capabilities; if (options.collation && typeof options.collation === 'object') { - if (capabilities && capabilities.commandsTakeCollation) { command.collation = options.collation; - } else { - throw new MongoCompatibilityError(`Current topology does not support collation`); - } } } From 44f187c0a2f7890f412a2a6eaccc506f00c27a4d Mon Sep 17 00:00:00 2001 From: Daria Pardue Date: Fri, 12 Sep 2025 14:48:40 -0400 Subject: [PATCH 5/8] feat: deprecate minWireVersion on ReadPreference --- src/read_preference.ts | 3 +++ src/sdam/server_selection.ts | 10 ---------- src/sdam/topology.ts | 2 +- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/read_preference.ts b/src/read_preference.ts index cef52ad4dcc..209752dc865 100644 --- a/src/read_preference.ts +++ b/src/read_preference.ts @@ -63,6 +63,9 @@ export class ReadPreference { tags?: TagSet[]; hedge?: HedgeOptions; maxStalenessSeconds?: number; + /** + * @deprecated This will be removed as dead code in the next major version. + */ minWireVersion?: number; public static PRIMARY = ReadPreferenceMode.primary; diff --git a/src/sdam/server_selection.ts b/src/sdam/server_selection.ts index 409ef646ddf..b08f141ca01 100644 --- a/src/sdam/server_selection.ts +++ b/src/sdam/server_selection.ts @@ -273,16 +273,6 @@ export function readPreferenceServerSelector(readPreference: ReadPreference): Se servers: ServerDescription[], deprioritized: ServerDescription[] = [] ): ServerDescription[] { - const commonWireVersion = topologyDescription.commonWireVersion; - if ( - commonWireVersion && - readPreference.minWireVersion && - readPreference.minWireVersion > commonWireVersion - ) { - throw new MongoCompatibilityError( - `Minimum wire version '${readPreference.minWireVersion}' required, but found '${commonWireVersion}'` - ); - } if (topologyDescription.type === TopologyType.LoadBalanced) { return servers.filter(loadBalancerFilter); diff --git a/src/sdam/topology.ts b/src/sdam/topology.ts index 8973286817c..3d088caf6c3 100644 --- a/src/sdam/topology.ts +++ b/src/sdam/topology.ts @@ -1106,7 +1106,7 @@ function isStaleServerDescription( /** * @public - * @deprecated This class will be removed as dead code. + * @deprecated This class will be removed as dead code in the next major version. */ export class ServerCapabilities { maxWireVersion: number; From c14fe1c22b9cec778d72975129758277ec6c5d11 Mon Sep 17 00:00:00 2001 From: Daria Pardue Date: Fri, 12 Sep 2025 16:22:33 -0400 Subject: [PATCH 6/8] fix: restore opMsgSupport check --- src/cmap/connection.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cmap/connection.ts b/src/cmap/connection.ts index 25ef58dbbec..ce62f9a7dad 100644 --- a/src/cmap/connection.ts +++ b/src/cmap/connection.ts @@ -284,6 +284,8 @@ export class Connection extends TypedEventEmitter { private get supportsOpMsg(): boolean { return ( this.description != null && + // TODO(NODE-6672,NODE-6287): This guard is primarily for maxWireVersion = 0 + maxWireVersion(this) >= 6 && !this.description.__nodejs_mock_server__ ); } From 347c47d01f266e5adfab53368d4099af4854b8bb Mon Sep 17 00:00:00 2001 From: Daria Pardue Date: Fri, 12 Sep 2025 16:52:49 -0400 Subject: [PATCH 7/8] lint --- src/operations/aggregate.ts | 3 +-- src/operations/find_and_modify.ts | 2 +- src/sdam/server_selection.ts | 3 +-- src/sessions.ts | 1 - src/utils.ts | 7 ++----- 5 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/operations/aggregate.ts b/src/operations/aggregate.ts index 5171111a117..2b23b9acb67 100644 --- a/src/operations/aggregate.ts +++ b/src/operations/aggregate.ts @@ -1,4 +1,3 @@ -import { type Connection } from '..'; import type { Document } from '../bson'; import { CursorResponse, ExplainedCursorResponse } from '../cmap/wire_protocol/responses'; import { type CursorTimeoutMode } from '../cursor/abstract_cursor'; @@ -106,7 +105,7 @@ export class AggregateOperation extends CommandOperation { this.pipeline.push(stage); } - override buildCommandDocument(connection: Connection): Document { + override buildCommandDocument(): Document { const options = this.options; const command: Document = { aggregate: this.target, pipeline: this.pipeline }; diff --git a/src/operations/find_and_modify.ts b/src/operations/find_and_modify.ts index 10cd8cb83b8..a35e288dd47 100644 --- a/src/operations/find_and_modify.ts +++ b/src/operations/find_and_modify.ts @@ -188,7 +188,7 @@ export class FindAndModifyOperation extends CommandOperation { command.comment = options.comment; } - decorateWithCollation(command, this.collection, options); + decorateWithCollation(command, options); if (options.hint) { const unacknowledgedWrite = this.writeConcern?.w === 0; diff --git a/src/sdam/server_selection.ts b/src/sdam/server_selection.ts index b08f141ca01..03b6e959386 100644 --- a/src/sdam/server_selection.ts +++ b/src/sdam/server_selection.ts @@ -1,4 +1,4 @@ -import { MongoCompatibilityError, MongoInvalidArgumentError } from '../error'; +import { MongoInvalidArgumentError } from '../error'; import { ReadPreference } from '../read_preference'; import { ServerType, TopologyType } from './common'; import type { ServerDescription, TagSet } from './server_description'; @@ -273,7 +273,6 @@ export function readPreferenceServerSelector(readPreference: ReadPreference): Se servers: ServerDescription[], deprioritized: ServerDescription[] = [] ): ServerDescription[] { - if (topologyDescription.type === TopologyType.LoadBalanced) { return servers.filter(loadBalancerFilter); } diff --git a/src/sessions.ts b/src/sessions.ts index 075f8c04a1d..25031a41754 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -2,7 +2,6 @@ import { Binary, type Document, Long, type Timestamp } from './bson'; import type { CommandOptions, Connection } from './cmap/connection'; import { ConnectionPoolMetrics } from './cmap/metrics'; import { type MongoDBResponse } from './cmap/wire_protocol/responses'; -import { isSharded } from './cmap/wire_protocol/shared'; import { PINNED, UNPINNED } from './constants'; import type { AbstractCursor } from './cursor/abstract_cursor'; import { diff --git a/src/utils.ts b/src/utils.ts index 0702b2a8111..1633d054faf 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -19,7 +19,6 @@ import type { Db } from './db'; import { type AnyError, MongoAPIError, - MongoCompatibilityError, MongoInvalidArgumentError, MongoNetworkTimeoutError, MongoNotConnectedError, @@ -207,12 +206,10 @@ export function isPromiseLike(value?: unknown): value is PromiseLik * @param options - options containing collation settings */ export function decorateWithCollation( - command: Document, - target: MongoClient | Db | Collection, - options: AnyOptions + command: Document, options: AnyOptions ): void { if (options.collation && typeof options.collation === 'object') { - command.collation = options.collation; + command.collation = options.collation; } } From b15f5f3963faeb27d801123becdec44c57d5575b Mon Sep 17 00:00:00 2001 From: Daria Pardue Date: Fri, 12 Sep 2025 16:59:18 -0400 Subject: [PATCH 8/8] lint and test cleanup --- src/utils.ts | 4 +-- test/unit/change_stream.test.ts | 60 --------------------------------- 2 files changed, 1 insertion(+), 63 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 1633d054faf..9f900bda411 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -205,9 +205,7 @@ export function isPromiseLike(value?: unknown): value is PromiseLik * @param target - target of command * @param options - options containing collation settings */ -export function decorateWithCollation( - command: Document, options: AnyOptions -): void { +export function decorateWithCollation(command: Document, options: AnyOptions): void { if (options.collation && typeof options.collation === 'object') { command.collation = options.collation; } diff --git a/test/unit/change_stream.test.ts b/test/unit/change_stream.test.ts index 7cbde2b2c42..0b1b2b7c301 100644 --- a/test/unit/change_stream.test.ts +++ b/test/unit/change_stream.test.ts @@ -184,36 +184,6 @@ describe('ChangeStreamCursor', function () { expect(cursor.resumeOptions).to.haveOwnProperty('startAtOperationTime'); }); }); - - context('when the maxWireVersion < 7', function () { - let cursor: ChangeStreamCursor; - beforeEach(function () { - cursor = new ChangeStreamCursor( - new MongoClient('mongodb://localhost:27027'), - new MongoDBNamespace('db', 'collection'), - [], - { - startAfter: 'start after', - resumeAfter: 'resume after', - startAtOperationTime: new Timestamp(Long.ZERO) - } - ); - cursor.resumeToken = null; - sinon.stub(cursor, 'server').get(() => ({ hello: { maxWireVersion: 6 } })); - }); - - it('does NOT set the resumeAfter option', function () { - expect(cursor.resumeOptions).not.to.haveOwnProperty('resumeAfter'); - }); - - it('does NOT set the startAfter option', function () { - expect(cursor.resumeOptions).not.to.haveOwnProperty('startAfter'); - }); - - it('does NOT set the startAtOperationTime option', function () { - expect(cursor.resumeOptions).not.to.haveOwnProperty('startAtOperationTime'); - }); - }); }); context('when the cursor does NOT have a saved operation time', function () { @@ -266,36 +236,6 @@ describe('ChangeStreamCursor', function () { expect(cursor.resumeOptions).not.to.haveOwnProperty('startAtOperationTime'); }); }); - - context('when the maxWireVersion < 7', function () { - let cursor: ChangeStreamCursor; - beforeEach(function () { - cursor = new ChangeStreamCursor( - new MongoClient('mongodb://localhost:27027'), - new MongoDBNamespace('db', 'collection'), - [], - { - startAfter: 'start after', - resumeAfter: 'resume after', - startAtOperationTime: new Timestamp(Long.ZERO) - } - ); - cursor.resumeToken = null; - sinon.stub(cursor, 'server').get(() => ({ hello: { maxWireVersion: 6 } })); - }); - - it('does NOT set the resumeAfter option', function () { - expect(cursor.resumeOptions).not.to.haveOwnProperty('resumeAfter'); - }); - - it('does NOT set the startAfter option', function () { - expect(cursor.resumeOptions).not.to.haveOwnProperty('startAfter'); - }); - - it('does NOT set the startAtOperationTime option', function () { - expect(cursor.resumeOptions).not.to.haveOwnProperty('startAtOperationTime'); - }); - }); }); }); });