Socket
Book a DemoInstallSign in
Socket

mongodb

Package Overview
Dependencies
Maintainers
5
Versions
706
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mongodb - npm Package Compare versions

Comparing version

to
6.19.0-dev.20250827.sha.3c5bb1d5

lib/cursor/explainable_cursor.js

3

lib/admin.js

@@ -10,2 +10,3 @@ "use strict";

const validate_collection_1 = require("./operations/validate_collection");
const utils_1 = require("./utils");
/**

@@ -61,3 +62,3 @@ * The **Admin** class is an internal class that allows convenient access to

async command(command, options) {
return await (0, execute_operation_1.executeOperation)(this.s.db.client, new run_command_1.RunAdminCommandOperation(command, {
return await (0, execute_operation_1.executeOperation)(this.s.db.client, new run_command_1.RunCommandOperation(new utils_1.MongoDBNamespace('admin'), command, {
...(0, bson_1.resolveBSONOptions)(options),

@@ -64,0 +65,0 @@ session: options?.session,

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BulkOperationBase = exports.BulkWriteShimOperation = exports.FindOperators = exports.MongoBulkWriteError = exports.WriteError = exports.WriteConcernError = exports.BulkWriteResult = exports.Batch = exports.BatchType = void 0;
exports.BulkOperationBase = exports.FindOperators = exports.MongoBulkWriteError = exports.WriteError = exports.WriteConcernError = exports.BulkWriteResult = exports.Batch = exports.BatchType = void 0;
exports.mergeBatchResults = mergeBatchResults;

@@ -10,4 +10,4 @@ const bson_1 = require("../bson");

const insert_1 = require("../operations/insert");
const operation_1 = require("../operations/operation");
const update_1 = require("../operations/update");
const timeout_1 = require("../timeout");
const utils_1 = require("../utils");

@@ -499,29 +499,2 @@ const write_concern_1 = require("../write_concern");

exports.FindOperators = FindOperators;
/**
* TODO(NODE-4063)
* BulkWrites merge complexity is implemented in executeCommands
* This provides a vehicle to treat bulkOperations like any other operation (hence "shim")
* We would like this logic to simply live inside the BulkWriteOperation class
* @internal
*/
class BulkWriteShimOperation extends operation_1.AbstractOperation {
constructor(bulkOperation, options) {
super(options);
this.bulkOperation = bulkOperation;
}
get commandName() {
return 'bulkWrite';
}
async execute(_server, session, timeoutContext) {
if (this.options.session == null) {
// An implicit session could have been created by 'executeOperation'
// So if we stick it on finalOptions here, each bulk operation
// will use this same session, it'll be passed in the same way
// an explicit session would be
this.options.session = session;
}
return await executeCommands(this.bulkOperation, { ...this.options, timeoutContext });
}
}
exports.BulkWriteShimOperation = BulkWriteShimOperation;
/** @public */

@@ -806,5 +779,19 @@ class BulkOperationBase {

this.s.executed = true;
const finalOptions = { ...this.s.options, ...options };
const operation = new BulkWriteShimOperation(this, finalOptions);
return await (0, execute_operation_1.executeOperation)(this.s.collection.client, operation, finalOptions.timeoutContext);
const finalOptions = (0, utils_1.resolveOptions)(this.collection, { ...this.s.options, ...options });
// if there is no timeoutContext provided, create a timeoutContext and use it for
// all batches in the bulk operation
finalOptions.timeoutContext ??= timeout_1.TimeoutContext.create({
session: finalOptions.session,
timeoutMS: finalOptions.timeoutMS,
serverSelectionTimeoutMS: this.collection.client.s.options.serverSelectionTimeoutMS,
waitQueueTimeoutMS: this.collection.client.s.options.waitQueueTimeoutMS
});
if (finalOptions.session == null) {
// if there is not an explicit session provided to `execute()`, create
// an implicit session and use that for all batches in the bulk operation
return await this.collection.client.withSession({ explicit: false }, async (session) => {
return await executeCommands(this, { ...finalOptions, session });
});
}
return await executeCommands(this, { ...finalOptions });
}

@@ -811,0 +798,0 @@ /**

@@ -551,3 +551,3 @@ "use strict";

async _encrypt(value, expressionMode, options) {
const { algorithm, keyId, keyAltName, contentionFactor, queryType, rangeOptions } = options;
const { algorithm, keyId, keyAltName, contentionFactor, queryType, rangeOptions, textOptions } = options;
const contextOptions = {

@@ -578,2 +578,5 @@ expressionMode,

}
if (typeof textOptions === 'object') {
contextOptions.textOptions = (0, bson_1.serialize)(textOptions);
}
const valueBuffer = (0, bson_1.serialize)({ v: value });

@@ -580,0 +583,0 @@ const stateMachine = new state_machine_1.StateMachine({

@@ -333,2 +333,6 @@ "use strict";

async setTlsOptions(tlsOptions, options) {
// If a secureContext is provided, ensure it is set.
if (tlsOptions.secureContext) {
options.secureContext = tlsOptions.secureContext;
}
if (tlsOptions.tlsCertificateKeyFile) {

@@ -335,0 +339,0 @@ const cert = await fs.readFile(tlsOptions.tlsCertificateKeyFile);

@@ -13,7 +13,5 @@ "use strict";

const error_1 = require("./error");
const bulk_write_1 = require("./operations/bulk_write");
const count_1 = require("./operations/count");
const delete_1 = require("./operations/delete");
const distinct_1 = require("./operations/distinct");
const drop_1 = require("./operations/drop");
const estimated_document_count_1 = require("./operations/estimated_document_count");

@@ -24,7 +22,5 @@ const execute_operation_1 = require("./operations/execute_operation");

const insert_1 = require("./operations/insert");
const is_capped_1 = require("./operations/is_capped");
const options_operation_1 = require("./operations/options_operation");
const rename_1 = require("./operations/rename");
const create_1 = require("./operations/search_indexes/create");
const drop_2 = require("./operations/search_indexes/drop");
const drop_1 = require("./operations/search_indexes/drop");
const update_1 = require("./operations/search_indexes/update");

@@ -170,3 +166,21 @@ const update_2 = require("./operations/update");

async insertMany(docs, options) {
return await (0, execute_operation_1.executeOperation)(this.client, new insert_1.InsertManyOperation(this, docs, (0, utils_1.resolveOptions)(this, options ?? { ordered: true })));
if (!Array.isArray(docs)) {
throw new error_1.MongoInvalidArgumentError('Argument "docs" must be an array of documents');
}
options = (0, utils_1.resolveOptions)(this, options ?? {});
const acknowledged = write_concern_1.WriteConcern.fromOptions(options)?.w !== 0;
try {
const res = await this.bulkWrite(docs.map(doc => ({ insertOne: { document: doc } })), options);
return {
acknowledged,
insertedCount: res.insertedCount,
insertedIds: res.insertedIds
};
}
catch (err) {
if (err && err.message === 'Operation must be an object with an operation key') {
throw new error_1.MongoInvalidArgumentError('Collection.insertMany() cannot be called with an array that has null/undefined values');
}
throw err;
}
}

@@ -196,3 +210,19 @@ /**

}
return await (0, execute_operation_1.executeOperation)(this.client, new bulk_write_1.BulkWriteOperation(this, operations, (0, utils_1.resolveOptions)(this, options ?? { ordered: true })));
options = (0, utils_1.resolveOptions)(this, options ?? {});
// TODO(NODE-7071): remove once the client doesn't need to be connected to construct
// bulk operations
const isConnected = this.client.topology != null;
if (!isConnected) {
await (0, execute_operation_1.autoConnect)(this.client);
}
// Create the bulk operation
const bulk = options.ordered === false
? this.initializeUnorderedBulkOp(options)
: this.initializeOrderedBulkOp(options);
// for each op go through and add to the bulk
for (const operation of operations) {
bulk.raw(operation);
}
// Execute the bulk
return await bulk.execute({ ...options });
}

@@ -211,3 +241,3 @@ /**

async updateOne(filter, update, options) {
return await (0, execute_operation_1.executeOperation)(this.client, new update_2.UpdateOneOperation(this, filter, update, (0, utils_1.resolveOptions)(this, options)));
return await (0, execute_operation_1.executeOperation)(this.client, new update_2.UpdateOneOperation(this.s.namespace, filter, update, (0, utils_1.resolveOptions)(this, options)));
}

@@ -222,3 +252,3 @@ /**

async replaceOne(filter, replacement, options) {
return await (0, execute_operation_1.executeOperation)(this.client, new update_2.ReplaceOneOperation(this, filter, replacement, (0, utils_1.resolveOptions)(this, options)));
return await (0, execute_operation_1.executeOperation)(this.client, new update_2.ReplaceOneOperation(this.s.namespace, filter, replacement, (0, utils_1.resolveOptions)(this, options)));
}

@@ -237,3 +267,3 @@ /**

async updateMany(filter, update, options) {
return await (0, execute_operation_1.executeOperation)(this.client, new update_2.UpdateManyOperation(this, filter, update, (0, utils_1.resolveOptions)(this, options)));
return await (0, execute_operation_1.executeOperation)(this.client, new update_2.UpdateManyOperation(this.s.namespace, filter, update, (0, utils_1.resolveOptions)(this, options)));
}

@@ -247,3 +277,3 @@ /**

async deleteOne(filter = {}, options = {}) {
return await (0, execute_operation_1.executeOperation)(this.client, new delete_1.DeleteOneOperation(this, filter, (0, utils_1.resolveOptions)(this, options)));
return await (0, execute_operation_1.executeOperation)(this.client, new delete_1.DeleteOneOperation(this.s.namespace, filter, (0, utils_1.resolveOptions)(this, options)));
}

@@ -257,3 +287,3 @@ /**

async deleteMany(filter = {}, options = {}) {
return await (0, execute_operation_1.executeOperation)(this.client, new delete_1.DeleteManyOperation(this, filter, (0, utils_1.resolveOptions)(this, options)));
return await (0, execute_operation_1.executeOperation)(this.client, new delete_1.DeleteManyOperation(this.s.namespace, filter, (0, utils_1.resolveOptions)(this, options)));
}

@@ -282,9 +312,14 @@ /**

async drop(options) {
return await (0, execute_operation_1.executeOperation)(this.client, new drop_1.DropCollectionOperation(this.s.db, this.collectionName, options));
return await this.s.db.dropCollection(this.collectionName, options);
}
async findOne(filter = {}, options = {}) {
const cursor = this.find(filter, options).limit(-1).batchSize(1);
const res = await cursor.next();
// Explicitly set the limit to 1 and singleBatch to true for all commands, per the spec.
// noCursorTimeout must be unset as well as batchSize.
// See: https://github.com/mongodb/specifications/blob/master/source/crud/crud.md#findone-api-details
const { batchSize: _batchSize, noCursorTimeout: _noCursorTimeout, ...opts } = options;
opts.singleBatch = true;
const cursor = this.find(filter, opts).limit(1);
const result = await cursor.next();
await cursor.close();
return res;
return result;
}

@@ -300,3 +335,10 @@ find(filter = {}, options = {}) {

async options(options) {
return await (0, execute_operation_1.executeOperation)(this.client, new options_operation_1.OptionsOperation(this, (0, utils_1.resolveOptions)(this, options)));
options = (0, utils_1.resolveOptions)(this, options);
const [collection] = await this.s.db
.listCollections({ name: this.collectionName }, { ...options, nameOnly: false })
.toArray();
if (collection == null || collection.options == null) {
throw new error_1.MongoAPIError(`collection ${this.namespace} not found`);
}
return collection.options;
}

@@ -309,3 +351,4 @@ /**

async isCapped(options) {
return await (0, execute_operation_1.executeOperation)(this.client, new is_capped_1.IsCappedOperation(this, (0, utils_1.resolveOptions)(this, options)));
const { capped } = await this.options(options);
return Boolean(capped);
}

@@ -704,3 +747,3 @@ /**

async dropSearchIndex(name) {
return await (0, execute_operation_1.executeOperation)(this.client, new drop_2.DropSearchIndexOperation(this, name));
return await (0, execute_operation_1.executeOperation)(this.client, new drop_1.DropSearchIndexOperation(this, name));
}

@@ -707,0 +750,0 @@ /**

@@ -10,2 +10,3 @@ "use strict";

const abstract_cursor_1 = require("./abstract_cursor");
const explainable_cursor_1 = require("./explainable_cursor");
/**

@@ -18,3 +19,3 @@ * The **AggregationCursor** class is an internal class that embodies an aggregation cursor on MongoDB

*/
class AggregationCursor extends explain_1.ExplainableCursor {
class AggregationCursor extends explainable_cursor_1.ExplainableCursor {
/** @internal */

@@ -21,0 +22,0 @@ constructor(client, namespace, pipeline = [], options = {}) {

@@ -12,2 +12,3 @@ "use strict";

const utils_1 = require("../utils");
const explainable_cursor_1 = require("./explainable_cursor");
/** @public Flags allowed for cursor */

@@ -23,3 +24,3 @@ exports.FLAGS = [

/** @public */
class FindCursor extends explain_1.ExplainableCursor {
class FindCursor extends explainable_cursor_1.ExplainableCursor {
/** @internal */

@@ -26,0 +27,0 @@ constructor(client, namespace, filter = {}, options = {}) {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RunCommandCursor = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const error_1 = require("../error");

@@ -68,7 +67,6 @@ const execute_operation_1 = require("../operations/execute_operation");

async _initialize(session) {
const operation = new run_command_1.RunCommandOperation(this.db, this.command, {
const operation = new run_command_1.RunCursorCommandOperation(this.db.s.namespace, this.command, {
...this.cursorOptions,
session: session,
readPreference: this.cursorOptions.readPreference,
responseType: responses_1.CursorResponse
readPreference: this.cursorOptions.readPreference
});

@@ -75,0 +73,0 @@ const response = await (0, execute_operation_1.executeOperation)(this.client, operation, this.timeoutContext);

@@ -13,3 +13,2 @@ "use strict";

const error_1 = require("./error");
const collections_1 = require("./operations/collections");
const create_collection_1 = require("./operations/create_collection");

@@ -161,3 +160,4 @@ const drop_1 = require("./operations/drop");

async createCollection(name, options) {
return await (0, execute_operation_1.executeOperation)(this.client, new create_collection_1.CreateCollectionOperation(this, name, (0, utils_1.resolveOptions)(this, options)));
options = (0, utils_1.resolveOptions)(this, options);
return await (0, create_collection_1.createCollections)(this, name, options);
}

@@ -191,3 +191,3 @@ /**

// Intentionally, we do not inherit options from parent for this operation.
return await (0, execute_operation_1.executeOperation)(this.client, new run_command_1.RunCommandOperation(this, command, (0, utils_1.resolveOptions)(undefined, {
return await (0, execute_operation_1.executeOperation)(this.client, new run_command_1.RunCommandOperation(this.s.namespace, command, (0, utils_1.resolveOptions)(undefined, {
...(0, bson_1.resolveBSONOptions)(options),

@@ -263,3 +263,4 @@ timeoutMS: options?.timeoutMS ?? this.timeoutMS,

async dropCollection(name, options) {
return await (0, execute_operation_1.executeOperation)(this.client, new drop_1.DropCollectionOperation(this, name, (0, utils_1.resolveOptions)(this, options)));
options = (0, utils_1.resolveOptions)(this, options);
return await (0, drop_1.dropCollections)(this, name, options);
}

@@ -280,3 +281,9 @@ /**

async collections(options) {
return await (0, execute_operation_1.executeOperation)(this.client, new collections_1.CollectionsOperation(this, (0, utils_1.resolveOptions)(this, options)));
options = (0, utils_1.resolveOptions)(this, options);
const collections = await this.listCollections({}, { ...options, nameOnly: true }).toArray();
return collections
.filter(
// Filter collections removing any illegal ones
({ name }) => !name.includes('$'))
.map(({ name }) => new collection_1.Collection(this, name, this.s.options));
}

@@ -283,0 +290,0 @@ /**

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExplainableCursor = exports.Explain = exports.ExplainVerbosity = void 0;
exports.Explain = exports.ExplainVerbosity = void 0;
exports.validateExplainTimeoutOptions = validateExplainTimeoutOptions;
exports.decorateWithExplain = decorateWithExplain;
const abstract_cursor_1 = require("./cursor/abstract_cursor");
const error_1 = require("./error");

@@ -60,33 +59,2 @@ /** @public */

}
/**
* @public
*
* A base class for any cursors that have `explain()` methods.
*/
class ExplainableCursor extends abstract_cursor_1.AbstractCursor {
resolveExplainTimeoutOptions(verbosity, options) {
let explain;
let timeout;
if (verbosity == null && options == null) {
explain = undefined;
timeout = undefined;
}
else if (verbosity != null && options == null) {
explain =
typeof verbosity !== 'object'
? verbosity
: 'verbosity' in verbosity
? verbosity
: undefined;
timeout = typeof verbosity === 'object' && 'timeoutMS' in verbosity ? verbosity : undefined;
}
else {
// @ts-expect-error TS isn't smart enough to determine that if both options are provided, the first is explain options
explain = verbosity;
timeout = options;
}
return { timeout, explain };
}
}
exports.ExplainableCursor = ExplainableCursor;
//# sourceMappingURL=explain.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MongoServerClosedError = exports.MongoRuntimeError = exports.MongoParseError = exports.MongoOperationTimeoutError = exports.MongoOIDCError = exports.MongoNotConnectedError = exports.MongoNetworkTimeoutError = exports.MongoNetworkError = exports.MongoMissingDependencyError = exports.MongoMissingCredentialsError = exports.MongoKerberosError = exports.MongoInvalidArgumentError = exports.MongoGridFSStreamError = exports.MongoGridFSChunkError = exports.MongoGCPError = exports.MongoExpiredSessionError = exports.MongoError = exports.MongoDriverError = exports.MongoDecompressionError = exports.MongoCursorInUseError = exports.MongoCursorExhaustedError = exports.MongoCompatibilityError = exports.MongoClientClosedError = exports.MongoClientBulkWriteExecutionError = exports.MongoClientBulkWriteError = exports.MongoClientBulkWriteCursorError = exports.MongoChangeStreamError = exports.MongoBatchReExecutionError = exports.MongoAzureError = exports.MongoAWSError = exports.MongoAPIError = exports.ChangeStreamCursor = exports.ClientEncryption = exports.MongoBulkWriteError = exports.UUID = exports.Timestamp = exports.ObjectId = exports.MinKey = exports.MaxKey = exports.Long = exports.Int32 = exports.Double = exports.Decimal128 = exports.DBRef = exports.Code = exports.BSONType = exports.BSONSymbol = exports.BSONRegExp = exports.Binary = exports.BSON = void 0;
exports.CommandFailedEvent = exports.WriteConcern = exports.ReadPreference = exports.ReadConcern = exports.TopologyType = exports.ServerType = exports.ReadPreferenceMode = exports.ReadConcernLevel = exports.ProfilingLevel = exports.ReturnDocument = exports.SeverityLevel = exports.MongoLoggableComponent = exports.ServerApiVersion = exports.ExplainVerbosity = exports.MongoErrorLabel = exports.CursorTimeoutMode = exports.CURSOR_FLAGS = exports.Compressor = exports.AuthMechanism = exports.GSSAPICanonicalizationValue = exports.AutoEncryptionLoggerLevel = exports.BatchType = exports.UnorderedBulkOperation = exports.OrderedBulkOperation = exports.MongoClient = exports.ListIndexesCursor = exports.ListCollectionsCursor = exports.GridFSBucketWriteStream = exports.GridFSBucketReadStream = exports.GridFSBucket = exports.FindCursor = exports.ExplainableCursor = exports.Db = exports.Collection = exports.ClientSession = exports.ChangeStream = exports.CancellationToken = exports.AggregationCursor = exports.Admin = exports.AbstractCursor = exports.configureExplicitResourceManagement = exports.MongoWriteConcernError = exports.MongoUnexpectedServerResponseError = exports.MongoTransactionError = exports.MongoTopologyClosedError = exports.MongoTailableCursorError = exports.MongoSystemError = exports.MongoStalePrimaryError = exports.MongoServerSelectionError = exports.MongoServerError = void 0;
exports.MongoRuntimeError = exports.MongoParseError = exports.MongoOperationTimeoutError = exports.MongoOIDCError = exports.MongoNotConnectedError = exports.MongoNetworkTimeoutError = exports.MongoNetworkError = exports.MongoMissingDependencyError = exports.MongoMissingCredentialsError = exports.MongoKerberosError = exports.MongoInvalidArgumentError = exports.MongoGridFSStreamError = exports.MongoGridFSChunkError = exports.MongoGCPError = exports.MongoExpiredSessionError = exports.MongoError = exports.MongoDriverError = exports.MongoDecompressionError = exports.MongoCursorInUseError = exports.MongoCursorExhaustedError = exports.MongoCompatibilityError = exports.MongoClientClosedError = exports.MongoClientBulkWriteExecutionError = exports.MongoClientBulkWriteError = exports.MongoClientBulkWriteCursorError = exports.MongoChangeStreamError = exports.MongoBatchReExecutionError = exports.MongoAzureError = exports.MongoAWSError = exports.MongoAPIError = exports.ExplainableCursor = exports.ChangeStreamCursor = exports.ClientEncryption = exports.MongoBulkWriteError = exports.UUID = exports.Timestamp = exports.ObjectId = exports.MinKey = exports.MaxKey = exports.Long = exports.Int32 = exports.Double = exports.Decimal128 = exports.DBRef = exports.Code = exports.BSONType = exports.BSONSymbol = exports.BSONRegExp = exports.Binary = exports.BSON = void 0;
exports.CommandFailedEvent = exports.WriteConcern = exports.ReadPreference = exports.ReadConcern = exports.TopologyType = exports.ServerType = exports.ReadPreferenceMode = exports.ReadConcernLevel = exports.ProfilingLevel = exports.ReturnDocument = exports.SeverityLevel = exports.MongoLoggableComponent = exports.ServerApiVersion = exports.ExplainVerbosity = exports.MongoErrorLabel = exports.CursorTimeoutMode = exports.CURSOR_FLAGS = exports.Compressor = exports.AuthMechanism = exports.GSSAPICanonicalizationValue = exports.AutoEncryptionLoggerLevel = exports.BatchType = exports.UnorderedBulkOperation = exports.OrderedBulkOperation = exports.MongoClient = exports.ListIndexesCursor = exports.ListCollectionsCursor = exports.GridFSBucketWriteStream = exports.GridFSBucketReadStream = exports.GridFSBucket = exports.FindCursor = exports.Db = exports.Collection = exports.ClientSession = exports.ChangeStream = exports.CancellationToken = exports.AggregationCursor = exports.Admin = exports.AbstractCursor = exports.configureExplicitResourceManagement = exports.MongoWriteConcernError = exports.MongoUnexpectedServerResponseError = exports.MongoTransactionError = exports.MongoTopologyClosedError = exports.MongoTailableCursorError = exports.MongoSystemError = exports.MongoStalePrimaryError = exports.MongoServerSelectionError = exports.MongoServerError = exports.MongoServerClosedError = void 0;
exports.MongoClientAuthProviders = exports.MongoCryptKMSRequestNetworkTimeoutError = exports.MongoCryptInvalidArgumentError = exports.MongoCryptError = exports.MongoCryptCreateEncryptedCollectionError = exports.MongoCryptCreateDataKeyError = exports.MongoCryptAzureKMSRequestError = exports.SrvPollingEvent = exports.WaitingForSuitableServerEvent = exports.ServerSelectionSucceededEvent = exports.ServerSelectionStartedEvent = exports.ServerSelectionFailedEvent = exports.ServerSelectionEvent = exports.TopologyOpeningEvent = exports.TopologyDescriptionChangedEvent = exports.TopologyClosedEvent = exports.ServerOpeningEvent = exports.ServerHeartbeatSucceededEvent = exports.ServerHeartbeatStartedEvent = exports.ServerHeartbeatFailedEvent = exports.ServerDescriptionChangedEvent = exports.ServerClosedEvent = exports.ConnectionReadyEvent = exports.ConnectionPoolReadyEvent = exports.ConnectionPoolMonitoringEvent = exports.ConnectionPoolCreatedEvent = exports.ConnectionPoolClosedEvent = exports.ConnectionPoolClearedEvent = exports.ConnectionCreatedEvent = exports.ConnectionClosedEvent = exports.ConnectionCheckOutStartedEvent = exports.ConnectionCheckOutFailedEvent = exports.ConnectionCheckedOutEvent = exports.ConnectionCheckedInEvent = exports.CommandSucceededEvent = exports.CommandStartedEvent = void 0;

@@ -28,4 +28,2 @@ const admin_1 = require("./admin");

Object.defineProperty(exports, "Db", { enumerable: true, get: function () { return db_1.Db; } });
const explain_1 = require("./explain");
Object.defineProperty(exports, "ExplainableCursor", { enumerable: true, get: function () { return explain_1.ExplainableCursor; } });
const gridfs_1 = require("./gridfs");

@@ -68,2 +66,4 @@ Object.defineProperty(exports, "GridFSBucket", { enumerable: true, get: function () { return gridfs_1.GridFSBucket; } });

Object.defineProperty(exports, "ChangeStreamCursor", { enumerable: true, get: function () { return change_stream_cursor_1.ChangeStreamCursor; } });
var explainable_cursor_1 = require("./cursor/explainable_cursor");
Object.defineProperty(exports, "ExplainableCursor", { enumerable: true, get: function () { return explainable_cursor_1.ExplainableCursor; } });
var error_1 = require("./error");

@@ -128,4 +128,4 @@ Object.defineProperty(exports, "MongoAPIError", { enumerable: true, get: function () { return error_1.MongoAPIError; } });

Object.defineProperty(exports, "MongoErrorLabel", { enumerable: true, get: function () { return error_2.MongoErrorLabel; } });
var explain_2 = require("./explain");
Object.defineProperty(exports, "ExplainVerbosity", { enumerable: true, get: function () { return explain_2.ExplainVerbosity; } });
var explain_1 = require("./explain");
Object.defineProperty(exports, "ExplainVerbosity", { enumerable: true, get: function () { return explain_1.ExplainVerbosity; } });
var mongo_client_2 = require("./mongo_client");

@@ -132,0 +132,0 @@ Object.defineProperty(exports, "ServerApiVersion", { enumerable: true, get: function () { return mongo_client_2.ServerApiVersion; } });

@@ -10,2 +10,3 @@ "use strict";

const client_metadata_1 = require("./cmap/handshake/client_metadata");
const responses_1 = require("./cmap/wire_protocol/responses");
const connection_string_1 = require("./connection_string");

@@ -20,3 +21,3 @@ const constants_1 = require("./constants");

const execute_operation_1 = require("./operations/execute_operation");
const run_command_1 = require("./operations/run_command");
const operation_1 = require("./operations/operation");
const read_preference_1 = require("./read_preference");

@@ -364,3 +365,25 @@ const resource_management_1 = require("./resource_management");

try {
await (0, execute_operation_1.executeOperation)(this, new run_command_1.RunAdminCommandOperation({ endSessions }, { readPreference: read_preference_1.ReadPreference.primaryPreferred, noResponse: true }));
class EndSessionsOperation extends operation_1.AbstractOperation {
constructor() {
super(...arguments);
this.ns = utils_1.MongoDBNamespace.fromString('admin.$cmd');
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
}
buildCommand(_connection, _session) {
return {
endSessions
};
}
buildOptions(timeoutContext) {
return {
timeoutContext,
readPreference: read_preference_1.ReadPreference.primaryPreferred,
noResponse: true
};
}
get commandName() {
return 'endSessions';
}
}
await (0, execute_operation_1.executeOperation)(this, new EndSessionsOperation());
}

@@ -367,0 +390,0 @@ catch (error) {

@@ -17,2 +17,3 @@ "use strict";

super(undefined, { ...options, dbName: ns.db });
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.CursorResponse;
this.options = { ...options };

@@ -34,6 +35,3 @@ // Covers when ns.collection is null, undefined or the empty string, use DB_AGGREGATE_COLLECTION

}
if (this.hasWriteStage) {
this.trySecondaryWrite = true;
}
else {
if (!this.hasWriteStage) {
delete this.options.writeConcern;

@@ -47,2 +45,3 @@ }

}
this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? responses_1.ExplainedCursorResponse : responses_1.CursorResponse;
}

@@ -58,5 +57,5 @@ get commandName() {

}
async execute(server, session, timeoutContext) {
buildCommandDocument(connection) {
const options = this.options;
const serverWireVersion = (0, utils_1.maxWireVersion)(server);
const serverWireVersion = (0, utils_1.maxWireVersion)(connection);
const command = { aggregate: this.target, pipeline: this.pipeline };

@@ -90,4 +89,7 @@ if (this.hasWriteStage && serverWireVersion < MIN_WIRE_VERSION_$OUT_READ_CONCERN_SUPPORT) {

}
return await super.executeCommand(server, session, command, timeoutContext, this.explain ? responses_1.ExplainedCursorResponse : responses_1.CursorResponse);
return command;
}
handleOk(response) {
return response;
}
}

@@ -94,0 +96,0 @@ exports.AggregateOperation = AggregateOperation;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientBulkWriteOperation = void 0;
const beta_1 = require("../../beta");
const responses_1 = require("../../cmap/wire_protocol/responses");

@@ -19,2 +18,3 @@ const utils_1 = require("../../utils");

super(undefined, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.ClientBulkWriteCursorResponse;
this.commandBuilder = commandBuilder;

@@ -30,45 +30,12 @@ this.options = options;

}
/**
* Execute the command. Superclass will handle write concern, etc.
* @param server - The server.
* @param session - The session.
* @returns The response.
*/
async execute(server, session, timeoutContext) {
let command;
if (server.description.type === beta_1.ServerType.LoadBalancer) {
if (session) {
let connection;
if (!session.pinnedConnection) {
// Checkout a connection to build the command.
connection = await server.pool.checkOut({ timeoutContext });
// Pin the connection to the session so it get used to execute the command and we do not
// perform a double check-in/check-out.
session.pin(connection);
}
else {
connection = session.pinnedConnection;
}
command = this.commandBuilder.buildBatch(connection.hello?.maxMessageSizeBytes, connection.hello?.maxWriteBatchSize, connection.hello?.maxBsonObjectSize);
}
else {
throw new beta_1.MongoClientBulkWriteExecutionError('Session provided to the client bulk write operation must be present.');
}
}
else {
// At this point we have a server and the auto connect code has already
// run in executeOperation, so the server description will be populated.
// We can use that to build the command.
if (!server.description.maxWriteBatchSize ||
!server.description.maxMessageSizeBytes ||
!server.description.maxBsonObjectSize) {
throw new beta_1.MongoClientBulkWriteExecutionError('In order to execute a client bulk write, both maxWriteBatchSize, maxMessageSizeBytes and maxBsonObjectSize must be provided by the servers hello response.');
}
command = this.commandBuilder.buildBatch(server.description.maxMessageSizeBytes, server.description.maxWriteBatchSize, server.description.maxBsonObjectSize);
}
// Check after the batch is built if we cannot retry it and override the option.
handleOk(response) {
return response;
}
buildCommandDocument(connection, _session) {
const command = this.commandBuilder.buildBatch(connection.description.maxMessageSizeBytes, connection.description.maxWriteBatchSize, connection.description.maxBsonObjectSize);
// Check _after_ the batch is built if we cannot retry it and override the option.
if (!this.canRetryWrite) {
this.options.willRetryWrite = false;
}
return await super.executeCommand(server, session, command, timeoutContext, responses_1.ClientBulkWriteCursorResponse);
return command;
}

@@ -75,0 +42,0 @@ }

@@ -7,3 +7,2 @@ "use strict";

const read_concern_1 = require("../read_concern");
const server_selection_1 = require("../sdam/server_selection");
const utils_1 = require("../utils");

@@ -46,5 +45,4 @@ const write_concern_1 = require("../write_concern");

}
async executeCommand(server, session, cmd, timeoutContext, responseType) {
this.server = server;
const options = {
buildOptions(timeoutContext) {
return {
...this.options,

@@ -54,27 +52,26 @@ ...this.bsonOptions,

readPreference: this.readPreference,
session
session: this.session
};
const serverWireVersion = (0, utils_1.maxWireVersion)(server);
}
buildCommand(connection, session) {
const command = this.buildCommandDocument(connection, session);
const inTransaction = this.session && this.session.inTransaction();
if (this.readConcern && (0, utils_1.commandSupportsReadConcern)(cmd) && !inTransaction) {
Object.assign(cmd, { readConcern: this.readConcern });
if (this.readConcern && (0, utils_1.commandSupportsReadConcern)(command) && !inTransaction) {
Object.assign(command, { readConcern: this.readConcern });
}
if (this.trySecondaryWrite && serverWireVersion < server_selection_1.MIN_SECONDARY_WRITE_WIRE_VERSION) {
options.omitReadPreference = true;
}
if (this.writeConcern && this.hasAspect(operation_1.Aspect.WRITE_OPERATION) && !inTransaction) {
write_concern_1.WriteConcern.apply(cmd, this.writeConcern);
write_concern_1.WriteConcern.apply(command, this.writeConcern);
}
if (options.collation &&
typeof options.collation === 'object' &&
if (this.options.collation &&
typeof this.options.collation === 'object' &&
!this.hasAspect(operation_1.Aspect.SKIP_COLLATION)) {
Object.assign(cmd, { collation: options.collation });
Object.assign(command, { collation: this.options.collation });
}
if (typeof options.maxTimeMS === 'number') {
cmd.maxTimeMS = options.maxTimeMS;
if (typeof this.options.maxTimeMS === 'number') {
command.maxTimeMS = this.options.maxTimeMS;
}
if (this.hasAspect(operation_1.Aspect.EXPLAINABLE) && this.explain) {
cmd = (0, explain_1.decorateWithExplain)(cmd, this.explain);
return (0, explain_1.decorateWithExplain)(command, this.explain);
}
return await server.command(this.ns, cmd, options, responseType);
return command;
}

@@ -81,0 +78,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CountOperation = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const command_1 = require("./command");

@@ -10,2 +11,3 @@ const operation_1 = require("./operation");

super({ s: { namespace: namespace } }, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;

@@ -18,3 +20,3 @@ this.collectionName = namespace.collection;

}
async execute(server, session, timeoutContext) {
buildCommandDocument(_connection, _session) {
const options = this.options;

@@ -37,5 +39,7 @@ const cmd = {

}
const result = await super.executeCommand(server, session, cmd, timeoutContext);
return result ? result.n : 0;
return cmd;
}
handleOk(response) {
return response.getNumber('n') ?? 0;
}
}

@@ -42,0 +46,0 @@ exports.CountOperation = CountOperation;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CreateCollectionOperation = void 0;
exports.createCollections = createCollections;
const constants_1 = require("../cmap/wire_protocol/constants");
const responses_1 = require("../cmap/wire_protocol/responses");
const collection_1 = require("../collection");
const error_1 = require("../error");
const timeout_1 = require("../timeout");
const utils_1 = require("../utils");
const command_1 = require("./command");
const execute_operation_1 = require("./execute_operation");
const indexes_1 = require("./indexes");

@@ -40,2 +45,3 @@ const operation_1 = require("./operation");

super(db, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;

@@ -48,58 +54,59 @@ this.db = db;

}
async execute(server, session, timeoutContext) {
const db = this.db;
const name = this.name;
const options = this.options;
const encryptedFields = options.encryptedFields ??
db.client.s.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
if (encryptedFields) {
// Creating a QE collection required min server of 7.0.0
// TODO(NODE-5353): Get wire version information from connection.
if (!server.loadBalanced &&
server.description.maxWireVersion < constants_1.MIN_SUPPORTED_QE_WIRE_VERSION) {
throw new error_1.MongoCompatibilityError(`${INVALID_QE_VERSION} The minimum server version required is ${constants_1.MIN_SUPPORTED_QE_SERVER_VERSION}`);
buildCommandDocument(_connection, _session) {
const isOptionValid = ([k, v]) => v != null && typeof v !== 'function' && !ILLEGAL_COMMAND_FIELDS.has(k);
return {
create: this.name,
...Object.fromEntries(Object.entries(this.options).filter(isOptionValid))
};
}
handleOk(_response) {
return new collection_1.Collection(this.db, this.name, this.options);
}
}
exports.CreateCollectionOperation = CreateCollectionOperation;
async function createCollections(db, name, options) {
const timeoutContext = timeout_1.TimeoutContext.create({
session: options.session,
serverSelectionTimeoutMS: db.client.s.options.serverSelectionTimeoutMS,
waitQueueTimeoutMS: db.client.s.options.waitQueueTimeoutMS,
timeoutMS: options.timeoutMS
});
const encryptedFields = options.encryptedFields ??
db.client.s.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
if (encryptedFields) {
class CreateSupportingFLEv2CollectionOperation extends CreateCollectionOperation {
buildCommandDocument(connection, session) {
if (!connection.description.loadBalanced &&
(0, utils_1.maxWireVersion)(connection) < constants_1.MIN_SUPPORTED_QE_WIRE_VERSION) {
throw new error_1.MongoCompatibilityError(`${INVALID_QE_VERSION} The minimum server version required is ${constants_1.MIN_SUPPORTED_QE_SERVER_VERSION}`);
}
return super.buildCommandDocument(connection, session);
}
// Create auxilliary collections for queryable encryption support.
const escCollection = encryptedFields.escCollection ?? `enxcol_.${name}.esc`;
const ecocCollection = encryptedFields.ecocCollection ?? `enxcol_.${name}.ecoc`;
for (const collectionName of [escCollection, ecocCollection]) {
const createOp = new CreateCollectionOperation(db, collectionName, {
clusteredIndex: {
key: { _id: 1 },
unique: true
}
});
await createOp.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
}
if (!options.encryptedFields) {
this.options = { ...this.options, encryptedFields };
}
}
const coll = await this.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
if (encryptedFields) {
// Create the required index for queryable encryption support.
const createIndexOp = indexes_1.CreateIndexesOperation.fromIndexSpecification(db, name, { __safeContent__: 1 }, {});
await createIndexOp.execute(server, session, timeoutContext);
// Create auxilliary collections for queryable encryption support.
const escCollection = encryptedFields.escCollection ?? `enxcol_.${name}.esc`;
const ecocCollection = encryptedFields.ecocCollection ?? `enxcol_.${name}.ecoc`;
for (const collectionName of [escCollection, ecocCollection]) {
const createOp = new CreateSupportingFLEv2CollectionOperation(db, collectionName, {
clusteredIndex: {
key: { _id: 1 },
unique: true
},
session: options.session
});
await (0, execute_operation_1.executeOperation)(db.client, createOp, timeoutContext);
}
return coll;
}
async executeWithoutEncryptedFieldsCheck(server, session, timeoutContext) {
const db = this.db;
const name = this.name;
const options = this.options;
const cmd = { create: name };
for (const n in options) {
if (options[n] != null &&
typeof options[n] !== 'function' &&
!ILLEGAL_COMMAND_FIELDS.has(n)) {
cmd[n] = options[n];
}
if (!options.encryptedFields) {
options = { ...options, encryptedFields };
}
// otherwise just execute the command
await super.executeCommand(server, session, cmd, timeoutContext);
return new collection_1.Collection(db, name, options);
}
const coll = await (0, execute_operation_1.executeOperation)(db.client, new CreateCollectionOperation(db, name, options), timeoutContext);
if (encryptedFields) {
// Create the required index for queryable encryption support.
const createIndexOp = indexes_1.CreateIndexesOperation.fromIndexSpecification(db, name, { __safeContent__: 1 }, { session: options.session });
await (0, execute_operation_1.executeOperation)(db.client, createIndexOp, timeoutContext);
}
return coll;
}
exports.CreateCollectionOperation = CreateCollectionOperation;
(0, operation_1.defineAspects)(CreateCollectionOperation, [operation_1.Aspect.WRITE_OPERATION]);
//# sourceMappingURL=create_collection.js.map

@@ -5,2 +5,3 @@ "use strict";

exports.makeDeleteStatement = makeDeleteStatement;
const responses_1 = require("../cmap/wire_protocol/responses");
const error_1 = require("../error");

@@ -13,2 +14,3 @@ const command_1 = require("./command");

super(undefined, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;

@@ -27,4 +29,4 @@ this.ns = ns;

}
async execute(server, session, timeoutContext) {
const options = this.options ?? {};
buildCommandDocument(_connection, _session) {
const options = this.options;
const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;

@@ -51,4 +53,3 @@ const command = {

}
const res = await super.executeCommand(server, session, command, timeoutContext);
return res;
return command;
}

@@ -58,7 +59,8 @@ }

class DeleteOneOperation extends DeleteOperation {
constructor(collection, filter, options) {
super(collection.s.namespace, [makeDeleteStatement(filter, { ...options, limit: 1 })], options);
constructor(ns, filter, options) {
super(ns, [makeDeleteStatement(filter, { ...options, limit: 1 })], options);
}
async execute(server, session, timeoutContext) {
const res = await super.execute(server, session, timeoutContext);
handleOk(response) {
const res = super.handleOk(response);
// @ts-expect-error Explain commands have broken TS
if (this.explain)

@@ -78,7 +80,8 @@ return res;

class DeleteManyOperation extends DeleteOperation {
constructor(collection, filter, options) {
super(collection.s.namespace, [makeDeleteStatement(filter, options)], options);
constructor(ns, filter, options) {
super(ns, [makeDeleteStatement(filter, options)], options);
}
async execute(server, session, timeoutContext) {
const res = await super.execute(server, session, timeoutContext);
handleOk(response) {
const res = super.handleOk(response);
// @ts-expect-error Explain commands have broken TS
if (this.explain)

@@ -85,0 +88,0 @@ return res;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DistinctOperation = void 0;
const utils_1 = require("../utils");
const responses_1 = require("../cmap/wire_protocol/responses");
const command_1 = require("./command");

@@ -22,2 +22,3 @@ const operation_1 = require("./operation");

super(collection, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options ?? {};

@@ -31,33 +32,24 @@ this.collection = collection;

}
async execute(server, session, timeoutContext) {
const coll = this.collection;
const key = this.key;
const query = this.query;
const options = this.options;
// Distinct command
const cmd = {
distinct: coll.collectionName,
key: key,
query: query
buildCommandDocument(_connection) {
const command = {
distinct: this.collection.collectionName,
key: this.key,
query: this.query
};
// Add maxTimeMS if defined
if (typeof options.maxTimeMS === 'number') {
cmd.maxTimeMS = options.maxTimeMS;
}
// we check for undefined specifically here to allow falsy values
// eslint-disable-next-line no-restricted-syntax
if (typeof options.comment !== 'undefined') {
cmd.comment = options.comment;
if (this.options.comment !== undefined) {
command.comment = this.options.comment;
}
if (options.hint != null) {
cmd.hint = options.hint;
if (this.options.hint != null) {
command.hint = this.options.hint;
}
// Do we have a readConcern specified
(0, utils_1.decorateWithReadConcern)(cmd, coll, options);
// Have we specified collation
(0, utils_1.decorateWithCollation)(cmd, coll, options);
const result = await super.executeCommand(server, session, cmd, timeoutContext);
// @ts-expect-error: Explain always returns a document
return this.explain ? result : result.values;
return command;
}
handleOk(response) {
if (this.explain) {
return response.toObject(this.bsonOptions);
}
return response.toObject(this.bsonOptions).values;
}
}

@@ -64,0 +56,0 @@ exports.DistinctOperation = DistinctOperation;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DropDatabaseOperation = exports.DropCollectionOperation = void 0;
exports.dropCollections = dropCollections;
const __1 = require("..");
const responses_1 = require("../cmap/wire_protocol/responses");
const abstract_cursor_1 = require("../cursor/abstract_cursor");
const error_1 = require("../error");
const timeout_1 = require("../timeout");
const command_1 = require("./command");
const execute_operation_1 = require("./execute_operation");
const operation_1 = require("./operation");

@@ -11,3 +17,3 @@ /** @internal */

super(db, options);
this.db = db;
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;

@@ -19,43 +25,52 @@ this.name = name;

}
async execute(server, session, timeoutContext) {
const db = this.db;
const options = this.options;
const name = this.name;
const encryptedFieldsMap = db.client.s.options.autoEncryption?.encryptedFieldsMap;
let encryptedFields = options.encryptedFields ?? encryptedFieldsMap?.[`${db.databaseName}.${name}`];
if (!encryptedFields && encryptedFieldsMap) {
// If the MongoClient was configured with an encryptedFieldsMap,
// and no encryptedFields config was available in it or explicitly
// passed as an argument, the spec tells us to look one up using
// listCollections().
const listCollectionsResult = await db
.listCollections({ name }, { nameOnly: false })
.toArray();
encryptedFields = listCollectionsResult?.[0]?.options?.encryptedFields;
}
if (encryptedFields) {
const escCollection = encryptedFields.escCollection || `enxcol_.${name}.esc`;
const ecocCollection = encryptedFields.ecocCollection || `enxcol_.${name}.ecoc`;
for (const collectionName of [escCollection, ecocCollection]) {
// Drop auxilliary collections, ignoring potential NamespaceNotFound errors.
const dropOp = new DropCollectionOperation(db, collectionName);
try {
await dropOp.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
buildCommandDocument(_connection, _session) {
return { drop: this.name };
}
handleOk(_response) {
return true;
}
}
exports.DropCollectionOperation = DropCollectionOperation;
async function dropCollections(db, name, options) {
const timeoutContext = timeout_1.TimeoutContext.create({
session: options.session,
serverSelectionTimeoutMS: db.client.s.options.serverSelectionTimeoutMS,
waitQueueTimeoutMS: db.client.s.options.waitQueueTimeoutMS,
timeoutMS: options.timeoutMS
});
const encryptedFieldsMap = db.client.s.options.autoEncryption?.encryptedFieldsMap;
let encryptedFields = options.encryptedFields ?? encryptedFieldsMap?.[`${db.databaseName}.${name}`];
if (!encryptedFields && encryptedFieldsMap) {
// If the MongoClient was configured with an encryptedFieldsMap,
// and no encryptedFields config was available in it or explicitly
// passed as an argument, the spec tells us to look one up using
// listCollections().
const listCollectionsResult = await db
.listCollections({ name }, {
nameOnly: false,
session: options.session,
timeoutContext: new abstract_cursor_1.CursorTimeoutContext(timeoutContext, Symbol())
})
.toArray();
encryptedFields = listCollectionsResult?.[0]?.options?.encryptedFields;
}
if (encryptedFields) {
const escCollection = encryptedFields.escCollection || `enxcol_.${name}.esc`;
const ecocCollection = encryptedFields.ecocCollection || `enxcol_.${name}.ecoc`;
for (const collectionName of [escCollection, ecocCollection]) {
// Drop auxilliary collections, ignoring potential NamespaceNotFound errors.
const dropOp = new DropCollectionOperation(db, collectionName, options);
try {
await (0, execute_operation_1.executeOperation)(db.client, dropOp, timeoutContext);
}
catch (err) {
if (!(err instanceof __1.MongoServerError) ||
err.code !== error_1.MONGODB_ERROR_CODES.NamespaceNotFound) {
throw err;
}
catch (err) {
if (!(err instanceof error_1.MongoServerError) ||
err.code !== error_1.MONGODB_ERROR_CODES.NamespaceNotFound) {
throw err;
}
}
}
}
return await this.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
}
async executeWithoutEncryptedFieldsCheck(server, session, timeoutContext) {
await super.executeCommand(server, session, { drop: this.name }, timeoutContext);
return true;
}
return await (0, execute_operation_1.executeOperation)(db.client, new DropCollectionOperation(db, name, options), timeoutContext);
}
exports.DropCollectionOperation = DropCollectionOperation;
/** @internal */

@@ -65,2 +80,3 @@ class DropDatabaseOperation extends command_1.CommandOperation {

super(db, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;

@@ -71,4 +87,6 @@ }

}
async execute(server, session, timeoutContext) {
await super.executeCommand(server, session, { dropDatabase: 1 }, timeoutContext);
buildCommandDocument(_connection, _session) {
return { dropDatabase: 1 };
}
handleOk(_response) {
return true;

@@ -75,0 +93,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EstimatedDocumentCountOperation = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const command_1 = require("./command");

@@ -10,2 +11,3 @@ const operation_1 = require("./operation");

super(collection, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;

@@ -17,3 +19,3 @@ this.collectionName = collection.collectionName;

}
async execute(server, session, timeoutContext) {
buildCommandDocument(_connection, _session) {
const cmd = { count: this.collectionName };

@@ -28,5 +30,7 @@ if (typeof this.options.maxTimeMS === 'number') {

}
const response = await super.executeCommand(server, session, cmd, timeoutContext);
return response?.n || 0;
return cmd;
}
handleOk(response) {
return response.getNumber('n') ?? 0;
}
}

@@ -33,0 +37,0 @@ exports.EstimatedDocumentCountOperation = EstimatedDocumentCountOperation;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.executeOperation = executeOperation;
exports.autoConnect = autoConnect;
const error_1 = require("../error");

@@ -9,2 +10,3 @@ const read_preference_1 = require("../read_preference");

const utils_1 = require("../utils");
const aggregate_1 = require("./aggregate");
const operation_1 = require("./operation");

@@ -58,2 +60,3 @@ const MMAPv1_RETRY_WRITES_ERROR_CODE = error_1.MONGODB_ERROR_CODES.IllegalOperation;

}
operation.session ??= session;
const readPreference = operation.readPreference ?? read_preference_1.ReadPreference.primary;

@@ -139,3 +142,3 @@ const inTransaction = !!session?.inTransaction();

}
else if (operation.trySecondaryWrite) {
else if (operation instanceof aggregate_1.AggregateOperation && operation.hasWriteStage) {
// If operation should try to write to secondary use the custom server selector

@@ -186,4 +189,5 @@ // otherwise provide the read preference.

throw previousOperationError;
if (hasReadAspect && !(0, error_1.isRetryableReadError)(previousOperationError))
if (hasReadAspect && !(0, error_1.isRetryableReadError)(previousOperationError)) {
throw previousOperationError;
}
if (previousOperationError instanceof error_1.MongoNetworkError &&

@@ -206,2 +210,3 @@ operation.hasAspect(operation_1.Aspect.CURSOR_CREATING) &&

}
operation.server = server;
try {

@@ -212,3 +217,9 @@ // If tries > 0 and we are command batching we need to reset the batch.

}
return await operation.execute(server, session, timeoutContext);
try {
const result = await server.command(operation, timeoutContext);
return operation.handleOk(result);
}
catch (error) {
return operation.handleError(error);
}
}

@@ -215,0 +226,0 @@ catch (operationError) {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FindOneAndUpdateOperation = exports.FindOneAndReplaceOperation = exports.FindOneAndDeleteOperation = exports.FindAndModifyOperation = exports.ReturnDocument = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const error_1 = require("../error");

@@ -27,4 +28,17 @@ const read_preference_1 = require("../read_preference");

super(collection, options);
this.options = options ?? {};
this.cmdBase = {
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;
// force primary read preference
this.readPreference = read_preference_1.ReadPreference.primary;
this.collection = collection;
this.query = query;
}
get commandName() {
return 'findAndModify';
}
buildCommandDocument(_connection, _session) {
const options = this.options;
const command = {
findAndModify: this.collection.collectionName,
query: this.query,
remove: false,

@@ -37,16 +51,16 @@ new: false,

if (sort) {
this.cmdBase.sort = sort;
command.sort = sort;
}
if (options.projection) {
this.cmdBase.fields = options.projection;
command.fields = options.projection;
}
if (options.maxTimeMS) {
this.cmdBase.maxTimeMS = options.maxTimeMS;
command.maxTimeMS = options.maxTimeMS;
}
// Decorate the findAndModify command with the write Concern
if (options.writeConcern) {
this.cmdBase.writeConcern = options.writeConcern;
command.writeConcern = options.writeConcern;
}
if (options.let) {
this.cmdBase.let = options.let;
command.let = options.let;
}

@@ -56,36 +70,18 @@ // we check for undefined specifically here to allow falsy values

if (options.comment !== undefined) {
this.cmdBase.comment = options.comment;
command.comment = options.comment;
}
// force primary read preference
this.readPreference = read_preference_1.ReadPreference.primary;
this.collection = collection;
this.query = query;
}
get commandName() {
return 'findAndModify';
}
async execute(server, session, timeoutContext) {
const coll = this.collection;
const query = this.query;
const options = { ...this.options, ...this.bsonOptions };
// Create findAndModify command object
const cmd = {
findAndModify: coll.collectionName,
query: query,
...this.cmdBase
};
(0, utils_1.decorateWithCollation)(cmd, coll, options);
(0, utils_1.decorateWithCollation)(command, this.collection, options);
if (options.hint) {
// TODO: once this method becomes a CommandOperation we will have the server
// in place to check.
const unacknowledgedWrite = this.writeConcern?.w === 0;
if (unacknowledgedWrite || (0, utils_1.maxWireVersion)(server) < 8) {
if (unacknowledgedWrite) {
throw new error_1.MongoCompatibilityError('The current topology does not support a hint on findAndModify commands');
}
cmd.hint = options.hint;
command.hint = options.hint;
}
// Execute the command
const result = await super.executeCommand(server, session, cmd, timeoutContext);
return options.includeResultMetadata ? result : (result.value ?? null);
return command;
}
handleOk(response) {
const result = super.handleOk(response);
return this.options.includeResultMetadata ? result : (result.value ?? null);
}
}

@@ -101,4 +97,8 @@ exports.FindAndModifyOperation = FindAndModifyOperation;

super(collection, filter, options);
this.cmdBase.remove = true;
}
buildCommandDocument(connection, session) {
const document = super.buildCommandDocument(connection, session);
document.remove = true;
return document;
}
}

@@ -119,5 +119,10 @@ exports.FindOneAndDeleteOperation = FindOneAndDeleteOperation;

super(collection, filter, options);
this.cmdBase.update = replacement;
configureFindAndModifyCmdBaseUpdateOpts(this.cmdBase, options);
this.replacement = replacement;
}
buildCommandDocument(connection, session) {
const document = super.buildCommandDocument(connection, session);
document.update = this.replacement;
configureFindAndModifyCmdBaseUpdateOpts(document, this.options);
return document;
}
}

@@ -138,7 +143,13 @@ exports.FindOneAndReplaceOperation = FindOneAndReplaceOperation;

super(collection, filter, options);
this.cmdBase.update = update;
configureFindAndModifyCmdBaseUpdateOpts(this.cmdBase, options);
if (options.arrayFilters) {
this.cmdBase.arrayFilters = options.arrayFilters;
this.update = update;
this.options = options;
}
buildCommandDocument(connection, session) {
const document = super.buildCommandDocument(connection, session);
document.update = this.update;
configureFindAndModifyCmdBaseUpdateOpts(document, this.options);
if (this.options.arrayFilters) {
document.arrayFilters = this.options.arrayFilters;
}
return document;
}

@@ -145,0 +156,0 @@ }

@@ -6,4 +6,2 @@ "use strict";

const error_1 = require("../error");
const explain_1 = require("../explain");
const read_concern_1 = require("../read_concern");
const sort_1 = require("../sort");

@@ -17,2 +15,3 @@ const utils_1 = require("../utils");

super(undefined, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.CursorResponse;
this.options = { ...options };

@@ -26,2 +25,3 @@ delete this.options.writeConcern;

this.filter = filter != null && filter._bsontype === 'ObjectId' ? { _id: filter } : filter;
this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? responses_1.ExplainedCursorResponse : responses_1.CursorResponse;
}

@@ -31,18 +31,17 @@ get commandName() {

}
async execute(server, session, timeoutContext) {
this.server = server;
const options = this.options;
let findCommand = makeFindCommand(this.ns, this.filter, options);
if (this.explain) {
(0, explain_1.validateExplainTimeoutOptions)(this.options, this.explain);
findCommand = (0, explain_1.decorateWithExplain)(findCommand, this.explain);
}
return await server.command(this.ns, findCommand, {
buildOptions(timeoutContext) {
return {
...this.options,
...this.bsonOptions,
documentsReturnedIn: 'firstBatch',
session,
session: this.session,
timeoutContext
}, this.explain ? responses_1.ExplainedCursorResponse : responses_1.CursorResponse);
};
}
handleOk(response) {
return response;
}
buildCommandDocument() {
return makeFindCommand(this.ns, this.filter, this.options);
}
}

@@ -87,11 +86,13 @@ exports.FindOperation = FindOperation;

if (options.batchSize < 0) {
if (options.limit &&
options.limit !== 0 &&
Math.abs(options.batchSize) < Math.abs(options.limit)) {
findCommand.limit = -options.batchSize;
}
findCommand.singleBatch = true;
findCommand.limit = -options.batchSize;
}
else {
findCommand.batchSize = options.batchSize;
if (options.batchSize === options.limit) {
// Spec dictates that if these are equal the batchSize should be one more than the
// limit to avoid leaving the cursor open.
findCommand.batchSize = options.batchSize + 1;
}
else {
findCommand.batchSize = options.batchSize;
}
}

@@ -107,9 +108,2 @@ }

}
if (typeof options.maxTimeMS === 'number') {
findCommand.maxTimeMS = options.maxTimeMS;
}
const readConcern = read_concern_1.ReadConcern.fromOptions(options);
if (readConcern) {
findCommand.readConcern = readConcern.toJSON();
}
if (options.max) {

@@ -145,5 +139,2 @@ findCommand.max = options.max;

}
if (options.collation) {
findCommand.collation = options.collation;
}
if (typeof options.allowDiskUse === 'boolean') {

@@ -150,0 +141,0 @@ findCommand.allowDiskUse = options.allowDiskUse;

@@ -12,2 +12,3 @@ "use strict";

super(options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.CursorResponse;
this.options = options;

@@ -21,10 +22,3 @@ this.ns = ns;

}
/**
* Although there is a server already associated with the get more operation, the signature
* for execute passes a server so we will just use that one.
*/
async execute(server, _session, timeoutContext) {
if (server !== this.server) {
throw new error_1.MongoRuntimeError('Getmore must run on the same server operation began on');
}
buildCommand(connection) {
if (this.cursorId == null || this.cursorId.isZero()) {

@@ -51,6 +45,9 @@ throw new error_1.MongoRuntimeError('Unable to iterate cursor with no id');

// eslint-disable-next-line no-restricted-syntax
if (this.options.comment !== undefined && (0, utils_1.maxWireVersion)(server) >= 9) {
if (this.options.comment !== undefined && (0, utils_1.maxWireVersion)(connection) >= 9) {
getMoreCmd.comment = this.options.comment;
}
const commandOptions = {
return getMoreCmd;
}
buildOptions(timeoutContext) {
return {
returnFieldSelector: null,

@@ -61,4 +58,6 @@ documentsReturnedIn: 'nextBatch',

};
return await server.command(this.ns, getMoreCmd, commandOptions, responses_1.CursorResponse);
}
handleOk(response) {
return response;
}
}

@@ -65,0 +64,0 @@ exports.GetMoreOperation = GetMoreOperation;

@@ -84,3 +84,6 @@ "use strict";

super(parent, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options ?? {};
// collation is set on each index, it should not be defined at the root
this.options.collation = undefined;
this.collectionName = collectionName;

@@ -98,2 +101,3 @@ this.indexes = indexes.map((userIndex) => {

});
this.ns = parent.s.namespace;
}

@@ -111,6 +115,6 @@ static fromIndexDescriptionArray(parent, collectionName, indexes, options) {

}
async execute(server, session, timeoutContext) {
buildCommandDocument(connection) {
const options = this.options;
const indexes = this.indexes;
const serverWireVersion = (0, utils_1.maxWireVersion)(server);
const serverWireVersion = (0, utils_1.maxWireVersion)(connection);
const cmd = { createIndexes: this.collectionName, indexes };

@@ -123,6 +127,6 @@ if (options.commitQuorum != null) {

}
// collation is set on each index, it should not be defined at the root
this.options.collation = undefined;
await super.executeCommand(server, session, cmd, timeoutContext);
const indexNames = indexes.map(index => index.name || '');
return cmd;
}
handleOk(_response) {
const indexNames = this.indexes.map(index => index.name || '');
return indexNames;

@@ -136,5 +140,7 @@ }

super(collection, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options ?? {};
this.collection = collection;
this.indexName = indexName;
this.ns = collection.fullNamespace;
}

@@ -144,5 +150,4 @@ get commandName() {

}
async execute(server, session, timeoutContext) {
const cmd = { dropIndexes: this.collection.collectionName, index: this.indexName };
return await super.executeCommand(server, session, cmd, timeoutContext);
buildCommandDocument(_connection) {
return { dropIndexes: this.collection.collectionName, index: this.indexName };
}

@@ -155,2 +160,3 @@ }

super(collection, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.CursorResponse;
this.options = { ...options };

@@ -163,4 +169,4 @@ delete this.options.writeConcern;

}
async execute(server, session, timeoutContext) {
const serverWireVersion = (0, utils_1.maxWireVersion)(server);
buildCommandDocument(connection) {
const serverWireVersion = (0, utils_1.maxWireVersion)(connection);
const cursor = this.options.batchSize ? { batchSize: this.options.batchSize } : {};

@@ -173,4 +179,7 @@ const command = { listIndexes: this.collectionNamespace.collection, cursor };

}
return await super.executeCommand(server, session, command, timeoutContext, responses_1.CursorResponse);
return command;
}
handleOk(response) {
return response;
}
}

@@ -177,0 +186,0 @@ exports.ListIndexesOperation = ListIndexesOperation;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InsertManyOperation = exports.InsertOneOperation = exports.InsertOperation = void 0;
exports.InsertOneOperation = exports.InsertOperation = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const error_1 = require("../error");
const utils_1 = require("../utils");
const write_concern_1 = require("../write_concern");
const bulk_write_1 = require("./bulk_write");
const command_1 = require("./command");

@@ -14,2 +13,3 @@ const operation_1 = require("./operation");

super(undefined, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = { ...options, checkKeys: options.checkKeys ?? false };

@@ -22,3 +22,3 @@ this.ns = ns;

}
async execute(server, session, timeoutContext) {
buildCommandDocument(_connection, _session) {
const options = this.options ?? {};

@@ -39,3 +39,3 @@ const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;

}
return await super.executeCommand(server, session, command, timeoutContext);
return command;
}

@@ -46,6 +46,6 @@ }

constructor(collection, doc, options) {
super(collection.s.namespace, (0, utils_1.maybeAddIdToDocuments)(collection, [doc], options), options);
super(collection.s.namespace, [(0, utils_1.maybeAddIdToDocuments)(collection, doc, options)], options);
}
async execute(server, session, timeoutContext) {
const res = await super.execute(server, session, timeoutContext);
handleOk(response) {
const res = super.handleOk(response);
if (res.code)

@@ -64,43 +64,4 @@ throw new error_1.MongoServerError(res);

exports.InsertOneOperation = InsertOneOperation;
/** @internal */
class InsertManyOperation extends operation_1.AbstractOperation {
constructor(collection, docs, options) {
super(options);
if (!Array.isArray(docs)) {
throw new error_1.MongoInvalidArgumentError('Argument "docs" must be an array of documents');
}
this.options = options;
this.collection = collection;
this.docs = docs;
}
get commandName() {
return 'insert';
}
async execute(server, session, timeoutContext) {
const coll = this.collection;
const options = { ...this.options, ...this.bsonOptions, readPreference: this.readPreference };
const writeConcern = write_concern_1.WriteConcern.fromOptions(options);
const bulkWriteOperation = new bulk_write_1.BulkWriteOperation(coll, this.docs.map(document => ({
insertOne: { document }
})), options);
try {
const res = await bulkWriteOperation.execute(server, session, timeoutContext);
return {
acknowledged: writeConcern?.w !== 0,
insertedCount: res.insertedCount,
insertedIds: res.insertedIds
};
}
catch (err) {
if (err && err.message === 'Operation must be an object with an operation key') {
throw new error_1.MongoInvalidArgumentError('Collection.insertMany() cannot be called with an array that has null/undefined values');
}
throw err;
}
}
}
exports.InsertManyOperation = InsertManyOperation;
(0, operation_1.defineAspects)(InsertOperation, [operation_1.Aspect.RETRYABLE, operation_1.Aspect.WRITE_OPERATION]);
(0, operation_1.defineAspects)(InsertOneOperation, [operation_1.Aspect.RETRYABLE, operation_1.Aspect.WRITE_OPERATION]);
(0, operation_1.defineAspects)(InsertManyOperation, [operation_1.Aspect.WRITE_OPERATION]);
//# sourceMappingURL=insert.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.KillCursorsOperation = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const error_1 = require("../error");
const utils_1 = require("../utils");
const operation_1 = require("./operation");

@@ -10,2 +10,3 @@ class KillCursorsOperation extends operation_1.AbstractOperation {

super(options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.ns = ns;

@@ -18,6 +19,3 @@ this.cursorId = cursorId;

}
async execute(server, session, timeoutContext) {
if (server !== this.server) {
throw new error_1.MongoRuntimeError('Killcursor must run on the same server operation began on');
}
buildCommand(_connection, _session) {
const killCursors = this.ns.collection;

@@ -33,13 +31,13 @@ if (killCursors == null) {

};
try {
await server.command(this.ns, killCursorsCommand, {
session,
timeoutContext
});
}
catch (error) {
// The driver should never emit errors from killCursors, this is spec-ed behavior
(0, utils_1.squashError)(error);
}
return killCursorsCommand;
}
buildOptions(timeoutContext) {
return {
session: this.session,
timeoutContext
};
}
handleError(_error) {
// The driver should never emit errors from killCursors, this is spec-ed behavior
}
}

@@ -46,0 +44,0 @@ exports.KillCursorsOperation = KillCursorsOperation;

@@ -12,2 +12,3 @@ "use strict";

super(db, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.CursorResponse;
this.options = { ...options };

@@ -22,2 +23,3 @@ delete this.options.writeConcern;

}
this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? responses_1.ExplainedCursorResponse : responses_1.CursorResponse;
}

@@ -27,7 +29,3 @@ get commandName() {

}
async execute(server, session, timeoutContext) {
return await super.executeCommand(server, session, this.generateCommand((0, utils_1.maxWireVersion)(server)), timeoutContext, responses_1.CursorResponse);
}
/* This is here for the purpose of unit testing the final command that gets sent. */
generateCommand(wireVersion) {
buildCommandDocument(connection) {
const command = {

@@ -42,3 +40,3 @@ listCollections: 1,

// eslint-disable-next-line no-restricted-syntax
if (wireVersion >= 9 && this.options.comment !== undefined) {
if ((0, utils_1.maxWireVersion)(connection) >= 9 && this.options.comment !== undefined) {
command.comment = this.options.comment;

@@ -48,2 +46,5 @@ }

}
handleOk(response) {
return response;
}
}

@@ -50,0 +51,0 @@ exports.ListCollectionsOperation = ListCollectionsOperation;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ListDatabasesOperation = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const utils_1 = require("../utils");

@@ -11,2 +12,3 @@ const command_1 = require("./command");

super(db, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options ?? {};

@@ -18,3 +20,3 @@ this.ns = new utils_1.MongoDBNamespace('admin', '$cmd');

}
async execute(server, session, timeoutContext) {
buildCommandDocument(connection, _session) {
const cmd = { listDatabases: 1 };

@@ -32,6 +34,6 @@ if (typeof this.options.nameOnly === 'boolean') {

// eslint-disable-next-line no-restricted-syntax
if ((0, utils_1.maxWireVersion)(server) >= 9 && this.options.comment !== undefined) {
if ((0, utils_1.maxWireVersion)(connection) >= 9 && this.options.comment !== undefined) {
cmd.comment = this.options.comment;
}
return await super.executeCommand(server, session, cmd, timeoutContext);
return cmd;
}

@@ -38,0 +40,0 @@ }

@@ -34,3 +34,2 @@ "use strict";

this.bypassPinningCheck = !!options.bypassPinningCheck;
this.trySecondaryWrite = false;
}

@@ -48,2 +47,5 @@ hasAspect(aspect) {

}
set session(session) {
this._session = session;
}
clearSession() {

@@ -61,2 +63,29 @@ this._session = undefined;

}
/**
* Given an instance of a MongoDBResponse, map the response to the correct result type. For
* example, a `CountOperation` might map the response as follows:
*
* ```typescript
* override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): TResult {
* return response.toObject(this.bsonOptions).n ?? 0;
* }
*
* // or, with type safety:
* override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): TResult {
* return response.getNumber('n') ?? 0;
* }
* ```
*/
handleOk(response) {
return response.toObject(this.bsonOptions);
}
/**
* Optional.
*
* If the operation performs error handling, such as wrapping, renaming the error, or squashing errors
* this method can be overridden.
*/
handleError(error) {
throw error;
}
}

@@ -63,0 +92,0 @@ exports.AbstractOperation = AbstractOperation;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProfilingLevelOperation = void 0;
const bson_1 = require("../bson");
const responses_1 = require("../cmap/wire_protocol/responses");
const error_1 = require("../error");
const command_1 = require("./command");
class ProfilingLevelResponse extends responses_1.MongoDBResponse {
get was() {
return this.get('was', bson_1.BSONType.int, true);
}
}
/** @internal */

@@ -10,2 +17,3 @@ class ProfilingLevelOperation extends command_1.CommandOperation {

super(db, options);
this.SERVER_COMMAND_RESPONSE_TYPE = ProfilingLevelResponse;
this.options = options;

@@ -16,6 +24,8 @@ }

}
async execute(server, session, timeoutContext) {
const doc = await super.executeCommand(server, session, { profile: -1 }, timeoutContext);
if (doc.ok === 1) {
const was = doc.was;
buildCommandDocument(_connection) {
return { profile: -1 };
}
handleOk(response) {
if (response.ok === 1) {
const was = response.was;
if (was === 0)

@@ -22,0 +32,0 @@ return 'off';

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RemoveUserOperation = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const command_1 = require("./command");

@@ -10,2 +11,3 @@ const operation_1 = require("./operation");

super(db, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;

@@ -17,4 +19,6 @@ this.username = username;

}
async execute(server, session, timeoutContext) {
await super.executeCommand(server, session, { dropUser: this.username }, timeoutContext);
buildCommandDocument(_connection) {
return { dropUser: this.username };
}
handleOk(_response) {
return true;

@@ -21,0 +25,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RenameOperation = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const collection_1 = require("../collection");

@@ -12,2 +13,3 @@ const utils_1 = require("../utils");

super(collection, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.collection = collection;

@@ -21,13 +23,13 @@ this.newName = newName;

}
async execute(server, session, timeoutContext) {
// Build the command
buildCommandDocument(_connection, _session) {
const renameCollection = this.collection.namespace;
const toCollection = this.collection.s.namespace.withCollection(this.newName).toString();
const to = this.collection.s.namespace.withCollection(this.newName).toString();
const dropTarget = typeof this.options.dropTarget === 'boolean' ? this.options.dropTarget : false;
const command = {
renameCollection: renameCollection,
to: toCollection,
dropTarget: dropTarget
return {
renameCollection,
to,
dropTarget
};
await super.executeCommand(server, session, command, timeoutContext);
}
handleOk(_response) {
return new collection_1.Collection(this.collection.s.db, this.newName, this.collection.s.options);

@@ -34,0 +36,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RunAdminCommandOperation = exports.RunCommandOperation = void 0;
const utils_1 = require("../utils");
const operation_1 = require("./operation");
exports.RunCursorCommandOperation = exports.RunCommandOperation = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const operation_1 = require("../operations/operation");
/** @internal */
class RunCommandOperation extends operation_1.AbstractOperation {
constructor(parent, command, options) {
constructor(namespace, command, options) {
super(options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.command = command;
this.options = options;
this.ns = parent.s.namespace.withCollection('$cmd');
this.ns = namespace.withCollection('$cmd');
}

@@ -17,36 +18,31 @@ get commandName() {

}
async execute(server, session, timeoutContext) {
this.server = server;
const res = await server.command(this.ns, this.command, {
buildCommand(_connection, _session) {
return this.command;
}
buildOptions(timeoutContext) {
return {
...this.options,
readPreference: this.readPreference,
session,
timeoutContext
}, this.options.responseType);
return res;
session: this.session,
timeoutContext,
signal: this.options.signal,
readPreference: this.options.readPreference
};
}
}
exports.RunCommandOperation = RunCommandOperation;
class RunAdminCommandOperation extends operation_1.AbstractOperation {
constructor(command, options) {
super(options);
this.command = command;
this.options = options;
this.ns = new utils_1.MongoDBNamespace('admin', '$cmd');
/**
* @internal
*
* A specialized subclass of RunCommandOperation for cursor-creating commands.
*/
class RunCursorCommandOperation extends RunCommandOperation {
constructor() {
super(...arguments);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.CursorResponse;
}
get commandName() {
return 'runCommand';
handleOk(response) {
return response;
}
async execute(server, session, timeoutContext) {
this.server = server;
const res = await server.command(this.ns, this.command, {
...this.options,
readPreference: this.readPreference,
session,
timeoutContext
});
return res;
}
}
exports.RunAdminCommandOperation = RunAdminCommandOperation;
exports.RunCursorCommandOperation = RunCursorCommandOperation;
//# sourceMappingURL=run_command.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CreateSearchIndexesOperation = void 0;
const responses_1 = require("../../cmap/wire_protocol/responses");
const operation_1 = require("../operation");

@@ -9,4 +10,6 @@ /** @internal */

super();
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.collection = collection;
this.descriptions = descriptions;
this.ns = collection.fullNamespace;
}

@@ -16,17 +19,17 @@ get commandName() {

}
async execute(server, session, timeoutContext) {
buildCommand(_connection, _session) {
const namespace = this.collection.fullNamespace;
const command = {
return {
createSearchIndexes: namespace.collection,
indexes: this.descriptions
};
const res = await server.command(namespace, command, {
session,
timeoutContext
});
const indexesCreated = res?.indexesCreated ?? [];
return indexesCreated.map(({ name }) => name);
}
handleOk(response) {
return super.handleOk(response).indexesCreated.map((val) => val.name);
}
buildOptions(timeoutContext) {
return { session: this.session, timeoutContext };
}
}
exports.CreateSearchIndexesOperation = CreateSearchIndexesOperation;
//# sourceMappingURL=create.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DropSearchIndexOperation = void 0;
const responses_1 = require("../../cmap/wire_protocol/responses");
const error_1 = require("../../error");

@@ -10,4 +11,6 @@ const operation_1 = require("../operation");

super();
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.collection = collection;
this.name = name;
this.ns = collection.fullNamespace;
}

@@ -17,3 +20,3 @@ get commandName() {

}
async execute(server, session, timeoutContext) {
buildCommand(_connection, _session) {
const namespace = this.collection.fullNamespace;

@@ -26,11 +29,15 @@ const command = {

}
try {
await server.command(namespace, command, { session, timeoutContext });
return command;
}
handleOk(_response) {
// do nothing
}
buildOptions(timeoutContext) {
return { session: this.session, timeoutContext };
}
handleError(error) {
const isNamespaceNotFoundError = error instanceof error_1.MongoServerError && error.code === error_1.MONGODB_ERROR_CODES.NamespaceNotFound;
if (!isNamespaceNotFoundError) {
throw error;
}
catch (error) {
const isNamespaceNotFoundError = error instanceof error_1.MongoServerError && error.code === error_1.MONGODB_ERROR_CODES.NamespaceNotFound;
if (!isNamespaceNotFoundError) {
throw error;
}
}
}

@@ -37,0 +44,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpdateSearchIndexOperation = void 0;
const responses_1 = require("../../cmap/wire_protocol/responses");
const operation_1 = require("../operation");

@@ -9,5 +10,7 @@ /** @internal */

super();
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.collection = collection;
this.name = name;
this.definition = definition;
this.ns = collection.fullNamespace;
}

@@ -17,5 +20,5 @@ get commandName() {

}
async execute(server, session, timeoutContext) {
buildCommand(_connection, _session) {
const namespace = this.collection.fullNamespace;
const command = {
return {
updateSearchIndex: namespace.collection,

@@ -25,7 +28,11 @@ name: this.name,

};
await server.command(namespace, command, { session, timeoutContext });
return;
}
handleOk(_response) {
// no response.
}
buildOptions(timeoutContext) {
return { session: this.session, timeoutContext };
}
}
exports.UpdateSearchIndexOperation = UpdateSearchIndexOperation;
//# sourceMappingURL=update.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SetProfilingLevelOperation = exports.ProfilingLevel = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const error_1 = require("../error");

@@ -18,2 +19,3 @@ const utils_1 = require("../utils");

super(db, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;

@@ -39,13 +41,15 @@ switch (level) {

}
async execute(server, session, timeoutContext) {
buildCommandDocument(_connection) {
const level = this.level;
if (!levelValues.has(level)) {
// TODO(NODE-3483): Determine error to put here
throw new error_1.MongoInvalidArgumentError(`Profiling level must be one of "${(0, utils_1.enumToString)(exports.ProfilingLevel)}"`);
}
// TODO(NODE-3483): Determine error to put here
await super.executeCommand(server, session, { profile: this.profile }, timeoutContext);
return level;
return { profile: this.profile };
}
handleOk(_response) {
return this.level;
}
}
exports.SetProfilingLevelOperation = SetProfilingLevelOperation;
//# sourceMappingURL=set_profiling_level.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DbStatsOperation = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const command_1 = require("./command");

@@ -10,2 +11,3 @@ const operation_1 = require("./operation");

super(db, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;

@@ -16,3 +18,3 @@ }

}
async execute(server, session, timeoutContext) {
buildCommandDocument(_connection) {
const command = { dbStats: true };

@@ -22,3 +24,3 @@ if (this.options.scale != null) {

}
return await super.executeCommand(server, session, command, timeoutContext);
return command;
}

@@ -25,0 +27,0 @@ }

@@ -5,2 +5,3 @@ "use strict";

exports.makeUpdateStatement = makeUpdateStatement;
const responses_1 = require("../cmap/wire_protocol/responses");
const error_1 = require("../error");

@@ -18,2 +19,3 @@ const sort_1 = require("../sort");

super(undefined, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;

@@ -32,9 +34,8 @@ this.ns = ns;

}
async execute(server, session, timeoutContext) {
const options = this.options ?? {};
const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
buildCommandDocument(_connection, _session) {
const options = this.options;
const command = {
update: this.ns.collection,
updates: this.statements,
ordered
ordered: options.ordered ?? true
};

@@ -52,3 +53,3 @@ if (typeof options.bypassDocumentValidation === 'boolean') {

}
const unacknowledgedWrite = this.writeConcern && this.writeConcern.w === 0;
const unacknowledgedWrite = this.writeConcern?.w === 0;
if (unacknowledgedWrite) {

@@ -60,4 +61,3 @@ if (this.statements.find((o) => o.hint)) {

}
const res = await super.executeCommand(server, session, command, timeoutContext);
return res;
return command;
}

@@ -68,4 +68,4 @@ }

class UpdateOneOperation extends UpdateOperation {
constructor(collection, filter, update, options) {
super(collection.s.namespace, [makeUpdateStatement(filter, update, { ...options, multi: false })], options);
constructor(ns, filter, update, options) {
super(ns, [makeUpdateStatement(filter, update, { ...options, multi: false })], options);
if (!(0, utils_1.hasAtomicOperators)(update, options)) {

@@ -75,4 +75,5 @@ throw new error_1.MongoInvalidArgumentError('Update document requires atomic operators');

}
async execute(server, session, timeoutContext) {
const res = await super.execute(server, session, timeoutContext);
handleOk(response) {
const res = super.handleOk(response);
// @ts-expect-error Explain typing is broken
if (this.explain != null)

@@ -96,4 +97,4 @@ return res;

class UpdateManyOperation extends UpdateOperation {
constructor(collection, filter, update, options) {
super(collection.s.namespace, [makeUpdateStatement(filter, update, { ...options, multi: true })], options);
constructor(ns, filter, update, options) {
super(ns, [makeUpdateStatement(filter, update, { ...options, multi: true })], options);
if (!(0, utils_1.hasAtomicOperators)(update, options)) {

@@ -103,4 +104,5 @@ throw new error_1.MongoInvalidArgumentError('Update document requires atomic operators');

}
async execute(server, session, timeoutContext) {
const res = await super.execute(server, session, timeoutContext);
handleOk(response) {
const res = super.handleOk(response);
// @ts-expect-error Explain typing is broken
if (this.explain != null)

@@ -124,4 +126,4 @@ return res;

class ReplaceOneOperation extends UpdateOperation {
constructor(collection, filter, replacement, options) {
super(collection.s.namespace, [makeUpdateStatement(filter, replacement, { ...options, multi: false })], options);
constructor(ns, filter, replacement, options) {
super(ns, [makeUpdateStatement(filter, replacement, { ...options, multi: false })], options);
if ((0, utils_1.hasAtomicOperators)(replacement)) {

@@ -131,4 +133,5 @@ throw new error_1.MongoInvalidArgumentError('Replacement document must not contain atomic operators');

}
async execute(server, session, timeoutContext) {
const res = await super.execute(server, session, timeoutContext);
handleOk(response) {
const res = super.handleOk(response);
// @ts-expect-error Explain typing is broken
if (this.explain != null)

@@ -135,0 +138,0 @@ return res;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ValidateCollectionOperation = void 0;
const responses_1 = require("../cmap/wire_protocol/responses");
const error_1 = require("../error");

@@ -9,13 +10,5 @@ const command_1 = require("./command");

constructor(admin, collectionName, options) {
// Decorate command with extra options
const command = { validate: collectionName };
const keys = Object.keys(options);
for (let i = 0; i < keys.length; i++) {
if (Object.prototype.hasOwnProperty.call(options, keys[i]) && keys[i] !== 'session') {
command[keys[i]] = options[keys[i]];
}
}
super(admin.s.db, options);
this.SERVER_COMMAND_RESPONSE_TYPE = responses_1.MongoDBResponse;
this.options = options;
this.command = command;
this.collectionName = collectionName;

@@ -26,12 +19,18 @@ }

}
async execute(server, session, timeoutContext) {
const collectionName = this.collectionName;
const doc = await super.executeCommand(server, session, this.command, timeoutContext);
if (doc.result != null && typeof doc.result !== 'string')
buildCommandDocument(_connection, _session) {
// Decorate command with extra options
return {
validate: this.collectionName,
...Object.fromEntries(Object.entries(this.options).filter(entry => entry[0] !== 'session'))
};
}
handleOk(response) {
const result = super.handleOk(response);
if (result.result != null && typeof result.result !== 'string')
throw new error_1.MongoUnexpectedServerResponseError('Error with validation data');
if (doc.result != null && doc.result.match(/exception|corrupt/) != null)
throw new error_1.MongoUnexpectedServerResponseError(`Invalid collection ${collectionName}`);
if (doc.valid != null && !doc.valid)
throw new error_1.MongoUnexpectedServerResponseError(`Invalid collection ${collectionName}`);
return doc;
if (result.result != null && result.result.match(/exception|corrupt/) != null)
throw new error_1.MongoUnexpectedServerResponseError(`Invalid collection ${this.collectionName}`);
if (result.valid != null && !result.valid)
throw new error_1.MongoUnexpectedServerResponseError(`Invalid collection ${this.collectionName}`);
return response;
}

@@ -38,0 +37,0 @@ }

@@ -10,2 +10,3 @@ "use strict";

const mongo_types_1 = require("../mongo_types");
const aggregate_1 = require("../operations/aggregate");
const transactions_1 = require("../transactions");

@@ -17,2 +18,3 @@ const utils_1 = require("../utils");

const server_description_1 = require("./server_description");
const server_selection_1 = require("./server_selection");
const stateTransition = (0, utils_1.makeStateMachine)({

@@ -135,21 +137,7 @@ [common_1.STATE_CLOSED]: [common_1.STATE_CLOSED, common_1.STATE_CONNECTING],

}
async command(ns, cmd, { ...options }, responseType) {
if (ns.db == null || typeof ns === 'string') {
throw new error_1.MongoInvalidArgumentError('Namespace must not be a string');
}
async command(operation, timeoutContext) {
if (this.s.state === common_1.STATE_CLOSING || this.s.state === common_1.STATE_CLOSED) {
throw new error_1.MongoServerClosedError();
}
options.directConnection = this.topology.s.options.directConnection;
// There are cases where we need to flag the read preference not to get sent in
// the command, such as pre-5.0 servers attempting to perform an aggregate write
// with a non-primary read preference. In this case the effective read preference
// (primary) is not the same as the provided and must be removed completely.
if (options.omitReadPreference) {
delete options.readPreference;
}
if (this.description.iscryptd) {
options.omitMaxTimeMS = true;
}
const session = options.session;
const session = operation.session;
let conn = session?.pinnedConnection;

@@ -159,6 +147,3 @@ this.incrementOperationCount();

try {
conn = await this.pool.checkOut(options);
if (this.loadBalanced && isPinnableCommand(cmd, session)) {
session?.pin(conn);
}
conn = await this.pool.checkOut({ timeoutContext, signal: operation.options.signal });
}

@@ -173,5 +158,43 @@ catch (checkoutError) {

let reauthPromise = null;
const cleanup = () => {
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);
}
}
};
let cmd;
try {
cmd = operation.buildCommand(conn, session);
}
catch (e) {
cleanup();
throw e;
}
const options = operation.buildOptions(timeoutContext);
const ns = operation.ns;
if (this.loadBalanced && isPinnableCommand(cmd, session) && !session?.pinnedConnection) {
session?.pin(conn);
}
options.directConnection = this.topology.s.options.directConnection;
const omitReadPreference = operation instanceof aggregate_1.AggregateOperation &&
operation.hasWriteStage &&
(0, utils_1.maxWireVersion)(conn) < server_selection_1.MIN_SECONDARY_WRITE_WIRE_VERSION;
if (omitReadPreference) {
delete options.readPreference;
}
if (this.description.iscryptd) {
options.omitMaxTimeMS = true;
}
try {
try {
const res = await conn.command(ns, cmd, options, responseType);
const res = await conn.command(ns, cmd, options, operation.SERVER_COMMAND_RESPONSE_TYPE);
(0, write_concern_1.throwIfWriteConcernError)(res);

@@ -195,3 +218,3 @@ return res;

try {
const res = await conn.command(ns, cmd, options, responseType);
const res = await conn.command(ns, cmd, options, operation.SERVER_COMMAND_RESPONSE_TYPE);
(0, write_concern_1.throwIfWriteConcernError)(res);

@@ -209,15 +232,3 @@ return res;

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);
}
}
cleanup();
}

@@ -224,0 +235,0 @@ }

@@ -195,3 +195,3 @@ "use strict";

const selectServerOptions = {
operationName: 'ping',
operationName: 'handshake',
...options,

@@ -204,3 +204,4 @@ timeoutContext

if (!skipPingOnConnect && this.s.credentials) {
await server.command((0, utils_1.ns)('admin.$cmd'), { ping: 1 }, { timeoutContext });
const connection = await server.pool.checkOut({ timeoutContext: timeoutContext });
server.pool.checkIn(connection);
stateTransition(this, common_1.STATE_CONNECTED);

@@ -406,3 +407,3 @@ this.emit(Topology.OPEN, this);

if (typeof credentials === 'function')
(callback = credentials), (credentials = undefined);
((callback = credentials), (credentials = undefined));
if (typeof callback === 'function')

@@ -409,0 +410,0 @@ callback(undefined, true);

@@ -314,3 +314,3 @@ "use strict";

}
const operation = new run_command_1.RunAdminCommandOperation(command, {
const operation = new run_command_1.RunCommandOperation(new utils_1.MongoDBNamespace('admin'), command, {
session: this,

@@ -341,3 +341,3 @@ readPreference: read_preference_1.ReadPreference.primary,

try {
await (0, execute_operation_1.executeOperation)(this.client, new run_command_1.RunAdminCommandOperation(command, {
await (0, execute_operation_1.executeOperation)(this.client, new run_command_1.RunCommandOperation(new utils_1.MongoDBNamespace('admin'), command, {
session: this,

@@ -410,3 +410,3 @@ readPreference: read_preference_1.ReadPreference.primary,

}
const operation = new run_command_1.RunAdminCommandOperation(command, {
const operation = new run_command_1.RunCommandOperation(new utils_1.MongoDBNamespace('admin'), command, {
session: this,

@@ -413,0 +413,0 @@ readPreference: read_preference_1.ReadPreference.primary,

@@ -1079,17 +1079,12 @@ "use strict";

}
function maybeAddIdToDocuments(coll, docOrDocs, options) {
const forceServerObjectId = typeof options.forceServerObjectId === 'boolean'
? options.forceServerObjectId
: coll.s.db.options?.forceServerObjectId;
function maybeAddIdToDocuments(collection, document, options) {
const forceServerObjectId = options.forceServerObjectId ?? collection.s.db.options?.forceServerObjectId ?? false;
// no need to modify the docs if server sets the ObjectId
if (forceServerObjectId === true) {
return docOrDocs;
if (forceServerObjectId) {
return document;
}
const transform = (doc) => {
if (doc._id == null) {
doc._id = coll.s.pkFactory.createPk();
}
return doc;
};
return Array.isArray(docOrDocs) ? docOrDocs.map(transform) : transform(docOrDocs);
if (document._id == null) {
document._id = collection.s.pkFactory.createPk();
}
return document;
}

@@ -1096,0 +1091,0 @@ async function fileIsAccessible(fileName, mode) {

{
"name": "mongodb",
"version": "6.18.0",
"version": "6.19.0-dev.20250827.sha.3c5bb1d5",
"description": "The official MongoDB driver for Node.js",

@@ -28,5 +28,5 @@ "main": "lib/index.js",

"dependencies": {
"@mongodb-js/saslprep": "^1.1.9",
"@mongodb-js/saslprep": "^1.3.0",
"bson": "^6.10.4",
"mongodb-connection-string-url": "^3.0.0"
"mongodb-connection-string-url": "^3.0.2"
},

@@ -39,3 +39,3 @@ "peerDependencies": {

"mongodb-client-encryption": ">=6.0.0 <7",
"snappy": "^7.2.2",
"snappy": "^7.3.2",
"socks": "^2.7.1"

@@ -67,6 +67,6 @@ },

"devDependencies": {
"@aws-sdk/credential-providers": "^3.632.0",
"@aws-sdk/credential-providers": "^3.864.0",
"@iarna/toml": "^2.2.5",
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@microsoft/api-extractor": "^7.52.5",
"@microsoft/api-extractor": "^7.52.10",
"@microsoft/tsdoc-config": "^0.17.1",

@@ -76,3 +76,3 @@ "@mongodb-js/zstd": "^2.0.1",

"@types/chai-subset": "^1.3.5",
"@types/express": "^5.0.1",
"@types/express": "^5.0.3",
"@types/kerberos": "^1.1.5",

@@ -86,3 +86,3 @@ "@types/mocha": "^10.0.9",

"@types/whatwg-url": "^13.0.0",
"@typescript-eslint/eslint-plugin": "^8.31.1",
"@typescript-eslint/eslint-plugin": "^8.40.0",
"@typescript-eslint/parser": "^8.31.1",

@@ -92,26 +92,26 @@ "chai": "^4.4.1",

"chalk": "^4.1.2",
"eslint": "^9.25.1",
"eslint-config-prettier": "^10.1.2",
"eslint": "^9.33.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-mocha": "^10.4.1",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-tsdoc": "^0.4.0",
"eslint-plugin-unused-imports": "^4.1.4",
"eslint-plugin-unused-imports": "^4.2.0",
"express": "^5.1.0",
"gcp-metadata": "^5.3.0",
"js-yaml": "^4.1.0",
"mocha": "^10.8.2",
"mocha": "^11.7.1",
"mocha-sinon": "^2.1.2",
"mongodb-client-encryption": "^6.4.0",
"mongodb-client-encryption": "^6.5.0",
"mongodb-legacy": "^6.1.3",
"nyc": "^15.1.0",
"prettier": "^3.5.3",
"semver": "^7.7.0",
"prettier": "^3.6.2",
"semver": "^7.7.2",
"sinon": "^18.0.1",
"sinon-chai": "^3.7.0",
"snappy": "^7.2.2",
"socks": "^2.8.1",
"snappy": "^7.3.2",
"socks": "^2.8.7",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.2",
"tsd": "^0.32.0",
"tsd": "^0.33.0",
"typescript": "5.8.3",

@@ -118,0 +118,0 @@ "typescript-cached-transpile": "^0.0.6",

@@ -11,3 +11,3 @@ import { type Document, resolveBSONOptions } from './bson';

import { RemoveUserOperation, type RemoveUserOptions } from './operations/remove_user';
import { RunAdminCommandOperation, type RunCommandOptions } from './operations/run_command';
import { RunCommandOperation, type RunCommandOptions } from './operations/run_command';
import {

@@ -17,2 +17,3 @@ ValidateCollectionOperation,

} from './operations/validate_collection';
import { MongoDBNamespace } from './utils';

@@ -80,3 +81,3 @@ /** @internal */

this.s.db.client,
new RunAdminCommandOperation(command, {
new RunCommandOperation(new MongoDBNamespace('admin'), command, {
...resolveBSONOptions(options),

@@ -83,0 +84,0 @@ session: options?.session,

@@ -17,9 +17,7 @@ import { type BSONSerializeOptions, type Document, EJSON, resolveBSONOptions } from '../bson';

import { InsertOperation } from '../operations/insert';
import { AbstractOperation, type Hint } from '../operations/operation';
import { type Hint } from '../operations/operation';
import { makeUpdateStatement, UpdateOperation, type UpdateStatement } from '../operations/update';
import type { Server } from '../sdam/server';
import type { Topology } from '../sdam/topology';
import type { ClientSession } from '../sessions';
import { type Sort } from '../sort';
import { type TimeoutContext } from '../timeout';
import { TimeoutContext } from '../timeout';
import {

@@ -858,36 +856,2 @@ applyRetryableWrites,

/**
* TODO(NODE-4063)
* BulkWrites merge complexity is implemented in executeCommands
* This provides a vehicle to treat bulkOperations like any other operation (hence "shim")
* We would like this logic to simply live inside the BulkWriteOperation class
* @internal
*/
export class BulkWriteShimOperation extends AbstractOperation {
bulkOperation: BulkOperationBase;
constructor(bulkOperation: BulkOperationBase, options: BulkWriteOptions) {
super(options);
this.bulkOperation = bulkOperation;
}
get commandName(): string {
return 'bulkWrite' as const;
}
async execute(
_server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<any> {
if (this.options.session == null) {
// An implicit session could have been created by 'executeOperation'
// So if we stick it on finalOptions here, each bulk operation
// will use this same session, it'll be passed in the same way
// an explicit session would be
this.options.session = session;
}
return await executeCommands(this.bulkOperation, { ...this.options, timeoutContext });
}
}
/** @public */

@@ -1213,6 +1177,22 @@ export abstract class BulkOperationBase {

this.s.executed = true;
const finalOptions = { ...this.s.options, ...options };
const operation = new BulkWriteShimOperation(this, finalOptions);
const finalOptions = resolveOptions(this.collection, { ...this.s.options, ...options });
return await executeOperation(this.s.collection.client, operation, finalOptions.timeoutContext);
// if there is no timeoutContext provided, create a timeoutContext and use it for
// all batches in the bulk operation
finalOptions.timeoutContext ??= TimeoutContext.create({
session: finalOptions.session,
timeoutMS: finalOptions.timeoutMS,
serverSelectionTimeoutMS: this.collection.client.s.options.serverSelectionTimeoutMS,
waitQueueTimeoutMS: this.collection.client.s.options.waitQueueTimeoutMS
});
if (finalOptions.session == null) {
// if there is not an explicit session provided to `execute()`, create
// an implicit session and use that for all batches in the bulk operation
return await this.collection.client.withSession({ explicit: false }, async session => {
return await executeCommands(this, { ...finalOptions, session });
});
}
return await executeCommands(this, { ...finalOptions });
}

@@ -1219,0 +1199,0 @@

@@ -752,3 +752,4 @@ import type {

): Promise<Binary> {
const { algorithm, keyId, keyAltName, contentionFactor, queryType, rangeOptions } = options;
const { algorithm, keyId, keyAltName, contentionFactor, queryType, rangeOptions, textOptions } =
options;
const contextOptions: ExplicitEncryptionContextOptions = {

@@ -786,2 +787,6 @@ expressionMode,

if (typeof textOptions === 'object') {
contextOptions.textOptions = serialize(textOptions);
}
const valueBuffer = serialize({ v: value });

@@ -817,3 +822,4 @@ const stateMachine = new StateMachine({

| 'Unindexed'
| 'Range';
| 'Range'
| 'TextPreview';

@@ -836,10 +842,53 @@ /**

*/
queryType?: 'equality' | 'range';
queryType?: 'equality' | 'range' | 'prefixPreview' | 'suffixPreview' | 'substringPreview';
/** The index options for a Queryable Encryption field supporting "range" queries.*/
rangeOptions?: RangeOptions;
/**
* Options for a Queryable Encryption field supporting text queries. Only valid when `algorithm` is `TextPreview`.
*
* @experimental Public Technical Preview: `textPreview` is an experimental feature and may break at any time.
*/
textOptions?: TextQueryOptions;
}
/**
* Options for a Queryable Encryption field supporting text queries.
*
* @public
* @experimental Public Technical Preview: `textPreview` is an experimental feature and may break at any time.
*/
export interface TextQueryOptions {
/** Indicates that text indexes for this field are case sensitive */
caseSensitive: boolean;
/** Indicates that text indexes for this field are diacritic sensitive. */
diacriticSensitive: boolean;
prefix?: {
/** The maximum allowed query length. */
strMaxQueryLength: Int32 | number;
/** The minimum allowed query length. */
strMinQueryLength: Int32 | number;
};
suffix?: {
/** The maximum allowed query length. */
strMaxQueryLength: Int32 | number;
/** The minimum allowed query length. */
strMinQueryLength: Int32 | number;
};
substring?: {
/** The maximum allowed length to insert. */
strMaxLength: Int32 | number;
/** The maximum allowed query length. */
strMaxQueryLength: Int32 | number;
/** The minimum allowed query length. */
strMinQueryLength: Int32 | number;
};
}
/**
* @public
* @experimental

@@ -846,0 +895,0 @@ */

@@ -109,3 +109,3 @@ import * as fs from 'fs/promises';

MongoClientOptions,
'tlsCAFile' | 'tlsCertificateKeyFile' | 'tlsCertificateKeyFilePassword'
'tlsCAFile' | 'tlsCertificateKeyFile' | 'tlsCertificateKeyFilePassword' | 'secureContext'
>;

@@ -525,2 +525,6 @@

): Promise<void> {
// If a secureContext is provided, ensure it is set.
if (tlsOptions.secureContext) {
options.secureContext = tlsOptions.secureContext;
}
if (tlsOptions.tlsCertificateKeyFile) {

@@ -527,0 +531,0 @@ const cert = await fs.readFile(tlsOptions.tlsCertificateKeyFile);

@@ -95,3 +95,2 @@ import { type Readable, Transform, type TransformCallback } from 'stream';

noResponse?: boolean;
omitReadPreference?: boolean;
omitMaxTimeMS?: boolean;

@@ -98,0 +97,0 @@

import { type BSONSerializeOptions, type Document, resolveBSONOptions } from './bson';
import type { AnyBulkWriteOperation, BulkWriteOptions, BulkWriteResult } from './bulk/common';
import type {
AnyBulkWriteOperation,
BulkOperationBase,
BulkWriteOptions,
BulkWriteResult
} from './bulk/common';
import { OrderedBulkOperation } from './bulk/ordered';

@@ -14,3 +19,4 @@ import { UnorderedBulkOperation } from './bulk/unordered';

import type { Db } from './db';
import { MongoInvalidArgumentError, MongoOperationTimeoutError } from './error';
import { MongoAPIError, MongoInvalidArgumentError, MongoOperationTimeoutError } from './error';
import { type ExplainCommandOptions, type ExplainVerbosityLike } from './explain';
import type { MongoClient, PkFactory } from './mongo_client';

@@ -28,3 +34,2 @@ import type {

import type { AggregateOptions } from './operations/aggregate';
import { BulkWriteOperation } from './operations/bulk_write';
import { CountOperation, type CountOptions } from './operations/count';

@@ -38,3 +43,3 @@ import {

import { DistinctOperation, type DistinctOptions } from './operations/distinct';
import { DropCollectionOperation, type DropCollectionOptions } from './operations/drop';
import { type DropCollectionOptions } from './operations/drop';
import {

@@ -44,4 +49,4 @@ EstimatedDocumentCountOperation,

} from './operations/estimated_document_count';
import { executeOperation } from './operations/execute_operation';
import type { FindOptions } from './operations/find';
import { autoConnect, executeOperation } from './operations/execute_operation';
import { type FindOneOptions, type FindOptions } from './operations/find';
import {

@@ -68,3 +73,2 @@ FindOneAndDeleteOperation,

import {
InsertManyOperation,
type InsertManyResult,

@@ -75,5 +79,3 @@ InsertOneOperation,

} from './operations/insert';
import { IsCappedOperation } from './operations/is_capped';
import type { Hint, OperationOptions } from './operations/operation';
import { OptionsOperation } from './operations/options_operation';
import { RenameOperation, type RenameOptions } from './operations/rename';

@@ -314,10 +316,27 @@ import {

): Promise<InsertManyResult<TSchema>> {
return await executeOperation(
this.client,
new InsertManyOperation(
this as TODO_NODE_3286,
docs,
resolveOptions(this, options ?? { ordered: true })
) as TODO_NODE_3286
);
if (!Array.isArray(docs)) {
throw new MongoInvalidArgumentError('Argument "docs" must be an array of documents');
}
options = resolveOptions(this, options ?? {});
const acknowledged = WriteConcern.fromOptions(options)?.w !== 0;
try {
const res = await this.bulkWrite(
docs.map(doc => ({ insertOne: { document: doc } })),
options
);
return {
acknowledged,
insertedCount: res.insertedCount,
insertedIds: res.insertedIds
};
} catch (err) {
if (err && err.message === 'Operation must be an object with an operation key') {
throw new MongoInvalidArgumentError(
'Collection.insertMany() cannot be called with an array that has null/undefined values'
);
}
throw err;
}
}

@@ -352,10 +371,24 @@

return await executeOperation(
this.client,
new BulkWriteOperation(
this as TODO_NODE_3286,
operations,
resolveOptions(this, options ?? { ordered: true })
)
);
options = resolveOptions(this, options ?? {});
// TODO(NODE-7071): remove once the client doesn't need to be connected to construct
// bulk operations
const isConnected = this.client.topology != null;
if (!isConnected) {
await autoConnect(this.client);
}
// Create the bulk operation
const bulk: BulkOperationBase =
options.ordered === false
? this.initializeUnorderedBulkOp(options)
: this.initializeOrderedBulkOp(options);
// for each op go through and add to the bulk
for (const operation of operations) {
bulk.raw(operation);
}
// Execute the bulk
return await bulk.execute({ ...options });
}

@@ -381,8 +414,3 @@

this.client,
new UpdateOneOperation(
this as TODO_NODE_3286,
filter,
update,
resolveOptions(this, options)
) as TODO_NODE_3286
new UpdateOneOperation(this.s.namespace, filter, update, resolveOptions(this, options))
);

@@ -405,8 +433,3 @@ }

this.client,
new ReplaceOneOperation(
this as TODO_NODE_3286,
filter,
replacement,
resolveOptions(this, options)
)
new ReplaceOneOperation(this.s.namespace, filter, replacement, resolveOptions(this, options))
);

@@ -433,8 +456,3 @@ }

this.client,
new UpdateManyOperation(
this as TODO_NODE_3286,
filter,
update,
resolveOptions(this, options)
) as TODO_NODE_3286
new UpdateManyOperation(this.s.namespace, filter, update, resolveOptions(this, options))
);

@@ -455,3 +473,3 @@ }

this.client,
new DeleteOneOperation(this as TODO_NODE_3286, filter, resolveOptions(this, options))
new DeleteOneOperation(this.s.namespace, filter, resolveOptions(this, options))
);

@@ -472,3 +490,3 @@ }

this.client,
new DeleteManyOperation(this as TODO_NODE_3286, filter, resolveOptions(this, options))
new DeleteManyOperation(this.s.namespace, filter, resolveOptions(this, options))
);

@@ -497,3 +515,3 @@ }

})
) as TODO_NODE_3286
)
);

@@ -508,6 +526,3 @@ }

async drop(options?: DropCollectionOptions): Promise<boolean> {
return await executeOperation(
this.client,
new DropCollectionOperation(this.s.db, this.collectionName, options)
);
return await this.s.db.dropCollection(this.collectionName, options);
}

@@ -525,3 +540,3 @@

filter: Filter<TSchema>,
options: Omit<FindOptions, 'timeoutMode'> & Abortable
options: Omit<FindOneOptions, 'timeoutMode'> & Abortable
): Promise<WithId<TSchema> | null>;

@@ -534,3 +549,3 @@

filter: Filter<TSchema>,
options?: Omit<FindOptions, 'timeoutMode'> & Abortable
options?: Omit<FindOneOptions, 'timeoutMode'> & Abortable
): Promise<T | null>;

@@ -540,8 +555,13 @@

filter: Filter<TSchema> = {},
options: FindOptions & Abortable = {}
options: Omit<FindOneOptions, 'timeoutMode'> & Abortable = {}
): Promise<WithId<TSchema> | null> {
const cursor = this.find(filter, options).limit(-1).batchSize(1);
const res = await cursor.next();
// Explicitly set the limit to 1 and singleBatch to true for all commands, per the spec.
// noCursorTimeout must be unset as well as batchSize.
// See: https://github.com/mongodb/specifications/blob/master/source/crud/crud.md#findone-api-details
const { batchSize: _batchSize, noCursorTimeout: _noCursorTimeout, ...opts } = options;
opts.singleBatch = true;
const cursor = this.find(filter, opts).limit(1);
const result = await cursor.next();
await cursor.close();
return res;
return result;
}

@@ -568,3 +588,3 @@

filter,
resolveOptions(this as TODO_NODE_3286, options)
resolveOptions(this, options)
);

@@ -579,6 +599,12 @@ }

async options(options?: OperationOptions): Promise<Document> {
return await executeOperation(
this.client,
new OptionsOperation(this as TODO_NODE_3286, resolveOptions(this, options))
);
options = resolveOptions(this, options);
const [collection] = await this.s.db
.listCollections({ name: this.collectionName }, { ...options, nameOnly: false })
.toArray();
if (collection == null || collection.options == null) {
throw new MongoAPIError(`collection ${this.namespace} not found`);
}
return collection.options;
}

@@ -592,6 +618,4 @@

async isCapped(options?: OperationOptions): Promise<boolean> {
return await executeOperation(
this.client,
new IsCappedOperation(this as TODO_NODE_3286, resolveOptions(this, options))
);
const { capped } = await this.options(options);
return Boolean(capped);
}

@@ -864,2 +888,7 @@

): Promise<Array<Flatten<WithId<TSchema>[Key]>>>;
distinct<Key extends keyof WithId<TSchema>>(
key: Key,
filter: Filter<TSchema>,
options: DistinctOptions & { explain: ExplainVerbosityLike | ExplainCommandOptions }
): Promise<Document>;

@@ -866,0 +895,0 @@ // Embedded documents overload

@@ -5,3 +5,2 @@ import type { Document } from '../bson';

Explain,
ExplainableCursor,
type ExplainCommandOptions,

@@ -23,2 +22,3 @@ type ExplainVerbosityLike,

} from './abstract_cursor';
import { ExplainableCursor } from './explainable_cursor';

@@ -25,0 +25,0 @@ /** @public */

@@ -6,3 +6,2 @@ import { type Document } from '../bson';

Explain,
ExplainableCursor,
type ExplainCommandOptions,

@@ -23,2 +22,3 @@ type ExplainVerbosityLike,

import { type InitialCursorResponse } from './abstract_cursor';
import { ExplainableCursor } from './explainable_cursor';

@@ -25,0 +25,0 @@ /** @public Flags allowed for cursor */

import type { BSONSerializeOptions, Document } from '../bson';
import { CursorResponse } from '../cmap/wire_protocol/responses';
import { type CursorResponse } from '../cmap/wire_protocol/responses';
import type { Db } from '../db';

@@ -7,3 +7,3 @@ import { MongoAPIError, MongoRuntimeError } from '../error';

import { GetMoreOperation } from '../operations/get_more';
import { RunCommandOperation } from '../operations/run_command';
import { RunCursorCommandOperation } from '../operations/run_command';
import type { ReadConcernLike } from '../read_concern';

@@ -147,7 +147,6 @@ import type { ReadPreferenceLike } from '../read_preference';

protected async _initialize(session: ClientSession): Promise<InitialCursorResponse> {
const operation = new RunCommandOperation<CursorResponse>(this.db, this.command, {
const operation = new RunCursorCommandOperation(this.db.s.namespace, this.command, {
...this.cursorOptions,
session: session,
readPreference: this.cursorOptions.readPreference,
responseType: CursorResponse
readPreference: this.cursorOptions.readPreference
});

@@ -154,0 +153,0 @@

@@ -13,10 +13,6 @@ import { Admin } from './admin';

import type { AggregateOptions } from './operations/aggregate';
import { CollectionsOperation } from './operations/collections';
import { type CreateCollectionOptions, createCollections } from './operations/create_collection';
import {
CreateCollectionOperation,
type CreateCollectionOptions
} from './operations/create_collection';
import {
DropCollectionOperation,
type DropCollectionOptions,
dropCollections,
DropDatabaseOperation,

@@ -246,6 +242,4 @@ type DropDatabaseOptions

): Promise<Collection<TSchema>> {
return await executeOperation(
this.client,
new CreateCollectionOperation(this, name, resolveOptions(this, options)) as TODO_NODE_3286
);
options = resolveOptions(this, options);
return await createCollections<TSchema>(this, name, options);
}

@@ -283,3 +277,3 @@

new RunCommandOperation(
this,
this.s.namespace,
command,

@@ -417,6 +411,4 @@ resolveOptions(undefined, {

async dropCollection(name: string, options?: DropCollectionOptions): Promise<boolean> {
return await executeOperation(
this.client,
new DropCollectionOperation(this, name, resolveOptions(this, options))
);
options = resolveOptions(this, options);
return await dropCollections(this, name, options);
}

@@ -442,6 +434,11 @@

async collections(options?: ListCollectionsOptions): Promise<Collection[]> {
return await executeOperation(
this.client,
new CollectionsOperation(this, resolveOptions(this, options))
);
options = resolveOptions(this, options);
const collections = await this.listCollections({}, { ...options, nameOnly: true }).toArray();
return collections
.filter(
// Filter collections removing any illegal ones
({ name }) => !name.includes('$')
)
.map(({ name }) => new Collection(this, name, this.s.options));
}

@@ -448,0 +445,0 @@

import { type Document } from './bson';
import { AbstractCursor } from './cursor/abstract_cursor';
import { MongoAPIError } from './error';

@@ -126,49 +125,1 @@

}
/**
* @public
*
* A base class for any cursors that have `explain()` methods.
*/
export abstract class ExplainableCursor<TSchema> extends AbstractCursor<TSchema> {
/** Execute the explain for the cursor */
abstract explain(): Promise<Document>;
abstract explain(verbosity: ExplainVerbosityLike | ExplainCommandOptions): Promise<Document>;
abstract explain(options: { timeoutMS?: number }): Promise<Document>;
abstract explain(
verbosity: ExplainVerbosityLike | ExplainCommandOptions,
options: { timeoutMS?: number }
): Promise<Document>;
abstract explain(
verbosity?: ExplainVerbosityLike | ExplainCommandOptions | { timeoutMS?: number },
options?: { timeoutMS?: number }
): Promise<Document>;
protected resolveExplainTimeoutOptions(
verbosity?: ExplainVerbosityLike | ExplainCommandOptions | { timeoutMS?: number },
options?: { timeoutMS?: number }
): { timeout?: { timeoutMS?: number }; explain?: ExplainVerbosityLike | ExplainCommandOptions } {
let explain: ExplainVerbosityLike | ExplainCommandOptions | undefined;
let timeout: { timeoutMS?: number } | undefined;
if (verbosity == null && options == null) {
explain = undefined;
timeout = undefined;
} else if (verbosity != null && options == null) {
explain =
typeof verbosity !== 'object'
? verbosity
: 'verbosity' in verbosity
? verbosity
: undefined;
timeout = typeof verbosity === 'object' && 'timeoutMS' in verbosity ? verbosity : undefined;
} else {
// @ts-expect-error TS isn't smart enough to determine that if both options are provided, the first is explain options
explain = verbosity;
timeout = options;
}
return { timeout, explain };
}
}

@@ -13,3 +13,2 @@ import { Admin } from './admin';

import { Db } from './db';
import { ExplainableCursor } from './explain';
import { GridFSBucket } from './gridfs';

@@ -48,2 +47,3 @@ import { GridFSBucketReadStream } from './gridfs/download';

export { ChangeStreamCursor } from './cursor/change_stream_cursor';
export { ExplainableCursor } from './cursor/explainable_cursor';
export {

@@ -103,3 +103,2 @@ MongoAPIError,

Db,
ExplainableCursor,
FindCursor,

@@ -249,3 +248,4 @@ GridFSBucket,

KMIPEncryptionKeyOptions,
RangeOptions
RangeOptions,
TextQueryOptions
} from './client-side-encryption/client_encryption';

@@ -530,3 +530,3 @@ export {

export type { EstimatedDocumentCountOptions } from './operations/estimated_document_count';
export type { FindOptions } from './operations/find';
export type { FindOneOptions, FindOptions } from './operations/find';
export type {

@@ -533,0 +533,0 @@ FindOneAndDeleteOptions,

@@ -5,2 +5,3 @@ import { promises as fs } from 'fs';

import { type ServerCommandOptions, type TimeoutContext } from '.';
import { type BSONSerializeOptions, type Document, resolveBSONOptions } from './bson';

@@ -24,2 +25,3 @@ import { ChangeStream, type ChangeStreamDocument, type ChangeStreamOptions } from './change_stream';

import type { CompressorName } from './cmap/wire_protocol/compression';
import { MongoDBResponse } from './cmap/wire_protocol/responses';
import { parseOptions, resolveSRVRecord } from './connection_string';

@@ -47,3 +49,3 @@ import { MONGO_CLIENT_EVENTS } from './constants';

import { executeOperation } from './operations/execute_operation';
import { RunAdminCommandOperation } from './operations/run_command';
import { AbstractOperation } from './operations/operation';
import type { ReadConcern, ReadConcernLevel, ReadConcernLike } from './read_concern';

@@ -66,3 +68,3 @@ import { ReadPreference, type ReadPreferenceMode } from './read_preference';

isHostMatch,
type MongoDBNamespace,
MongoDBNamespace,
noop,

@@ -797,9 +799,22 @@ ns,

try {
await executeOperation(
this,
new RunAdminCommandOperation(
{ endSessions },
{ readPreference: ReadPreference.primaryPreferred, noResponse: true }
)
);
class EndSessionsOperation extends AbstractOperation<void> {
override ns = MongoDBNamespace.fromString('admin.$cmd');
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override buildCommand(_connection: Connection, _session?: ClientSession): Document {
return {
endSessions
};
}
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
return {
timeoutContext,
readPreference: ReadPreference.primaryPreferred,
noResponse: true
};
}
override get commandName(): string {
return 'endSessions';
}
}
await executeOperation(this, new EndSessionsOperation());
} catch (error) {

@@ -806,0 +821,0 @@ squashError(error);

@@ -0,1 +1,2 @@

import { type Connection } from '..';
import type { Document } from '../bson';

@@ -6,5 +7,2 @@ import { CursorResponse, ExplainedCursorResponse } from '../cmap/wire_protocol/responses';

import { type ExplainOptions } from '../explain';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { maxWireVersion, type MongoDBNamespace } from '../utils';

@@ -56,2 +54,3 @@ import { WriteConcern } from '../write_concern';

export class AggregateOperation extends CommandOperation<CursorResponse> {
override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
override options: AggregateOptions;

@@ -84,5 +83,3 @@ target: string | typeof DB_AGGREGATE_COLLECTION;

if (this.hasWriteStage) {
this.trySecondaryWrite = true;
} else {
if (!this.hasWriteStage) {
delete this.options.writeConcern;

@@ -100,2 +97,4 @@ }

}
this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? ExplainedCursorResponse : CursorResponse;
}

@@ -115,9 +114,5 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<CursorResponse> {
const options: AggregateOptions = this.options;
const serverWireVersion = maxWireVersion(server);
override buildCommandDocument(connection: Connection): Document {
const options = this.options;
const serverWireVersion = maxWireVersion(connection);
const command: Document = { aggregate: this.target, pipeline: this.pipeline };

@@ -160,10 +155,10 @@

return await super.executeCommand(
server,
session,
command,
timeoutContext,
this.explain ? ExplainedCursorResponse : CursorResponse
);
return command;
}
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): CursorResponse {
return response;
}
}

@@ -170,0 +165,0 @@

@@ -1,10 +0,8 @@

import { MongoClientBulkWriteExecutionError, ServerType } from '../../beta';
import { type Connection } from '../../cmap/connection';
import { ClientBulkWriteCursorResponse } from '../../cmap/wire_protocol/responses';
import type { Server } from '../../sdam/server';
import type { ClientSession } from '../../sessions';
import { type TimeoutContext } from '../../timeout';
import { MongoDBNamespace } from '../../utils';
import { CommandOperation } from '../command';
import { Aspect, defineAspects } from '../operation';
import { type ClientBulkWriteCommandBuilder } from './command_builder';
import { type ClientBulkWriteCommand, type ClientBulkWriteCommandBuilder } from './command_builder';
import { type ClientBulkWriteOptions } from './common';

@@ -17,2 +15,4 @@

export class ClientBulkWriteOperation extends CommandOperation<ClientBulkWriteCursorResponse> {
override SERVER_COMMAND_RESPONSE_TYPE = ClientBulkWriteCursorResponse;
commandBuilder: ClientBulkWriteCommandBuilder;

@@ -40,68 +40,24 @@ override options: ClientBulkWriteOptions;

/**
* Execute the command. Superclass will handle write concern, etc.
* @param server - The server.
* @param session - The session.
* @returns The response.
*/
override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<ClientBulkWriteCursorResponse> {
let command;
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): ClientBulkWriteCursorResponse {
return response;
}
if (server.description.type === ServerType.LoadBalancer) {
if (session) {
let connection;
if (!session.pinnedConnection) {
// Checkout a connection to build the command.
connection = await server.pool.checkOut({ timeoutContext });
// Pin the connection to the session so it get used to execute the command and we do not
// perform a double check-in/check-out.
session.pin(connection);
} else {
connection = session.pinnedConnection;
}
command = this.commandBuilder.buildBatch(
connection.hello?.maxMessageSizeBytes,
connection.hello?.maxWriteBatchSize,
connection.hello?.maxBsonObjectSize
);
} else {
throw new MongoClientBulkWriteExecutionError(
'Session provided to the client bulk write operation must be present.'
);
}
} else {
// At this point we have a server and the auto connect code has already
// run in executeOperation, so the server description will be populated.
// We can use that to build the command.
if (
!server.description.maxWriteBatchSize ||
!server.description.maxMessageSizeBytes ||
!server.description.maxBsonObjectSize
) {
throw new MongoClientBulkWriteExecutionError(
'In order to execute a client bulk write, both maxWriteBatchSize, maxMessageSizeBytes and maxBsonObjectSize must be provided by the servers hello response.'
);
}
command = this.commandBuilder.buildBatch(
server.description.maxMessageSizeBytes,
server.description.maxWriteBatchSize,
server.description.maxBsonObjectSize
);
}
override buildCommandDocument(
connection: Connection,
_session?: ClientSession
): ClientBulkWriteCommand {
const command = this.commandBuilder.buildBatch(
connection.description.maxMessageSizeBytes,
connection.description.maxWriteBatchSize,
connection.description.maxBsonObjectSize
);
// Check after the batch is built if we cannot retry it and override the option.
// Check _after_ the batch is built if we cannot retry it and override the option.
if (!this.canRetryWrite) {
this.options.willRetryWrite = false;
}
return await super.executeCommand(
server,
session,
command,
timeoutContext,
ClientBulkWriteCursorResponse
);
return command;
}

@@ -108,0 +64,0 @@ }

@@ -0,3 +1,3 @@

import { type Connection } from '..';
import type { BSONSerializeOptions, Document } from '../bson';
import { type MongoDBResponseConstructor } from '../cmap/wire_protocol/responses';
import { MongoInvalidArgumentError } from '../error';

@@ -12,7 +12,6 @@ import {

import type { ReadPreference } from '../read_preference';
import type { Server } from '../sdam/server';
import { MIN_SECONDARY_WRITE_WIRE_VERSION } from '../sdam/server_selection';
import type { ServerCommandOptions } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { commandSupportsReadConcern, maxWireVersion, MongoDBNamespace } from '../utils';
import { commandSupportsReadConcern, MongoDBNamespace } from '../utils';
import { WriteConcern, type WriteConcernOptions } from '../write_concern';

@@ -121,27 +120,6 @@ import type { ReadConcernLike } from './../read_concern';

public async executeCommand<T extends MongoDBResponseConstructor>(
server: Server,
session: ClientSession | undefined,
cmd: Document,
timeoutContext: TimeoutContext,
responseType: T | undefined
): Promise<typeof responseType extends undefined ? Document : InstanceType<T>>;
abstract buildCommandDocument(connection: Connection, session?: ClientSession): Document;
public async executeCommand(
server: Server,
session: ClientSession | undefined,
cmd: Document,
timeoutContext: TimeoutContext
): Promise<Document>;
async executeCommand(
server: Server,
session: ClientSession | undefined,
cmd: Document,
timeoutContext: TimeoutContext,
responseType?: MongoDBResponseConstructor
): Promise<Document> {
this.server = server;
const options = {
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
return {
...this.options,

@@ -151,38 +129,37 @@ ...this.bsonOptions,

readPreference: this.readPreference,
session
session: this.session
};
}
const serverWireVersion = maxWireVersion(server);
override buildCommand(connection: Connection, session?: ClientSession): Document {
const command = this.buildCommandDocument(connection, session);
const inTransaction = this.session && this.session.inTransaction();
if (this.readConcern && commandSupportsReadConcern(cmd) && !inTransaction) {
Object.assign(cmd, { readConcern: this.readConcern });
if (this.readConcern && commandSupportsReadConcern(command) && !inTransaction) {
Object.assign(command, { readConcern: this.readConcern });
}
if (this.trySecondaryWrite && serverWireVersion < MIN_SECONDARY_WRITE_WIRE_VERSION) {
options.omitReadPreference = true;
}
if (this.writeConcern && this.hasAspect(Aspect.WRITE_OPERATION) && !inTransaction) {
WriteConcern.apply(cmd, this.writeConcern);
WriteConcern.apply(command, this.writeConcern);
}
if (
options.collation &&
typeof options.collation === 'object' &&
this.options.collation &&
typeof this.options.collation === 'object' &&
!this.hasAspect(Aspect.SKIP_COLLATION)
) {
Object.assign(cmd, { collation: options.collation });
Object.assign(command, { collation: this.options.collation });
}
if (typeof options.maxTimeMS === 'number') {
cmd.maxTimeMS = options.maxTimeMS;
if (typeof this.options.maxTimeMS === 'number') {
command.maxTimeMS = this.options.maxTimeMS;
}
if (this.hasAspect(Aspect.EXPLAINABLE) && this.explain) {
cmd = decorateWithExplain(cmd, this.explain);
return decorateWithExplain(command, this.explain);
}
return await server.command(this.ns, cmd, options, responseType);
return command;
}
}

@@ -0,6 +1,6 @@

import { type Connection } from '..';
import type { Document } from '../bson';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import type { Collection } from '../collection';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import type { MongoDBNamespace } from '../utils';

@@ -26,2 +26,3 @@ import { CommandOperation, type CommandOperationOptions } from './command';

export class CountOperation extends CommandOperation<number> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: CountOptions;

@@ -43,7 +44,3 @@ collectionName?: string;

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<number> {
override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
const options = this.options;

@@ -71,7 +68,10 @@ const cmd: Document = {

const result = await super.executeCommand(server, session, cmd, timeoutContext);
return result ? result.n : 0;
return cmd;
}
override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): number {
return response.getNumber('n') ?? 0;
}
}
defineAspects(CountOperation, [Aspect.READ_OPERATION, Aspect.RETRYABLE]);

@@ -0,1 +1,2 @@

import { type Connection } from '..';
import type { Document } from '../bson';

@@ -6,2 +7,3 @@ import {

} from '../cmap/wire_protocol/constants';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import { Collection } from '../collection';

@@ -11,6 +13,7 @@ import type { Db } from '../db';

import type { PkFactory } from '../mongo_client';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { TimeoutContext } from '../timeout';
import { maxWireVersion } from '../utils';
import { CommandOperation, type CommandOperationOptions } from './command';
import { executeOperation } from './execute_operation';
import { CreateIndexesOperation } from './indexes';

@@ -115,2 +118,3 @@ import { Aspect, defineAspects } from './operation';

export class CreateCollectionOperation extends CommandOperation<Collection> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: CreateCollectionOptions;

@@ -132,86 +136,90 @@ db: Db;

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<Collection> {
const db = this.db;
const name = this.name;
const options = this.options;
override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
const isOptionValid = ([k, v]: [k: string, v: unknown]) =>
v != null && typeof v !== 'function' && !ILLEGAL_COMMAND_FIELDS.has(k);
return {
create: this.name,
...Object.fromEntries(Object.entries(this.options).filter(isOptionValid))
};
}
const encryptedFields: Document | undefined =
options.encryptedFields ??
db.client.s.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
override handleOk(
_response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): Collection<Document> {
return new Collection(this.db, this.name, this.options);
}
}
if (encryptedFields) {
// Creating a QE collection required min server of 7.0.0
// TODO(NODE-5353): Get wire version information from connection.
if (
!server.loadBalanced &&
server.description.maxWireVersion < MIN_SUPPORTED_QE_WIRE_VERSION
) {
throw new MongoCompatibilityError(
`${INVALID_QE_VERSION} The minimum server version required is ${MIN_SUPPORTED_QE_SERVER_VERSION}`
);
}
// Create auxilliary collections for queryable encryption support.
const escCollection = encryptedFields.escCollection ?? `enxcol_.${name}.esc`;
const ecocCollection = encryptedFields.ecocCollection ?? `enxcol_.${name}.ecoc`;
export async function createCollections<TSchema extends Document>(
db: Db,
name: string,
options: CreateCollectionOptions
): Promise<Collection<TSchema>> {
const timeoutContext = TimeoutContext.create({
session: options.session,
serverSelectionTimeoutMS: db.client.s.options.serverSelectionTimeoutMS,
waitQueueTimeoutMS: db.client.s.options.waitQueueTimeoutMS,
timeoutMS: options.timeoutMS
});
for (const collectionName of [escCollection, ecocCollection]) {
const createOp = new CreateCollectionOperation(db, collectionName, {
clusteredIndex: {
key: { _id: 1 },
unique: true
}
});
await createOp.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
}
const encryptedFields: Document | undefined =
options.encryptedFields ??
db.client.s.options.autoEncryption?.encryptedFieldsMap?.[`${db.databaseName}.${name}`];
if (!options.encryptedFields) {
this.options = { ...this.options, encryptedFields };
if (encryptedFields) {
class CreateSupportingFLEv2CollectionOperation extends CreateCollectionOperation {
override buildCommandDocument(connection: Connection, session?: ClientSession): Document {
if (
!connection.description.loadBalanced &&
maxWireVersion(connection) < MIN_SUPPORTED_QE_WIRE_VERSION
) {
throw new MongoCompatibilityError(
`${INVALID_QE_VERSION} The minimum server version required is ${MIN_SUPPORTED_QE_SERVER_VERSION}`
);
}
return super.buildCommandDocument(connection, session);
}
}
const coll = await this.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
// Create auxilliary collections for queryable encryption support.
const escCollection = encryptedFields.escCollection ?? `enxcol_.${name}.esc`;
const ecocCollection = encryptedFields.ecocCollection ?? `enxcol_.${name}.ecoc`;
if (encryptedFields) {
// Create the required index for queryable encryption support.
const createIndexOp = CreateIndexesOperation.fromIndexSpecification(
db,
name,
{ __safeContent__: 1 },
{}
);
await createIndexOp.execute(server, session, timeoutContext);
for (const collectionName of [escCollection, ecocCollection]) {
const createOp = new CreateSupportingFLEv2CollectionOperation(db, collectionName, {
clusteredIndex: {
key: { _id: 1 },
unique: true
},
session: options.session
});
await executeOperation(db.client, createOp, timeoutContext);
}
return coll;
if (!options.encryptedFields) {
options = { ...options, encryptedFields };
}
}
private async executeWithoutEncryptedFieldsCheck(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<Collection> {
const db = this.db;
const name = this.name;
const options = this.options;
const coll = await executeOperation(
db.client,
new CreateCollectionOperation(db, name, options),
timeoutContext
);
const cmd: Document = { create: name };
for (const n in options) {
if (
(options as any)[n] != null &&
typeof (options as any)[n] !== 'function' &&
!ILLEGAL_COMMAND_FIELDS.has(n)
) {
cmd[n] = (options as any)[n];
}
}
// otherwise just execute the command
await super.executeCommand(server, session, cmd, timeoutContext);
return new Collection(db, name, options);
if (encryptedFields) {
// Create the required index for queryable encryption support.
const createIndexOp = CreateIndexesOperation.fromIndexSpecification(
db,
name,
{ __safeContent__: 1 },
{ session: options.session }
);
await executeOperation(db.client, createIndexOp, timeoutContext);
}
return coll as unknown as Collection<TSchema>;
}
defineAspects(CreateCollectionOperation, [Aspect.WRITE_OPERATION]);
import type { Document } from '../bson';
import type { Collection } from '../collection';
import { type Connection } from '../cmap/connection';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import { MongoCompatibilityError, MongoServerError } from '../error';
import { type TODO_NODE_3286 } from '../mongo_types';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { type MongoDBNamespace } from '../utils';
import { type MongoDBCollectionNamespace, type MongoDBNamespace } from '../utils';
import { type WriteConcernOptions } from '../write_concern';

@@ -46,3 +44,4 @@ import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command';

/** @internal */
export class DeleteOperation extends CommandOperation<DeleteResult> {
export class DeleteOperation extends CommandOperation<Document> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: DeleteOptions;

@@ -70,8 +69,5 @@ statements: DeleteStatement[];

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<DeleteResult> {
const options = this.options ?? {};
override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
const options = this.options;
const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;

@@ -102,9 +98,3 @@ const command: Document = {

const res: TODO_NODE_3286 = await super.executeCommand(
server,
session,
command,
timeoutContext
);
return res;
return command;
}

@@ -114,13 +104,14 @@ }

export class DeleteOneOperation extends DeleteOperation {
constructor(collection: Collection, filter: Document, options: DeleteOptions) {
super(collection.s.namespace, [makeDeleteStatement(filter, { ...options, limit: 1 })], options);
constructor(ns: MongoDBCollectionNamespace, filter: Document, options: DeleteOptions) {
super(ns, [makeDeleteStatement(filter, { ...options, limit: 1 })], options);
}
override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<DeleteResult> {
const res: TODO_NODE_3286 = await super.execute(server, session, timeoutContext);
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): DeleteResult {
const res = super.handleOk(response);
// @ts-expect-error Explain commands have broken TS
if (this.explain) return res;
if (res.code) throw new MongoServerError(res);

@@ -136,13 +127,14 @@ if (res.writeErrors) throw new MongoServerError(res.writeErrors[0]);

export class DeleteManyOperation extends DeleteOperation {
constructor(collection: Collection, filter: Document, options: DeleteOptions) {
super(collection.s.namespace, [makeDeleteStatement(filter, options)], options);
constructor(ns: MongoDBCollectionNamespace, filter: Document, options: DeleteOptions) {
super(ns, [makeDeleteStatement(filter, options)], options);
}
override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<DeleteResult> {
const res: TODO_NODE_3286 = await super.execute(server, session, timeoutContext);
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): DeleteResult {
const res = super.handleOk(response);
// @ts-expect-error Explain commands have broken TS
if (this.explain) return res;
if (res.code) throw new MongoServerError(res);

@@ -149,0 +141,0 @@ if (res.writeErrors) throw new MongoServerError(res.writeErrors[0]);

@@ -1,7 +0,5 @@

import type { Document } from '../bson';
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 { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { decorateWithCollation, decorateWithReadConcern } from '../utils';
import { CommandOperation, type CommandOperationOptions } from './command';

@@ -30,3 +28,4 @@ import { Aspect, defineAspects } from './operation';

*/
export class DistinctOperation extends CommandOperation<any[]> {
export class DistinctOperation extends CommandOperation<any[] | Document> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: DistinctOptions;

@@ -60,44 +59,28 @@ collection: Collection;

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<any[]> {
const coll = this.collection;
const key = this.key;
const query = this.query;
const options = this.options;
// Distinct command
const cmd: Document = {
distinct: coll.collectionName,
key: key,
query: query
override buildCommandDocument(_connection: Connection): Document {
const command: Document = {
distinct: this.collection.collectionName,
key: this.key,
query: this.query
};
// Add maxTimeMS if defined
if (typeof options.maxTimeMS === 'number') {
cmd.maxTimeMS = options.maxTimeMS;
}
// we check for undefined specifically here to allow falsy values
// eslint-disable-next-line no-restricted-syntax
if (typeof options.comment !== 'undefined') {
cmd.comment = options.comment;
if (this.options.comment !== undefined) {
command.comment = this.options.comment;
}
if (options.hint != null) {
cmd.hint = options.hint;
if (this.options.hint != null) {
command.hint = this.options.hint;
}
// Do we have a readConcern specified
decorateWithReadConcern(cmd, coll, options);
return command;
}
// Have we specified collation
decorateWithCollation(cmd, coll, options);
const result = await super.executeCommand(server, session, cmd, timeoutContext);
// @ts-expect-error: Explain always returns a document
return this.explain ? result : result.values;
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): any[] | Document {
if (this.explain) {
return response.toObject(this.bsonOptions);
}
return response.toObject(this.bsonOptions).values;
}

@@ -104,0 +87,0 @@ }

@@ -0,8 +1,11 @@

import { type Connection, MongoServerError } from '..';
import type { Document } from '../bson';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import { CursorTimeoutContext } from '../cursor/abstract_cursor';
import type { Db } from '../db';
import { MONGODB_ERROR_CODES, MongoServerError } from '../error';
import type { Server } from '../sdam/server';
import { MONGODB_ERROR_CODES } from '../error';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { TimeoutContext } from '../timeout';
import { CommandOperation, type CommandOperationOptions } from './command';
import { executeOperation } from './execute_operation';
import { Aspect, defineAspects } from './operation';

@@ -18,4 +21,5 @@

export class DropCollectionOperation extends CommandOperation<boolean> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: DropCollectionOptions;
db: Db;
name: string;

@@ -25,3 +29,2 @@

super(db, options);
this.db = db;
this.options = options;

@@ -35,57 +38,70 @@ this.name = name;

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<boolean> {
const db = this.db;
const options = this.options;
const name = this.name;
override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
return { drop: this.name };
}
const encryptedFieldsMap = db.client.s.options.autoEncryption?.encryptedFieldsMap;
let encryptedFields: Document | undefined =
options.encryptedFields ?? encryptedFieldsMap?.[`${db.databaseName}.${name}`];
override handleOk(_response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): boolean {
return true;
}
}
if (!encryptedFields && encryptedFieldsMap) {
// If the MongoClient was configured with an encryptedFieldsMap,
// and no encryptedFields config was available in it or explicitly
// passed as an argument, the spec tells us to look one up using
// listCollections().
const listCollectionsResult = await db
.listCollections({ name }, { nameOnly: false })
.toArray();
encryptedFields = listCollectionsResult?.[0]?.options?.encryptedFields;
}
export async function dropCollections(
db: Db,
name: string,
options: DropCollectionOptions
): Promise<boolean> {
const timeoutContext = TimeoutContext.create({
session: options.session,
serverSelectionTimeoutMS: db.client.s.options.serverSelectionTimeoutMS,
waitQueueTimeoutMS: db.client.s.options.waitQueueTimeoutMS,
timeoutMS: options.timeoutMS
});
if (encryptedFields) {
const escCollection = encryptedFields.escCollection || `enxcol_.${name}.esc`;
const ecocCollection = encryptedFields.ecocCollection || `enxcol_.${name}.ecoc`;
const encryptedFieldsMap = db.client.s.options.autoEncryption?.encryptedFieldsMap;
let encryptedFields: Document | undefined =
options.encryptedFields ?? encryptedFieldsMap?.[`${db.databaseName}.${name}`];
for (const collectionName of [escCollection, ecocCollection]) {
// Drop auxilliary collections, ignoring potential NamespaceNotFound errors.
const dropOp = new DropCollectionOperation(db, collectionName);
try {
await dropOp.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
} catch (err) {
if (
!(err instanceof MongoServerError) ||
err.code !== MONGODB_ERROR_CODES.NamespaceNotFound
) {
throw err;
}
if (!encryptedFields && encryptedFieldsMap) {
// If the MongoClient was configured with an encryptedFieldsMap,
// and no encryptedFields config was available in it or explicitly
// passed as an argument, the spec tells us to look one up using
// listCollections().
const listCollectionsResult = await db
.listCollections(
{ name },
{
nameOnly: false,
session: options.session,
timeoutContext: new CursorTimeoutContext(timeoutContext, Symbol())
}
)
.toArray();
encryptedFields = listCollectionsResult?.[0]?.options?.encryptedFields;
}
if (encryptedFields) {
const escCollection = encryptedFields.escCollection || `enxcol_.${name}.esc`;
const ecocCollection = encryptedFields.ecocCollection || `enxcol_.${name}.ecoc`;
for (const collectionName of [escCollection, ecocCollection]) {
// Drop auxilliary collections, ignoring potential NamespaceNotFound errors.
const dropOp = new DropCollectionOperation(db, collectionName, options);
try {
await executeOperation(db.client, dropOp, timeoutContext);
} catch (err) {
if (
!(err instanceof MongoServerError) ||
err.code !== MONGODB_ERROR_CODES.NamespaceNotFound
) {
throw err;
}
}
}
return await this.executeWithoutEncryptedFieldsCheck(server, session, timeoutContext);
}
private async executeWithoutEncryptedFieldsCheck(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<boolean> {
await super.executeCommand(server, session, { drop: this.name }, timeoutContext);
return true;
}
return await executeOperation(
db.client,
new DropCollectionOperation(db, name, options),
timeoutContext
);
}

@@ -98,2 +114,3 @@

export class DropDatabaseOperation extends CommandOperation<boolean> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: DropDatabaseOptions;

@@ -109,8 +126,7 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<boolean> {
await super.executeCommand(server, session, { dropDatabase: 1 }, timeoutContext);
override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
return { dropDatabase: 1 };
}
override handleOk(_response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): boolean {
return true;

@@ -117,0 +133,0 @@ }

@@ -0,6 +1,6 @@

import { type Connection } from '..';
import type { Document } from '../bson';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import type { Collection } from '../collection';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { CommandOperation, type CommandOperationOptions } from './command';

@@ -21,2 +21,3 @@ import { Aspect, defineAspects } from './operation';

export class EstimatedDocumentCountOperation extends CommandOperation<number> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: EstimatedDocumentCountOptions;

@@ -35,7 +36,3 @@ collectionName: string;

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<number> {
override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
const cmd: Document = { count: this.collectionName };

@@ -53,5 +50,7 @@

const response = await super.executeCommand(server, session, cmd, timeoutContext);
return cmd;
}
return response?.n || 0;
override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): number {
return response.getNumber('n') ?? 0;
}

@@ -58,0 +57,0 @@ }

@@ -29,2 +29,3 @@ import {

import { abortable, supportsRetryableWrites } from '../utils';
import { AggregateOperation } from './aggregate';
import { AbstractOperation, Aspect } from './operation';

@@ -36,4 +37,5 @@

type ResultTypeFromOperation<TOperation> =
TOperation extends AbstractOperation<infer K> ? K : never;
type ResultTypeFromOperation<TOperation extends AbstractOperation> = ReturnType<
TOperation['handleOk']
>;

@@ -61,3 +63,3 @@ /**

export async function executeOperation<
T extends AbstractOperation<TResult>,
T extends AbstractOperation,
TResult = ResultTypeFromOperation<T>

@@ -91,2 +93,4 @@ >(client: MongoClient, operation: T, timeoutContext?: TimeoutContext | null): Promise<TResult> {

operation.session ??= session;
const readPreference = operation.readPreference ?? ReadPreference.primary;

@@ -136,3 +140,3 @@ const inTransaction = !!session?.inTransaction();

*/
async function autoConnect(client: MongoClient): Promise<Topology> {
export async function autoConnect(client: MongoClient): Promise<Topology> {
if (client.topology == null) {

@@ -184,6 +188,3 @@ if (client.s.hasBeenClosed) {

* */
async function tryOperation<
T extends AbstractOperation<TResult>,
TResult = ResultTypeFromOperation<T>
>(
async function tryOperation<T extends AbstractOperation, TResult = ResultTypeFromOperation<T>>(
operation: T,

@@ -199,3 +200,3 @@ { topology, timeoutContext, session, readPreference }: RetryOptions

selector = sameServerSelector(operation.server?.description);
} else if (operation.trySecondaryWrite) {
} else if (operation instanceof AggregateOperation && operation.hasWriteStage) {
// If operation should try to write to secondary use the custom server selector

@@ -258,4 +259,5 @@ // otherwise provide the read preference.

if (hasReadAspect && !isRetryableReadError(previousOperationError))
if (hasReadAspect && !isRetryableReadError(previousOperationError)) {
throw previousOperationError;
}

@@ -286,2 +288,4 @@ if (

operation.server = server;
try {

@@ -292,3 +296,9 @@ // If tries > 0 and we are command batching we need to reset the batch.

}
return await operation.execute(server, session, timeoutContext);
try {
const result = await server.command(operation, timeoutContext);
return operation.handleOk(result);
} catch (error) {
return operation.handleError(error);
}
} catch (operationError) {

@@ -295,0 +305,0 @@ if (!(operationError instanceof MongoError)) throw operationError;

@@ -0,10 +1,10 @@

import { type Connection } from '..';
import type { Document } from '../bson';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import type { Collection } from '../collection';
import { MongoCompatibilityError, MongoInvalidArgumentError } from '../error';
import { ReadPreference } from '../read_preference';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { formatSort, type Sort, type SortForCmd } from '../sort';
import { type TimeoutContext } from '../timeout';
import { decorateWithCollation, hasAtomicOperators, maxWireVersion } from '../utils';
import { decorateWithCollation, hasAtomicOperators } from '../utils';
import { type WriteConcern, type WriteConcernSettings } from '../write_concern';

@@ -124,4 +124,4 @@ import { CommandOperation, type CommandOperationOptions } from './command';

export class FindAndModifyOperation extends CommandOperation<Document> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: FindOneAndReplaceOptions | FindOneAndUpdateOptions | FindOneAndDeleteOptions;
cmdBase: FindAndModifyCmdBase;
collection: Collection;

@@ -137,4 +137,22 @@ query: Document;

super(collection, options);
this.options = options ?? {};
this.cmdBase = {
this.options = options;
// force primary read preference
this.readPreference = ReadPreference.primary;
this.collection = collection;
this.query = query;
}
override get commandName() {
return 'findAndModify' as const;
}
override buildCommandDocument(
_connection: Connection,
_session?: ClientSession
): Document & FindAndModifyCmdBase {
const options = this.options;
const command: Document & FindAndModifyCmdBase = {
findAndModify: this.collection.collectionName,
query: this.query,
remove: false,

@@ -149,11 +167,11 @@ new: false,

if (sort) {
this.cmdBase.sort = sort;
command.sort = sort;
}
if (options.projection) {
this.cmdBase.fields = options.projection;
command.fields = options.projection;
}
if (options.maxTimeMS) {
this.cmdBase.maxTimeMS = options.maxTimeMS;
command.maxTimeMS = options.maxTimeMS;
}

@@ -163,7 +181,7 @@

if (options.writeConcern) {
this.cmdBase.writeConcern = options.writeConcern;
command.writeConcern = options.writeConcern;
}
if (options.let) {
this.cmdBase.let = options.let;
command.let = options.let;
}

@@ -174,39 +192,10 @@

if (options.comment !== undefined) {
this.cmdBase.comment = options.comment;
command.comment = options.comment;
}
// force primary read preference
this.readPreference = ReadPreference.primary;
decorateWithCollation(command, this.collection, options);
this.collection = collection;
this.query = query;
}
override get commandName() {
return 'findAndModify' as const;
}
override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<Document> {
const coll = this.collection;
const query = this.query;
const options = { ...this.options, ...this.bsonOptions };
// Create findAndModify command object
const cmd: Document = {
findAndModify: coll.collectionName,
query: query,
...this.cmdBase
};
decorateWithCollation(cmd, coll, options);
if (options.hint) {
// TODO: once this method becomes a CommandOperation we will have the server
// in place to check.
const unacknowledgedWrite = this.writeConcern?.w === 0;
if (unacknowledgedWrite || maxWireVersion(server) < 8) {
if (unacknowledgedWrite) {
throw new MongoCompatibilityError(

@@ -217,9 +206,12 @@ 'The current topology does not support a hint on findAndModify commands'

cmd.hint = options.hint;
command.hint = options.hint;
}
// Execute the command
const result = await super.executeCommand(server, session, cmd, timeoutContext);
return options.includeResultMetadata ? result : (result.value ?? null);
return command;
}
override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): Document {
const result = super.handleOk(response);
return this.options.includeResultMetadata ? result : (result.value ?? null);
}
}

@@ -236,4 +228,12 @@

super(collection, filter, options);
this.cmdBase.remove = true;
}
override buildCommandDocument(
connection: Connection,
session?: ClientSession
): Document & FindAndModifyCmdBase {
const document = super.buildCommandDocument(connection, session);
document.remove = true;
return document;
}
}

@@ -243,2 +243,3 @@

export class FindOneAndReplaceOperation extends FindAndModifyOperation {
private replacement: Document;
constructor(

@@ -263,5 +264,14 @@ collection: Collection,

super(collection, filter, options);
this.cmdBase.update = replacement;
configureFindAndModifyCmdBaseUpdateOpts(this.cmdBase, options);
this.replacement = replacement;
}
override buildCommandDocument(
connection: Connection,
session?: ClientSession
): Document & FindAndModifyCmdBase {
const document = super.buildCommandDocument(connection, session);
document.update = this.replacement;
configureFindAndModifyCmdBaseUpdateOpts(document, this.options);
return document;
}
}

@@ -271,2 +281,5 @@

export class FindOneAndUpdateOperation extends FindAndModifyOperation {
override options: FindOneAndUpdateOptions;
private update: Document;
constructor(

@@ -291,8 +304,19 @@ collection: Collection,

super(collection, filter, options);
this.cmdBase.update = update;
configureFindAndModifyCmdBaseUpdateOpts(this.cmdBase, options);
this.update = update;
this.options = options;
}
if (options.arrayFilters) {
this.cmdBase.arrayFilters = options.arrayFilters;
override buildCommandDocument(
connection: Connection,
session?: ClientSession
): Document & FindAndModifyCmdBase {
const document = super.buildCommandDocument(connection, session);
document.update = this.update;
configureFindAndModifyCmdBaseUpdateOpts(document, this.options);
if (this.options.arrayFilters) {
document.arrayFilters = this.options.arrayFilters;
}
return document;
}

@@ -299,0 +323,0 @@ }

@@ -5,10 +5,4 @@ import type { Document } from '../bson';

import { MongoInvalidArgumentError } from '../error';
import {
decorateWithExplain,
type ExplainOptions,
validateExplainTimeoutOptions
} from '../explain';
import { ReadConcern } from '../read_concern';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type ExplainOptions } from '../explain';
import type { ServerCommandOptions } from '../sdam/server';
import { formatSort, type Sort } from '../sort';

@@ -85,4 +79,16 @@ import { type TimeoutContext } from '../timeout';

/** @public */
export interface FindOneOptions extends FindOptions {
/** @deprecated Will be removed in the next major version. User provided value will be ignored. */
batchSize?: number;
/** @deprecated Will be removed in the next major version. User provided value will be ignored. */
limit?: number;
/** @deprecated Will be removed in the next major version. User provided value will be ignored. */
noCursorTimeout?: boolean;
}
/** @internal */
export class FindOperation extends CommandOperation<CursorResponse> {
override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
/**

@@ -111,2 +117,4 @@ * @remarks WriteConcern can still be present on the options because

this.filter = filter != null && filter._bsontype === 'ObjectId' ? { _id: filter } : filter;
this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? ExplainedCursorResponse : CursorResponse;
}

@@ -118,29 +126,20 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<CursorResponse> {
this.server = server;
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
return {
...this.options,
...this.bsonOptions,
documentsReturnedIn: 'firstBatch',
session: this.session,
timeoutContext
};
}
const options = this.options;
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): CursorResponse {
return response;
}
let findCommand = makeFindCommand(this.ns, this.filter, options);
if (this.explain) {
validateExplainTimeoutOptions(this.options, this.explain);
findCommand = decorateWithExplain(findCommand, this.explain);
}
return await server.command(
this.ns,
findCommand,
{
...this.options,
...this.bsonOptions,
documentsReturnedIn: 'firstBatch',
session,
timeoutContext
},
this.explain ? ExplainedCursorResponse : CursorResponse
);
override buildCommandDocument(): Document {
return makeFindCommand(this.ns, this.filter, this.options);
}

@@ -192,13 +191,11 @@ }

if (options.batchSize < 0) {
if (
options.limit &&
options.limit !== 0 &&
Math.abs(options.batchSize) < Math.abs(options.limit)
) {
findCommand.limit = -options.batchSize;
findCommand.limit = -options.batchSize;
} else {
if (options.batchSize === options.limit) {
// Spec dictates that if these are equal the batchSize should be one more than the
// limit to avoid leaving the cursor open.
findCommand.batchSize = options.batchSize + 1;
} else {
findCommand.batchSize = options.batchSize;
}
findCommand.singleBatch = true;
} else {
findCommand.batchSize = options.batchSize;
}

@@ -217,11 +214,2 @@ }

if (typeof options.maxTimeMS === 'number') {
findCommand.maxTimeMS = options.maxTimeMS;
}
const readConcern = ReadConcern.fromOptions(options);
if (readConcern) {
findCommand.readConcern = readConcern.toJSON();
}
if (options.max) {

@@ -264,7 +252,2 @@ findCommand.max = options.max;

}
if (options.collation) {
findCommand.collation = options.collation;
}
if (typeof options.allowDiskUse === 'boolean') {

@@ -271,0 +254,0 @@ findCommand.allowDiskUse = options.allowDiskUse;

@@ -1,6 +0,6 @@

import type { Long } from '../bson';
import type { Document, Long } from '../bson';
import { type Connection } from '../cmap/connection';
import { CursorResponse } from '../cmap/wire_protocol/responses';
import { MongoRuntimeError } from '../error';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import type { Server, ServerCommandOptions } from '../sdam/server';
import { type TimeoutContext } from '../timeout';

@@ -40,3 +40,4 @@ import { maxWireVersion, type MongoDBNamespace } from '../utils';

/** @internal */
export class GetMoreOperation extends AbstractOperation {
export class GetMoreOperation extends AbstractOperation<CursorResponse> {
override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
cursorId: Long;

@@ -57,15 +58,4 @@ override options: GetMoreOptions;

}
/**
* Although there is a server already associated with the get more operation, the signature
* for execute passes a server so we will just use that one.
*/
override async execute(
server: Server,
_session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<CursorResponse> {
if (server !== this.server) {
throw new MongoRuntimeError('Getmore must run on the same server operation began on');
}
override buildCommand(connection: Connection): Document {
if (this.cursorId == null || this.cursorId.isZero()) {

@@ -97,7 +87,11 @@ throw new MongoRuntimeError('Unable to iterate cursor with no id');

// eslint-disable-next-line no-restricted-syntax
if (this.options.comment !== undefined && maxWireVersion(server) >= 9) {
if (this.options.comment !== undefined && maxWireVersion(connection) >= 9) {
getMoreCmd.comment = this.options.comment;
}
const commandOptions = {
return getMoreCmd;
}
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
return {
returnFieldSelector: null,

@@ -108,4 +102,8 @@ documentsReturnedIn: 'nextBatch',

};
}
return await server.command(this.ns, getMoreCmd, commandOptions, CursorResponse);
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): CursorResponse {
return response;
}

@@ -112,0 +110,0 @@ }

import type { Document } from '../bson';
import { CursorResponse } from '../cmap/wire_protocol/responses';
import { type Connection } from '../cmap/connection';
import { CursorResponse, MongoDBResponse } from '../cmap/wire_protocol/responses';
import type { Collection } from '../collection';

@@ -7,5 +8,2 @@ import { type AbstractCursorOptions } from '../cursor/abstract_cursor';

import { type OneOrMore } from '../mongo_types';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { isObject, maxWireVersion, type MongoDBNamespace } from '../utils';

@@ -249,2 +247,3 @@ import {

export class CreateIndexesOperation extends CommandOperation<string[]> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: CreateIndexesOptions;

@@ -263,2 +262,4 @@ collectionName: string;

this.options = options ?? {};
// collation is set on each index, it should not be defined at the root
this.options.collation = undefined;
this.collectionName = collectionName;

@@ -277,2 +278,3 @@ this.indexes = indexes.map((userIndex: IndexDescription): ResolvedIndexDescription => {

});
this.ns = parent.s.namespace;
}

@@ -304,11 +306,7 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<string[]> {
override buildCommandDocument(connection: Connection): Document {
const options = this.options;
const indexes = this.indexes;
const serverWireVersion = maxWireVersion(server);
const serverWireVersion = maxWireVersion(connection);

@@ -325,9 +323,7 @@ const cmd: Document = { createIndexes: this.collectionName, indexes };

}
return cmd;
}
// collation is set on each index, it should not be defined at the root
this.options.collation = undefined;
await super.executeCommand(server, session, cmd, timeoutContext);
const indexNames = indexes.map(index => index.name || '');
override handleOk(_response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): string[] {
const indexNames = this.indexes.map(index => index.name || '');
return indexNames;

@@ -342,2 +338,3 @@ }

export class DropIndexOperation extends CommandOperation<Document> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: DropIndexesOptions;

@@ -353,2 +350,3 @@ collection: Collection;

this.indexName = indexName;
this.ns = collection.fullNamespace;
}

@@ -360,9 +358,4 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<Document> {
const cmd = { dropIndexes: this.collection.collectionName, index: this.indexName };
return await super.executeCommand(server, session, cmd, timeoutContext);
override buildCommandDocument(_connection: Connection): Document {
return { dropIndexes: this.collection.collectionName, index: this.indexName };
}

@@ -379,2 +372,3 @@ }

export class ListIndexesOperation extends CommandOperation<CursorResponse> {
override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
/**

@@ -402,8 +396,4 @@ * @remarks WriteConcern can still be present on the options because

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<CursorResponse> {
const serverWireVersion = maxWireVersion(server);
override buildCommandDocument(connection: Connection): Document {
const serverWireVersion = maxWireVersion(connection);

@@ -420,4 +410,10 @@ const cursor = this.options.batchSize ? { batchSize: this.options.batchSize } : {};

return await super.executeCommand(server, session, command, timeoutContext, CursorResponse);
return command;
}
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): CursorResponse {
return response;
}
}

@@ -424,0 +420,0 @@

@@ -0,18 +1,17 @@

import { type Connection } from '..';
import type { Document } from '../bson';
import type { BulkWriteOptions } from '../bulk/common';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import type { Collection } from '../collection';
import { MongoInvalidArgumentError, MongoServerError } from '../error';
import { MongoServerError } from '../error';
import type { InferIdType } from '../mongo_types';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { maybeAddIdToDocuments, type MongoDBNamespace } from '../utils';
import { WriteConcern } from '../write_concern';
import { BulkWriteOperation } from './bulk_write';
import { CommandOperation, type CommandOperationOptions } from './command';
import { AbstractOperation, Aspect, defineAspects } from './operation';
import { Aspect, defineAspects } from './operation';
/** @internal */
export class InsertOperation extends CommandOperation<Document> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: BulkWriteOptions;
documents: Document[];

@@ -31,7 +30,3 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<Document> {
override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
const options = this.options ?? {};

@@ -55,3 +50,3 @@ const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;

return await super.executeCommand(server, session, command, timeoutContext);
return command;
}

@@ -78,11 +73,7 @@ }

constructor(collection: Collection, doc: Document, options: InsertOneOptions) {
super(collection.s.namespace, maybeAddIdToDocuments(collection, [doc], options), options);
super(collection.s.namespace, [maybeAddIdToDocuments(collection, doc, options)], options);
}
override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<InsertOneResult> {
const res = await super.execute(server, session, timeoutContext);
override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): Document {
const res = super.handleOk(response);
if (res.code) throw new MongoServerError(res);

@@ -111,60 +102,3 @@ if (res.writeErrors) {

/** @internal */
export class InsertManyOperation extends AbstractOperation<InsertManyResult> {
override options: BulkWriteOptions;
collection: Collection;
docs: ReadonlyArray<Document>;
constructor(collection: Collection, docs: ReadonlyArray<Document>, options: BulkWriteOptions) {
super(options);
if (!Array.isArray(docs)) {
throw new MongoInvalidArgumentError('Argument "docs" must be an array of documents');
}
this.options = options;
this.collection = collection;
this.docs = docs;
}
override get commandName() {
return 'insert' as const;
}
override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<InsertManyResult> {
const coll = this.collection;
const options = { ...this.options, ...this.bsonOptions, readPreference: this.readPreference };
const writeConcern = WriteConcern.fromOptions(options);
const bulkWriteOperation = new BulkWriteOperation(
coll,
this.docs.map(document => ({
insertOne: { document }
})),
options
);
try {
const res = await bulkWriteOperation.execute(server, session, timeoutContext);
return {
acknowledged: writeConcern?.w !== 0,
insertedCount: res.insertedCount,
insertedIds: res.insertedIds
};
} catch (err) {
if (err && err.message === 'Operation must be an object with an operation key') {
throw new MongoInvalidArgumentError(
'Collection.insertMany() cannot be called with an array that has null/undefined values'
);
}
throw err;
}
}
}
defineAspects(InsertOperation, [Aspect.RETRYABLE, Aspect.WRITE_OPERATION]);
defineAspects(InsertOneOperation, [Aspect.RETRYABLE, Aspect.WRITE_OPERATION]);
defineAspects(InsertManyOperation, [Aspect.WRITE_OPERATION]);
import type { Long } from '../bson';
import { MongoRuntimeError } from '../error';
import type { Server } from '../sdam/server';
import { type Connection } from '../cmap/connection';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import { type MongoError, MongoRuntimeError } from '../error';
import type { Server, ServerCommandOptions } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { type MongoDBNamespace, squashError } from '../utils';
import { type MongoDBNamespace } from '../utils';
import { AbstractOperation, Aspect, defineAspects, type OperationOptions } from './operation';

@@ -19,3 +21,4 @@

export class KillCursorsOperation extends AbstractOperation {
export class KillCursorsOperation extends AbstractOperation<void> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
cursorId: Long;

@@ -34,11 +37,3 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<void> {
if (server !== this.server) {
throw new MongoRuntimeError('Killcursor must run on the same server operation began on');
}
override buildCommand(_connection: Connection, _session?: ClientSession): KillCursorsCommand {
const killCursors = this.ns.collection;

@@ -55,14 +50,18 @@ if (killCursors == null) {

};
try {
await server.command(this.ns, killCursorsCommand, {
session,
timeoutContext
});
} catch (error) {
// The driver should never emit errors from killCursors, this is spec-ed behavior
squashError(error);
}
return killCursorsCommand;
}
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
return {
session: this.session,
timeoutContext
};
}
override handleError(_error: MongoError): void {
// The driver should never emit errors from killCursors, this is spec-ed behavior
}
}
defineAspects(KillCursorsOperation, [Aspect.MUST_SELECT_SAME_SERVER]);

@@ -0,9 +1,7 @@

import { type Connection } from '..';
import type { Binary, Document } from '../bson';
import { CursorResponse } from '../cmap/wire_protocol/responses';
import { CursorResponse, ExplainedCursorResponse } from '../cmap/wire_protocol/responses';
import { type CursorTimeoutContext, type CursorTimeoutMode } from '../cursor/abstract_cursor';
import type { Db } from '../db';
import { type Abortable } from '../mongo_types';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { maxWireVersion } from '../utils';

@@ -32,2 +30,3 @@ import { CommandOperation, type CommandOperationOptions } from './command';

export class ListCollectionsOperation extends CommandOperation<CursorResponse> {
override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
/**

@@ -60,2 +59,4 @@ * @remarks WriteConcern can still be present on the options because

}
this.SERVER_COMMAND_RESPONSE_TYPE = this.explain ? ExplainedCursorResponse : CursorResponse;
}

@@ -67,18 +68,3 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<CursorResponse> {
return await super.executeCommand(
server,
session,
this.generateCommand(maxWireVersion(server)),
timeoutContext,
CursorResponse
);
}
/* This is here for the purpose of unit testing the final command that gets sent. */
generateCommand(wireVersion: number): Document {
override buildCommandDocument(connection: Connection): Document {
const command: Document = {

@@ -94,3 +80,3 @@ listCollections: 1,

// eslint-disable-next-line no-restricted-syntax
if (wireVersion >= 9 && this.options.comment !== undefined) {
if (maxWireVersion(connection) >= 9 && this.options.comment !== undefined) {
command.comment = this.options.comment;

@@ -101,2 +87,8 @@ }

}
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): CursorResponse {
return response;
}
}

@@ -103,0 +95,0 @@

@@ -0,7 +1,6 @@

import { type Connection } from '..';
import type { Document } from '../bson';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import type { Db } from '../db';
import { type TODO_NODE_3286 } from '../mongo_types';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { maxWireVersion, MongoDBNamespace } from '../utils';

@@ -31,2 +30,3 @@ import { CommandOperation, type CommandOperationOptions } from './command';

export class ListDatabasesOperation extends CommandOperation<ListDatabasesResult> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: ListDatabasesOptions;

@@ -44,7 +44,3 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<ListDatabasesResult> {
override buildCommandDocument(connection: Connection, _session?: ClientSession): Document {
const cmd: Document = { listDatabases: 1 };

@@ -66,12 +62,7 @@

// eslint-disable-next-line no-restricted-syntax
if (maxWireVersion(server) >= 9 && this.options.comment !== undefined) {
if (maxWireVersion(connection) >= 9 && this.options.comment !== undefined) {
cmd.comment = this.options.comment;
}
return await (super.executeCommand(
server,
session,
cmd,
timeoutContext
) as Promise<TODO_NODE_3286>);
return cmd;
}

@@ -78,0 +69,0 @@ }

@@ -0,5 +1,7 @@

import { type Connection, type MongoError } from '..';
import { type BSONSerializeOptions, type Document, resolveBSONOptions } from '../bson';
import { type MongoDBResponse } from '../cmap/wire_protocol/responses';
import { type Abortable } from '../mongo_types';
import { ReadPreference, type ReadPreferenceLike } from '../read_preference';
import type { Server } from '../sdam/server';
import type { Server, ServerCommandOptions } from '../sdam/server';
import type { ClientSession } from '../sessions';

@@ -34,3 +36,2 @@ import { type TimeoutContext } from '../timeout';

bypassPinningCheck?: boolean;
omitReadPreference?: boolean;

@@ -59,3 +60,2 @@ /** @internal Hint to `executeOperation` to omit maxTimeMS */

bypassPinningCheck: boolean;
trySecondaryWrite: boolean;

@@ -86,3 +86,2 @@ // BSON serialization options

this.bypassPinningCheck = !!options.bypassPinningCheck;
this.trySecondaryWrite = false;
}

@@ -94,8 +93,2 @@

abstract execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<TResult>;
hasAspect(aspect: symbol): boolean {

@@ -115,2 +108,6 @@ const ctor = this.constructor as { aspects?: Set<symbol> };

set session(session: ClientSession) {
this._session = session;
}
clearSession() {

@@ -131,2 +128,42 @@ this._session = undefined;

}
abstract SERVER_COMMAND_RESPONSE_TYPE: typeof MongoDBResponse;
/**
* Build a raw command document.
*/
abstract buildCommand(connection: Connection, session?: ClientSession): Document;
/**
* Builds an instance of `ServerCommandOptions` to be used for operation execution.
*/
abstract buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions;
/**
* Given an instance of a MongoDBResponse, map the response to the correct result type. For
* example, a `CountOperation` might map the response as follows:
*
* ```typescript
* override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): TResult {
* return response.toObject(this.bsonOptions).n ?? 0;
* }
*
* // or, with type safety:
* override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): TResult {
* return response.getNumber('n') ?? 0;
* }
* ```
*/
handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): TResult {
return response.toObject(this.bsonOptions) as TResult;
}
/**
* Optional.
*
* If the operation performs error handling, such as wrapping, renaming the error, or squashing errors
* this method can be overridden.
*/
handleError(error: MongoError): TResult | never {
throw error;
}
}

@@ -133,0 +170,0 @@

@@ -0,6 +1,6 @@

import { BSONType, type Document } from '../bson';
import { type Connection } from '../cmap/connection';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import type { Db } from '../db';
import { MongoUnexpectedServerResponseError } from '../error';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { CommandOperation, type CommandOperationOptions } from './command';

@@ -11,4 +11,11 @@

class ProfilingLevelResponse extends MongoDBResponse {
get was() {
return this.get('was', BSONType.int, true);
}
}
/** @internal */
export class ProfilingLevelOperation extends CommandOperation<string> {
override SERVER_COMMAND_RESPONSE_TYPE = ProfilingLevelResponse;
override options: ProfilingLevelOptions;

@@ -25,10 +32,9 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<string> {
const doc = await super.executeCommand(server, session, { profile: -1 }, timeoutContext);
if (doc.ok === 1) {
const was = doc.was;
override buildCommandDocument(_connection: Connection): Document {
return { profile: -1 };
}
override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): string {
if (response.ok === 1) {
const was = response.was;
if (was === 0) return 'off';

@@ -35,0 +41,0 @@ if (was === 1) return 'slow_only';

@@ -0,5 +1,5 @@

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 { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { CommandOperation, type CommandOperationOptions } from './command';

@@ -13,2 +13,3 @@ import { Aspect, defineAspects } from './operation';

export class RemoveUserOperation extends CommandOperation<boolean> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: RemoveUserOptions;

@@ -27,8 +28,7 @@ username: string;

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<boolean> {
await super.executeCommand(server, session, { dropUser: this.username }, timeoutContext);
override buildCommandDocument(_connection: Connection): Document {
return { dropUser: this.username };
}
override handleOk(_response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): boolean {
return true;

@@ -35,0 +35,0 @@ }

@@ -0,6 +1,6 @@

import { type Connection } from '..';
import type { Document } from '../bson';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import { Collection } from '../collection';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { MongoDBNamespace } from '../utils';

@@ -20,2 +20,3 @@ import { CommandOperation, type CommandOperationOptions } from './command';

export class RenameOperation extends CommandOperation<Document> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
collection: Collection;

@@ -37,20 +38,16 @@ newName: string;

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<Collection> {
// Build the command
override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
const renameCollection = this.collection.namespace;
const toCollection = this.collection.s.namespace.withCollection(this.newName).toString();
const to = this.collection.s.namespace.withCollection(this.newName).toString();
const dropTarget =
typeof this.options.dropTarget === 'boolean' ? this.options.dropTarget : false;
const command = {
renameCollection: renameCollection,
to: toCollection,
dropTarget: dropTarget
return {
renameCollection,
to,
dropTarget
};
}
await super.executeCommand(server, session, command, timeoutContext);
override handleOk(_response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): Document {
return new Collection(this.collection.s.db, this.newName, this.collection.s.options);

@@ -57,0 +54,0 @@ }

@@ -0,11 +1,11 @@

import { type Abortable } from '..';
import type { BSONSerializeOptions, Document } from '../bson';
import { type MongoDBResponseConstructor } from '../cmap/wire_protocol/responses';
import { type Db } from '../db';
import { type TODO_NODE_3286 } from '../mongo_types';
import { type Connection } from '../cmap/connection';
import { CursorResponse, MongoDBResponse } from '../cmap/wire_protocol/responses';
import { AbstractOperation } from '../operations/operation';
import type { ReadPreferenceLike } from '../read_preference';
import type { Server } from '../sdam/server';
import type { ServerCommandOptions } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { MongoDBNamespace } from '../utils';
import { AbstractOperation } from './operation';
import { type MongoDBNamespace } from '../utils';

@@ -25,18 +25,22 @@ /** @public */

omitMaxTimeMS?: boolean;
} & BSONSerializeOptions;
/**
* @internal Hints to `executeOperation` that this operation should not unpin on an ended transaction
* This is only used by the driver for transaction commands
*/
bypassPinningCheck?: boolean;
} & BSONSerializeOptions &
Abortable;
/** @internal */
export class RunCommandOperation<T = Document> extends AbstractOperation<T> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
command: Document;
override options: RunCommandOptions & { responseType?: MongoDBResponseConstructor };
override options: RunCommandOptions;
constructor(
parent: Db,
command: Document,
options: RunCommandOptions & { responseType?: MongoDBResponseConstructor }
) {
constructor(namespace: MongoDBNamespace, command: Document, options: RunCommandOptions) {
super(options);
this.command = command;
this.options = options;
this.ns = parent.s.namespace.withCollection('$cmd');
this.ns = namespace.withCollection('$cmd');
}

@@ -48,62 +52,30 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<T> {
this.server = server;
const res: TODO_NODE_3286 = await server.command(
this.ns,
this.command,
{
...this.options,
readPreference: this.readPreference,
session,
timeoutContext
},
this.options.responseType
);
override buildCommand(_connection: Connection, _session?: ClientSession): Document {
return this.command;
}
return res;
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
return {
...this.options,
session: this.session,
timeoutContext,
signal: this.options.signal,
readPreference: this.options.readPreference
};
}
}
export class RunAdminCommandOperation<T = Document> extends AbstractOperation<T> {
command: Document;
override options: RunCommandOptions & {
noResponse?: boolean;
bypassPinningCheck?: boolean;
};
/**
* @internal
*
* A specialized subclass of RunCommandOperation for cursor-creating commands.
*/
export class RunCursorCommandOperation extends RunCommandOperation {
override SERVER_COMMAND_RESPONSE_TYPE = CursorResponse;
constructor(
command: Document,
options: RunCommandOptions & {
noResponse?: boolean;
bypassPinningCheck?: boolean;
}
) {
super(options);
this.command = command;
this.options = options;
this.ns = new MongoDBNamespace('admin', '$cmd');
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): CursorResponse {
return response;
}
override get commandName() {
return 'runCommand' as const;
}
override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<T> {
this.server = server;
const res: TODO_NODE_3286 = await server.command(this.ns, this.command, {
...this.options,
readPreference: this.readPreference,
session,
timeoutContext
});
return res;
}
}

@@ -1,4 +0,6 @@

import type { Document } from '../../bson';
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 { Server } from '../../sdam/server';
import type { ServerCommandOptions } from '../../sdam/server';
import type { ClientSession } from '../../sessions';

@@ -23,3 +25,4 @@ import { type TimeoutContext } from '../../timeout';

/** @internal */
export class CreateSearchIndexesOperation extends AbstractOperation<string[]> {
export class CreateSearchIndexesOperation extends AbstractOperation<Document> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
private readonly collection: Collection;

@@ -32,2 +35,3 @@ private readonly descriptions: ReadonlyArray<SearchIndexDescription>;

this.descriptions = descriptions;
this.ns = collection.fullNamespace;
}

@@ -39,21 +43,17 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<string[]> {
override buildCommand(_connection: Connection, _session?: ClientSession): Document {
const namespace = this.collection.fullNamespace;
const command = {
return {
createSearchIndexes: namespace.collection,
indexes: this.descriptions
};
}
const res = await server.command(namespace, command, {
session,
timeoutContext
});
override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): string[] {
return super.handleOk(response).indexesCreated.map((val: { name: string }) => val.name);
}
const indexesCreated: Array<{ name: string }> = res?.indexesCreated ?? [];
return indexesCreated.map(({ name }) => name);
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
return { session: this.session, timeoutContext };
}
}

@@ -0,5 +1,7 @@

import { type Connection, type MongoError } from '../..';
import type { Document } from '../../bson';
import { MongoDBResponse } from '../../cmap/wire_protocol/responses';
import type { Collection } from '../../collection';
import { MONGODB_ERROR_CODES, MongoServerError } from '../../error';
import type { Server } from '../../sdam/server';
import type { ServerCommandOptions } from '../../sdam/server';
import type { ClientSession } from '../../sessions';

@@ -11,2 +13,4 @@ import { type TimeoutContext } from '../../timeout';

export class DropSearchIndexOperation extends AbstractOperation<void> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
private readonly collection: Collection;

@@ -19,2 +23,3 @@ private readonly name: string;

this.name = name;
this.ns = collection.fullNamespace;
}

@@ -26,7 +31,3 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<void> {
override buildCommand(_connection: Connection, _session?: ClientSession): Document {
const namespace = this.collection.fullNamespace;

@@ -42,12 +43,20 @@

try {
await server.command(namespace, command, { session, timeoutContext });
} catch (error) {
const isNamespaceNotFoundError =
error instanceof MongoServerError && error.code === MONGODB_ERROR_CODES.NamespaceNotFound;
if (!isNamespaceNotFoundError) {
throw error;
}
return command;
}
override handleOk(_response: MongoDBResponse): void {
// do nothing
}
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
return { session: this.session, timeoutContext };
}
override handleError(error: MongoError): void {
const isNamespaceNotFoundError =
error instanceof MongoServerError && error.code === MONGODB_ERROR_CODES.NamespaceNotFound;
if (!isNamespaceNotFoundError) {
throw error;
}
}
}
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 { Server } from '../../sdam/server';
import type { ServerCommandOptions } from '../../sdam/server';
import type { ClientSession } from '../../sessions';

@@ -10,2 +12,3 @@ import { type TimeoutContext } from '../../timeout';

export class UpdateSearchIndexOperation extends AbstractOperation<void> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
private readonly collection: Collection;

@@ -20,2 +23,3 @@ private readonly name: string;

this.definition = definition;
this.ns = collection.fullNamespace;
}

@@ -27,9 +31,5 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<void> {
override buildCommand(_connection: Connection, _session?: ClientSession): Document {
const namespace = this.collection.fullNamespace;
const command = {
return {
updateSearchIndex: namespace.collection,

@@ -39,6 +39,11 @@ name: this.name,

};
}
await server.command(namespace, command, { session, timeoutContext });
return;
override handleOk(_response: MongoDBResponse): void {
// no response.
}
override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions {
return { session: this.session, timeoutContext };
}
}

@@ -0,6 +1,6 @@

import { type Document } from '../bson';
import { type Connection } from '../cmap/connection';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import type { Db } from '../db';
import { MongoInvalidArgumentError } from '../error';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { enumToString } from '../utils';

@@ -26,2 +26,3 @@ import { CommandOperation, type CommandOperationOptions } from './command';

export class SetProfilingLevelOperation extends CommandOperation<ProfilingLevel> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: SetProfilingLevelOptions;

@@ -56,10 +57,7 @@ level: ProfilingLevel;

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<ProfilingLevel> {
override buildCommandDocument(_connection: Connection): Document {
const level = this.level;
if (!levelValues.has(level)) {
// TODO(NODE-3483): Determine error to put here
throw new MongoInvalidArgumentError(

@@ -70,6 +68,10 @@ `Profiling level must be one of "${enumToString(ProfilingLevel)}"`

// TODO(NODE-3483): Determine error to put here
await super.executeCommand(server, session, { profile: this.profile }, timeoutContext);
return level;
return { profile: this.profile };
}
override handleOk(
_response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): ProfilingLevel {
return this.level;
}
}
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 { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { CommandOperation, type CommandOperationOptions } from './command';

@@ -17,2 +16,3 @@ import { Aspect, defineAspects } from './operation';

export class DbStatsOperation extends CommandOperation<Document> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: DbStatsOptions;

@@ -29,7 +29,3 @@

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<Document> {
override buildCommandDocument(_connection: Connection): Document {
const command: Document = { dbStats: true };

@@ -39,4 +35,3 @@ if (this.options.scale != null) {

}
return await super.executeCommand(server, session, command, timeoutContext);
return command;
}

@@ -43,0 +38,0 @@ }

import type { Document } from '../bson';
import type { Collection } from '../collection';
import { type Connection } from '../cmap/connection';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import { MongoCompatibilityError, MongoInvalidArgumentError, MongoServerError } from '../error';
import type { InferIdType, TODO_NODE_3286 } from '../mongo_types';
import type { Server } from '../sdam/server';
import type { InferIdType } from '../mongo_types';
import type { ClientSession } from '../sessions';
import { formatSort, type Sort, type SortForCmd } from '../sort';
import { type TimeoutContext } from '../timeout';
import { hasAtomicOperators, type MongoDBNamespace } from '../utils';
import {
hasAtomicOperators,
type MongoDBCollectionNamespace,
type MongoDBNamespace
} from '../utils';
import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command';

@@ -71,2 +74,3 @@ import { Aspect, defineAspects, type Hint } from './operation';

export class UpdateOperation extends CommandOperation<Document> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: UpdateOptions & { ordered?: boolean };

@@ -99,13 +103,8 @@ statements: UpdateStatement[];

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<Document> {
const options = this.options ?? {};
const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
const options = this.options;
const command: Document = {
update: this.ns.collection,
updates: this.statements,
ordered
ordered: options.ordered ?? true
};

@@ -127,3 +126,3 @@

const unacknowledgedWrite = this.writeConcern && this.writeConcern.w === 0;
const unacknowledgedWrite = this.writeConcern?.w === 0;
if (unacknowledgedWrite) {

@@ -136,4 +135,3 @@ if (this.statements.find((o: Document) => o.hint)) {

const res = await super.executeCommand(server, session, command, timeoutContext);
return res;
return command;
}

@@ -144,8 +142,9 @@ }

export class UpdateOneOperation extends UpdateOperation {
constructor(collection: Collection, filter: Document, update: Document, options: UpdateOptions) {
super(
collection.s.namespace,
[makeUpdateStatement(filter, update, { ...options, multi: false })],
options
);
constructor(
ns: MongoDBCollectionNamespace,
filter: Document,
update: Document,
options: UpdateOptions
) {
super(ns, [makeUpdateStatement(filter, update, { ...options, multi: false })], options);

@@ -157,9 +156,10 @@ if (!hasAtomicOperators(update, options)) {

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<UpdateResult> {
const res: TODO_NODE_3286 = await super.execute(server, session, timeoutContext);
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): UpdateResult {
const res = super.handleOk(response);
// @ts-expect-error Explain typing is broken
if (this.explain != null) return res;
if (res.code) throw new MongoServerError(res);

@@ -181,8 +181,9 @@ if (res.writeErrors) throw new MongoServerError(res.writeErrors[0]);

export class UpdateManyOperation extends UpdateOperation {
constructor(collection: Collection, filter: Document, update: Document, options: UpdateOptions) {
super(
collection.s.namespace,
[makeUpdateStatement(filter, update, { ...options, multi: true })],
options
);
constructor(
ns: MongoDBCollectionNamespace,
filter: Document,
update: Document,
options: UpdateOptions
) {
super(ns, [makeUpdateStatement(filter, update, { ...options, multi: true })], options);

@@ -194,8 +195,8 @@ if (!hasAtomicOperators(update, options)) {

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<UpdateResult> {
const res: TODO_NODE_3286 = await super.execute(server, session, timeoutContext);
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): UpdateResult {
const res = super.handleOk(response);
// @ts-expect-error Explain typing is broken
if (this.explain != null) return res;

@@ -235,3 +236,3 @@ if (res.code) throw new MongoServerError(res);

constructor(
collection: Collection,
ns: MongoDBCollectionNamespace,
filter: Document,

@@ -241,7 +242,3 @@ replacement: Document,

) {
super(
collection.s.namespace,
[makeUpdateStatement(filter, replacement, { ...options, multi: false })],
options
);
super(ns, [makeUpdateStatement(filter, replacement, { ...options, multi: false })], options);

@@ -253,8 +250,8 @@ if (hasAtomicOperators(replacement)) {

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<UpdateResult> {
const res: TODO_NODE_3286 = await super.execute(server, session, timeoutContext);
override handleOk(
response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>
): UpdateResult {
const res = super.handleOk(response);
// @ts-expect-error Explain typing is broken
if (this.explain != null) return res;

@@ -261,0 +258,0 @@ if (res.code) throw new MongoServerError(res);

@@ -0,7 +1,7 @@

import { type Connection } from '..';
import type { Admin } from '../admin';
import type { Document } from '../bson';
import { type Document } from '../bson';
import { MongoDBResponse } from '../cmap/wire_protocol/responses';
import { MongoUnexpectedServerResponseError } from '../error';
import type { Server } from '../sdam/server';
import type { ClientSession } from '../sessions';
import { type TimeoutContext } from '../timeout';
import { CommandOperation, type CommandOperationOptions } from './command';

@@ -17,19 +17,9 @@

export class ValidateCollectionOperation extends CommandOperation<Document> {
override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse;
override options: ValidateCollectionOptions;
collectionName: string;
command: Document;
constructor(admin: Admin, collectionName: string, options: ValidateCollectionOptions) {
// Decorate command with extra options
const command: Document = { validate: collectionName };
const keys = Object.keys(options);
for (let i = 0; i < keys.length; i++) {
if (Object.prototype.hasOwnProperty.call(options, keys[i]) && keys[i] !== 'session') {
command[keys[i]] = (options as Document)[keys[i]];
}
}
super(admin.s.db, options);
this.options = options;
this.command = command;
this.collectionName = collectionName;

@@ -42,19 +32,21 @@ }

override async execute(
server: Server,
session: ClientSession | undefined,
timeoutContext: TimeoutContext
): Promise<Document> {
const collectionName = this.collectionName;
override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document {
// Decorate command with extra options
return {
validate: this.collectionName,
...Object.fromEntries(Object.entries(this.options).filter(entry => entry[0] !== 'session'))
};
}
const doc = await super.executeCommand(server, session, this.command, timeoutContext);
if (doc.result != null && typeof doc.result !== 'string')
override handleOk(response: InstanceType<typeof this.SERVER_COMMAND_RESPONSE_TYPE>): Document {
const result = super.handleOk(response);
if (result.result != null && typeof result.result !== 'string')
throw new MongoUnexpectedServerResponseError('Error with validation data');
if (doc.result != null && doc.result.match(/exception|corrupt/) != null)
throw new MongoUnexpectedServerResponseError(`Invalid collection ${collectionName}`);
if (doc.valid != null && !doc.valid)
throw new MongoUnexpectedServerResponseError(`Invalid collection ${collectionName}`);
if (result.result != null && result.result.match(/exception|corrupt/) != null)
throw new MongoUnexpectedServerResponseError(`Invalid collection ${this.collectionName}`);
if (result.valid != null && !result.valid)
throw new MongoUnexpectedServerResponseError(`Invalid collection ${this.collectionName}`);
return doc;
return response;
}
}

@@ -10,3 +10,2 @@ import type { Document } from '../bson';

import { PoolClearedError } from '../cmap/errors';
import { type MongoDBResponseConstructor } from '../cmap/wire_protocol/responses';
import {

@@ -31,3 +30,2 @@ APM_EVENTS,

MongoErrorLabel,
MongoInvalidArgumentError,
MongoNetworkError,

@@ -42,3 +40,5 @@ MongoNetworkTimeoutError,

import { type Abortable, TypedEventEmitter } from '../mongo_types';
import { AggregateOperation } from '../operations/aggregate';
import type { GetMoreOptions } from '../operations/get_more';
import { type AbstractOperation } from '../operations/operation';
import type { ClientSession } from '../sessions';

@@ -52,3 +52,2 @@ import { type TimeoutContext } from '../timeout';

maxWireVersion,
type MongoDBNamespace,
noop,

@@ -74,2 +73,3 @@ squashError,

import { compareTopologyVersion, ServerDescription } from './server_description';
import { MIN_SECONDARY_WRITE_WIRE_VERSION } from './server_selection';
import type { Topology } from './topology';

@@ -118,2 +118,3 @@

timeoutContext: TimeoutContext;
returnFieldSelector?: Document | null;
} & Abortable;

@@ -286,44 +287,11 @@

public async command<T extends MongoDBResponseConstructor>(
ns: MongoDBNamespace,
command: Document,
options: ServerCommandOptions,
responseType: T | undefined
): Promise<typeof responseType extends undefined ? Document : InstanceType<T>>;
public async command(
ns: MongoDBNamespace,
command: Document,
options: ServerCommandOptions
): Promise<Document>;
public async command(
ns: MongoDBNamespace,
cmd: Document,
{ ...options }: ServerCommandOptions,
responseType?: MongoDBResponseConstructor
): Promise<Document> {
if (ns.db == null || typeof ns === 'string') {
throw new MongoInvalidArgumentError('Namespace must not be a string');
}
public async command<TResult>(
operation: AbstractOperation<TResult>,
timeoutContext: TimeoutContext
): Promise<InstanceType<typeof operation.SERVER_COMMAND_RESPONSE_TYPE>> {
if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
throw new MongoServerClosedError();
}
const session = operation.session;
options.directConnection = this.topology.s.options.directConnection;
// There are cases where we need to flag the read preference not to get sent in
// the command, such as pre-5.0 servers attempting to perform an aggregate write
// with a non-primary read preference. In this case the effective read preference
// (primary) is not the same as the provided and must be removed completely.
if (options.omitReadPreference) {
delete options.readPreference;
}
if (this.description.iscryptd) {
options.omitMaxTimeMS = true;
}
const session = options.session;
let conn = session?.pinnedConnection;

@@ -334,6 +302,3 @@

try {
conn = await this.pool.checkOut(options);
if (this.loadBalanced && isPinnableCommand(cmd, session)) {
session?.pin(conn);
}
conn = await this.pool.checkOut({ timeoutContext, signal: operation.options.signal });
} catch (checkoutError) {

@@ -347,6 +312,49 @@ this.decrementOperationCount();

let reauthPromise: Promise<void> | null = null;
const cleanup = () => {
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);
}
}
};
let cmd;
try {
cmd = operation.buildCommand(conn, session);
} catch (e) {
cleanup();
throw e;
}
const options = operation.buildOptions(timeoutContext);
const ns = operation.ns;
if (this.loadBalanced && isPinnableCommand(cmd, session) && !session?.pinnedConnection) {
session?.pin(conn);
}
options.directConnection = this.topology.s.options.directConnection;
const omitReadPreference =
operation instanceof AggregateOperation &&
operation.hasWriteStage &&
maxWireVersion(conn) < MIN_SECONDARY_WRITE_WIRE_VERSION;
if (omitReadPreference) {
delete options.readPreference;
}
if (this.description.iscryptd) {
options.omitMaxTimeMS = true;
}
try {
try {
const res = await conn.command(ns, cmd, options, responseType);
const res = await conn.command(ns, cmd, options, operation.SERVER_COMMAND_RESPONSE_TYPE);
throwIfWriteConcernError(res);

@@ -372,3 +380,3 @@ return res;

try {
const res = await conn.command(ns, cmd, options, responseType);
const res = await conn.command(ns, cmd, options, operation.SERVER_COMMAND_RESPONSE_TYPE);
throwIfWriteConcernError(res);

@@ -383,14 +391,3 @@ return res;

} 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);
}
}
cleanup();
}

@@ -397,0 +394,0 @@ }

@@ -49,3 +49,2 @@ import type { BSONSerializeOptions, Document } from '../bson';

now,
ns,
promiseWithResolvers,

@@ -463,3 +462,3 @@ shuffle

const selectServerOptions = {
operationName: 'ping',
operationName: 'handshake',
...options,

@@ -474,5 +473,7 @@ timeoutContext

);
const skipPingOnConnect = this.s.options.__skipPingOnConnect === true;
if (!skipPingOnConnect && this.s.credentials) {
await server.command(ns('admin.$cmd'), { ping: 1 }, { timeoutContext });
const connection = await server.pool.checkOut({ timeoutContext: timeoutContext });
server.pool.checkIn(connection);
stateTransition(this, STATE_CONNECTED);

@@ -755,3 +756,3 @@ this.emit(Topology.OPEN, this);

auth(credentials?: MongoCredentials, callback?: Callback): void {
if (typeof credentials === 'function') (callback = credentials), (credentials = undefined);
if (typeof credentials === 'function') ((callback = credentials), (credentials = undefined));
if (typeof callback === 'function') callback(undefined, true);

@@ -758,0 +759,0 @@ }

@@ -27,3 +27,3 @@ import { Binary, type Document, Long, type Timestamp } from './bson';

import { executeOperation } from './operations/execute_operation';
import { RunAdminCommandOperation } from './operations/run_command';
import { RunCommandOperation } from './operations/run_command';
import { ReadConcernLevel } from './read_concern';

@@ -47,2 +47,3 @@ import { ReadPreference } from './read_preference';

maxWireVersion,
MongoDBNamespace,
noop,

@@ -510,3 +511,3 @@ now,

const operation = new RunAdminCommandOperation(command, {
const operation = new RunCommandOperation(new MongoDBNamespace('admin'), command, {
session: this,

@@ -542,3 +543,3 @@ readPreference: ReadPreference.primary,

this.client,
new RunAdminCommandOperation(command, {
new RunCommandOperation(new MongoDBNamespace('admin'), command, {
session: this,

@@ -644,3 +645,3 @@ readPreference: ReadPreference.primary,

const operation = new RunAdminCommandOperation(command, {
const operation = new RunCommandOperation(new MongoDBNamespace('admin'), command, {
session: this,

@@ -647,0 +648,0 @@ readPreference: ReadPreference.primary,

@@ -1360,34 +1360,19 @@ import * as crypto from 'crypto';

export function maybeAddIdToDocuments(
coll: Collection,
docs: Document[],
collection: Collection,
document: Document,
options: { forceServerObjectId?: boolean }
): Document[];
export function maybeAddIdToDocuments(
coll: Collection,
docs: Document,
options: { forceServerObjectId?: boolean }
): Document;
export function maybeAddIdToDocuments(
coll: Collection,
docOrDocs: Document[] | Document,
options: { forceServerObjectId?: boolean }
): Document[] | Document {
): Document {
const forceServerObjectId =
typeof options.forceServerObjectId === 'boolean'
? options.forceServerObjectId
: coll.s.db.options?.forceServerObjectId;
options.forceServerObjectId ?? collection.s.db.options?.forceServerObjectId ?? false;
// no need to modify the docs if server sets the ObjectId
if (forceServerObjectId === true) {
return docOrDocs;
if (forceServerObjectId) {
return document;
}
const transform = (doc: Document): Document => {
if (doc._id == null) {
doc._id = coll.s.pkFactory.createPk();
}
if (document._id == null) {
document._id = collection.s.pkFactory.createPk();
}
return doc;
};
return Array.isArray(docOrDocs) ? docOrDocs.map(transform) : transform(docOrDocs);
return document;
}

@@ -1394,0 +1379,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.