You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							874 lines
						
					
					
						
							32 KiB
						
					
					
				
			
		
		
	
	
							874 lines
						
					
					
						
							32 KiB
						
					
					
				| "use strict";
 | |
| Object.defineProperty(exports, "__esModule", { value: true });
 | |
| exports.BulkOperationBase = exports.FindOperators = exports.MongoBulkWriteError = exports.mergeBatchResults = exports.WriteError = exports.WriteConcernError = exports.BulkWriteResult = exports.Batch = exports.BatchType = void 0;
 | |
| const bson_1 = require("../bson");
 | |
| const error_1 = require("../error");
 | |
| const delete_1 = require("../operations/delete");
 | |
| const execute_operation_1 = require("../operations/execute_operation");
 | |
| const insert_1 = require("../operations/insert");
 | |
| const operation_1 = require("../operations/operation");
 | |
| const update_1 = require("../operations/update");
 | |
| const utils_1 = require("../utils");
 | |
| const write_concern_1 = require("../write_concern");
 | |
| /** @internal */
 | |
| const kServerError = Symbol('serverError');
 | |
| /** @public */
 | |
| exports.BatchType = Object.freeze({
 | |
|     INSERT: 1,
 | |
|     UPDATE: 2,
 | |
|     DELETE: 3
 | |
| });
 | |
| /**
 | |
|  * Keeps the state of a unordered batch so we can rewrite the results
 | |
|  * correctly after command execution
 | |
|  *
 | |
|  * @public
 | |
|  */
 | |
| class Batch {
 | |
|     constructor(batchType, originalZeroIndex) {
 | |
|         this.originalZeroIndex = originalZeroIndex;
 | |
|         this.currentIndex = 0;
 | |
|         this.originalIndexes = [];
 | |
|         this.batchType = batchType;
 | |
|         this.operations = [];
 | |
|         this.size = 0;
 | |
|         this.sizeBytes = 0;
 | |
|     }
 | |
| }
 | |
| exports.Batch = Batch;
 | |
| /**
 | |
|  * @public
 | |
|  * The result of a bulk write.
 | |
|  */
 | |
| class BulkWriteResult {
 | |
|     static generateIdMap(ids) {
 | |
|         const idMap = {};
 | |
|         for (const doc of ids) {
 | |
|             idMap[doc.index] = doc._id;
 | |
|         }
 | |
|         return idMap;
 | |
|     }
 | |
|     /**
 | |
|      * Create a new BulkWriteResult instance
 | |
|      * @internal
 | |
|      */
 | |
|     constructor(bulkResult) {
 | |
|         this.result = bulkResult;
 | |
|         this.insertedCount = this.result.nInserted ?? 0;
 | |
|         this.matchedCount = this.result.nMatched ?? 0;
 | |
|         this.modifiedCount = this.result.nModified ?? 0;
 | |
|         this.deletedCount = this.result.nRemoved ?? 0;
 | |
|         this.upsertedCount = this.result.upserted.length ?? 0;
 | |
|         this.upsertedIds = BulkWriteResult.generateIdMap(this.result.upserted);
 | |
|         this.insertedIds = BulkWriteResult.generateIdMap(this.result.insertedIds);
 | |
|         Object.defineProperty(this, 'result', { value: this.result, enumerable: false });
 | |
|     }
 | |
|     /** Evaluates to true if the bulk operation correctly executes */
 | |
|     get ok() {
 | |
|         return this.result.ok;
 | |
|     }
 | |
|     /** The number of inserted documents */
 | |
|     get nInserted() {
 | |
|         return this.result.nInserted;
 | |
|     }
 | |
|     /** Number of upserted documents */
 | |
|     get nUpserted() {
 | |
|         return this.result.nUpserted;
 | |
|     }
 | |
|     /** Number of matched documents */
 | |
|     get nMatched() {
 | |
|         return this.result.nMatched;
 | |
|     }
 | |
|     /** Number of documents updated physically on disk */
 | |
|     get nModified() {
 | |
|         return this.result.nModified;
 | |
|     }
 | |
|     /** Number of removed documents */
 | |
|     get nRemoved() {
 | |
|         return this.result.nRemoved;
 | |
|     }
 | |
|     /** Returns an array of all inserted ids */
 | |
|     getInsertedIds() {
 | |
|         return this.result.insertedIds;
 | |
|     }
 | |
|     /** Returns an array of all upserted ids */
 | |
|     getUpsertedIds() {
 | |
|         return this.result.upserted;
 | |
|     }
 | |
|     /** Returns the upserted id at the given index */
 | |
|     getUpsertedIdAt(index) {
 | |
|         return this.result.upserted[index];
 | |
|     }
 | |
|     /** Returns raw internal result */
 | |
|     getRawResponse() {
 | |
|         return this.result;
 | |
|     }
 | |
|     /** Returns true if the bulk operation contains a write error */
 | |
|     hasWriteErrors() {
 | |
|         return this.result.writeErrors.length > 0;
 | |
|     }
 | |
|     /** Returns the number of write errors off the bulk operation */
 | |
|     getWriteErrorCount() {
 | |
|         return this.result.writeErrors.length;
 | |
|     }
 | |
|     /** Returns a specific write error object */
 | |
|     getWriteErrorAt(index) {
 | |
|         return index < this.result.writeErrors.length ? this.result.writeErrors[index] : undefined;
 | |
|     }
 | |
|     /** Retrieve all write errors */
 | |
|     getWriteErrors() {
 | |
|         return this.result.writeErrors;
 | |
|     }
 | |
|     /** Retrieve the write concern error if one exists */
 | |
|     getWriteConcernError() {
 | |
|         if (this.result.writeConcernErrors.length === 0) {
 | |
|             return;
 | |
|         }
 | |
|         else if (this.result.writeConcernErrors.length === 1) {
 | |
|             // Return the error
 | |
|             return this.result.writeConcernErrors[0];
 | |
|         }
 | |
|         else {
 | |
|             // Combine the errors
 | |
|             let errmsg = '';
 | |
|             for (let i = 0; i < this.result.writeConcernErrors.length; i++) {
 | |
|                 const err = this.result.writeConcernErrors[i];
 | |
|                 errmsg = errmsg + err.errmsg;
 | |
|                 // TODO: Something better
 | |
|                 if (i === 0)
 | |
|                     errmsg = errmsg + ' and ';
 | |
|             }
 | |
|             return new WriteConcernError({ errmsg, code: error_1.MONGODB_ERROR_CODES.WriteConcernFailed });
 | |
|         }
 | |
|     }
 | |
|     toString() {
 | |
|         return `BulkWriteResult(${this.result})`;
 | |
|     }
 | |
|     isOk() {
 | |
|         return this.result.ok === 1;
 | |
|     }
 | |
| }
 | |
| exports.BulkWriteResult = BulkWriteResult;
 | |
| /**
 | |
|  * An error representing a failure by the server to apply the requested write concern to the bulk operation.
 | |
|  * @public
 | |
|  * @category Error
 | |
|  */
 | |
| class WriteConcernError {
 | |
|     constructor(error) {
 | |
|         this[kServerError] = error;
 | |
|     }
 | |
|     /** Write concern error code. */
 | |
|     get code() {
 | |
|         return this[kServerError].code;
 | |
|     }
 | |
|     /** Write concern error message. */
 | |
|     get errmsg() {
 | |
|         return this[kServerError].errmsg;
 | |
|     }
 | |
|     /** Write concern error info. */
 | |
|     get errInfo() {
 | |
|         return this[kServerError].errInfo;
 | |
|     }
 | |
|     toJSON() {
 | |
|         return this[kServerError];
 | |
|     }
 | |
|     toString() {
 | |
|         return `WriteConcernError(${this.errmsg})`;
 | |
|     }
 | |
| }
 | |
| exports.WriteConcernError = WriteConcernError;
 | |
| /**
 | |
|  * An error that occurred during a BulkWrite on the server.
 | |
|  * @public
 | |
|  * @category Error
 | |
|  */
 | |
| class WriteError {
 | |
|     constructor(err) {
 | |
|         this.err = err;
 | |
|     }
 | |
|     /** WriteError code. */
 | |
|     get code() {
 | |
|         return this.err.code;
 | |
|     }
 | |
|     /** WriteError original bulk operation index. */
 | |
|     get index() {
 | |
|         return this.err.index;
 | |
|     }
 | |
|     /** WriteError message. */
 | |
|     get errmsg() {
 | |
|         return this.err.errmsg;
 | |
|     }
 | |
|     /** WriteError details. */
 | |
|     get errInfo() {
 | |
|         return this.err.errInfo;
 | |
|     }
 | |
|     /** Returns the underlying operation that caused the error */
 | |
|     getOperation() {
 | |
|         return this.err.op;
 | |
|     }
 | |
|     toJSON() {
 | |
|         return { code: this.err.code, index: this.err.index, errmsg: this.err.errmsg, op: this.err.op };
 | |
|     }
 | |
|     toString() {
 | |
|         return `WriteError(${JSON.stringify(this.toJSON())})`;
 | |
|     }
 | |
| }
 | |
| exports.WriteError = WriteError;
 | |
| /** Merges results into shared data structure */
 | |
| function mergeBatchResults(batch, bulkResult, err, result) {
 | |
|     // If we have an error set the result to be the err object
 | |
|     if (err) {
 | |
|         result = err;
 | |
|     }
 | |
|     else if (result && result.result) {
 | |
|         result = result.result;
 | |
|     }
 | |
|     if (result == null) {
 | |
|         return;
 | |
|     }
 | |
|     // Do we have a top level error stop processing and return
 | |
|     if (result.ok === 0 && bulkResult.ok === 1) {
 | |
|         bulkResult.ok = 0;
 | |
|         const writeError = {
 | |
|             index: 0,
 | |
|             code: result.code || 0,
 | |
|             errmsg: result.message,
 | |
|             errInfo: result.errInfo,
 | |
|             op: batch.operations[0]
 | |
|         };
 | |
|         bulkResult.writeErrors.push(new WriteError(writeError));
 | |
|         return;
 | |
|     }
 | |
|     else if (result.ok === 0 && bulkResult.ok === 0) {
 | |
|         return;
 | |
|     }
 | |
|     // If we have an insert Batch type
 | |
|     if (isInsertBatch(batch) && result.n) {
 | |
|         bulkResult.nInserted = bulkResult.nInserted + result.n;
 | |
|     }
 | |
|     // If we have an insert Batch type
 | |
|     if (isDeleteBatch(batch) && result.n) {
 | |
|         bulkResult.nRemoved = bulkResult.nRemoved + result.n;
 | |
|     }
 | |
|     let nUpserted = 0;
 | |
|     // We have an array of upserted values, we need to rewrite the indexes
 | |
|     if (Array.isArray(result.upserted)) {
 | |
|         nUpserted = result.upserted.length;
 | |
|         for (let i = 0; i < result.upserted.length; i++) {
 | |
|             bulkResult.upserted.push({
 | |
|                 index: result.upserted[i].index + batch.originalZeroIndex,
 | |
|                 _id: result.upserted[i]._id
 | |
|             });
 | |
|         }
 | |
|     }
 | |
|     else if (result.upserted) {
 | |
|         nUpserted = 1;
 | |
|         bulkResult.upserted.push({
 | |
|             index: batch.originalZeroIndex,
 | |
|             _id: result.upserted
 | |
|         });
 | |
|     }
 | |
|     // If we have an update Batch type
 | |
|     if (isUpdateBatch(batch) && result.n) {
 | |
|         const nModified = result.nModified;
 | |
|         bulkResult.nUpserted = bulkResult.nUpserted + nUpserted;
 | |
|         bulkResult.nMatched = bulkResult.nMatched + (result.n - nUpserted);
 | |
|         if (typeof nModified === 'number') {
 | |
|             bulkResult.nModified = bulkResult.nModified + nModified;
 | |
|         }
 | |
|         else {
 | |
|             bulkResult.nModified = 0;
 | |
|         }
 | |
|     }
 | |
|     if (Array.isArray(result.writeErrors)) {
 | |
|         for (let i = 0; i < result.writeErrors.length; i++) {
 | |
|             const writeError = {
 | |
|                 index: batch.originalIndexes[result.writeErrors[i].index],
 | |
|                 code: result.writeErrors[i].code,
 | |
|                 errmsg: result.writeErrors[i].errmsg,
 | |
|                 errInfo: result.writeErrors[i].errInfo,
 | |
|                 op: batch.operations[result.writeErrors[i].index]
 | |
|             };
 | |
|             bulkResult.writeErrors.push(new WriteError(writeError));
 | |
|         }
 | |
|     }
 | |
|     if (result.writeConcernError) {
 | |
|         bulkResult.writeConcernErrors.push(new WriteConcernError(result.writeConcernError));
 | |
|     }
 | |
| }
 | |
| exports.mergeBatchResults = mergeBatchResults;
 | |
| function executeCommands(bulkOperation, options, callback) {
 | |
|     if (bulkOperation.s.batches.length === 0) {
 | |
|         return callback(undefined, new BulkWriteResult(bulkOperation.s.bulkResult));
 | |
|     }
 | |
|     const batch = bulkOperation.s.batches.shift();
 | |
|     function resultHandler(err, result) {
 | |
|         // Error is a driver related error not a bulk op error, return early
 | |
|         if (err && 'message' in err && !(err instanceof error_1.MongoWriteConcernError)) {
 | |
|             return callback(new MongoBulkWriteError(err, new BulkWriteResult(bulkOperation.s.bulkResult)));
 | |
|         }
 | |
|         if (err instanceof error_1.MongoWriteConcernError) {
 | |
|             return handleMongoWriteConcernError(batch, bulkOperation.s.bulkResult, err, callback);
 | |
|         }
 | |
|         // Merge the results together
 | |
|         mergeBatchResults(batch, bulkOperation.s.bulkResult, err, result);
 | |
|         const writeResult = new BulkWriteResult(bulkOperation.s.bulkResult);
 | |
|         if (bulkOperation.handleWriteError(callback, writeResult))
 | |
|             return;
 | |
|         // Execute the next command in line
 | |
|         executeCommands(bulkOperation, options, callback);
 | |
|     }
 | |
|     const finalOptions = (0, utils_1.resolveOptions)(bulkOperation, {
 | |
|         ...options,
 | |
|         ordered: bulkOperation.isOrdered
 | |
|     });
 | |
|     if (finalOptions.bypassDocumentValidation !== true) {
 | |
|         delete finalOptions.bypassDocumentValidation;
 | |
|     }
 | |
|     // Set an operationIf if provided
 | |
|     if (bulkOperation.operationId) {
 | |
|         resultHandler.operationId = bulkOperation.operationId;
 | |
|     }
 | |
|     // Is the bypassDocumentValidation options specific
 | |
|     if (bulkOperation.s.bypassDocumentValidation === true) {
 | |
|         finalOptions.bypassDocumentValidation = true;
 | |
|     }
 | |
|     // Is the checkKeys option disabled
 | |
|     if (bulkOperation.s.checkKeys === false) {
 | |
|         finalOptions.checkKeys = false;
 | |
|     }
 | |
|     if (finalOptions.retryWrites) {
 | |
|         if (isUpdateBatch(batch)) {
 | |
|             finalOptions.retryWrites = finalOptions.retryWrites && !batch.operations.some(op => op.multi);
 | |
|         }
 | |
|         if (isDeleteBatch(batch)) {
 | |
|             finalOptions.retryWrites =
 | |
|                 finalOptions.retryWrites && !batch.operations.some(op => op.limit === 0);
 | |
|         }
 | |
|     }
 | |
|     try {
 | |
|         if (isInsertBatch(batch)) {
 | |
|             (0, execute_operation_1.executeOperation)(bulkOperation.s.collection.s.db.s.client, new insert_1.InsertOperation(bulkOperation.s.namespace, batch.operations, finalOptions), resultHandler);
 | |
|         }
 | |
|         else if (isUpdateBatch(batch)) {
 | |
|             (0, execute_operation_1.executeOperation)(bulkOperation.s.collection.s.db.s.client, new update_1.UpdateOperation(bulkOperation.s.namespace, batch.operations, finalOptions), resultHandler);
 | |
|         }
 | |
|         else if (isDeleteBatch(batch)) {
 | |
|             (0, execute_operation_1.executeOperation)(bulkOperation.s.collection.s.db.s.client, new delete_1.DeleteOperation(bulkOperation.s.namespace, batch.operations, finalOptions), resultHandler);
 | |
|         }
 | |
|     }
 | |
|     catch (err) {
 | |
|         // Force top level error
 | |
|         err.ok = 0;
 | |
|         // Merge top level error and return
 | |
|         mergeBatchResults(batch, bulkOperation.s.bulkResult, err, undefined);
 | |
|         callback();
 | |
|     }
 | |
| }
 | |
| function handleMongoWriteConcernError(batch, bulkResult, err, callback) {
 | |
|     mergeBatchResults(batch, bulkResult, undefined, err.result);
 | |
|     callback(new MongoBulkWriteError({
 | |
|         message: err.result?.writeConcernError.errmsg,
 | |
|         code: err.result?.writeConcernError.result
 | |
|     }, new BulkWriteResult(bulkResult)));
 | |
| }
 | |
| /**
 | |
|  * An error indicating an unsuccessful Bulk Write
 | |
|  * @public
 | |
|  * @category Error
 | |
|  */
 | |
| class MongoBulkWriteError extends error_1.MongoServerError {
 | |
|     /** Creates a new MongoBulkWriteError */
 | |
|     constructor(error, result) {
 | |
|         super(error);
 | |
|         this.writeErrors = [];
 | |
|         if (error instanceof WriteConcernError)
 | |
|             this.err = error;
 | |
|         else if (!(error instanceof Error)) {
 | |
|             this.message = error.message;
 | |
|             this.code = error.code;
 | |
|             this.writeErrors = error.writeErrors ?? [];
 | |
|         }
 | |
|         this.result = result;
 | |
|         Object.assign(this, error);
 | |
|     }
 | |
|     get name() {
 | |
|         return 'MongoBulkWriteError';
 | |
|     }
 | |
|     /** Number of documents inserted. */
 | |
|     get insertedCount() {
 | |
|         return this.result.insertedCount;
 | |
|     }
 | |
|     /** Number of documents matched for update. */
 | |
|     get matchedCount() {
 | |
|         return this.result.matchedCount;
 | |
|     }
 | |
|     /** Number of documents modified. */
 | |
|     get modifiedCount() {
 | |
|         return this.result.modifiedCount;
 | |
|     }
 | |
|     /** Number of documents deleted. */
 | |
|     get deletedCount() {
 | |
|         return this.result.deletedCount;
 | |
|     }
 | |
|     /** Number of documents upserted. */
 | |
|     get upsertedCount() {
 | |
|         return this.result.upsertedCount;
 | |
|     }
 | |
|     /** Inserted document generated Id's, hash key is the index of the originating operation */
 | |
|     get insertedIds() {
 | |
|         return this.result.insertedIds;
 | |
|     }
 | |
|     /** Upserted document generated Id's, hash key is the index of the originating operation */
 | |
|     get upsertedIds() {
 | |
|         return this.result.upsertedIds;
 | |
|     }
 | |
| }
 | |
| exports.MongoBulkWriteError = MongoBulkWriteError;
 | |
| /**
 | |
|  * A builder object that is returned from {@link BulkOperationBase#find}.
 | |
|  * Is used to build a write operation that involves a query filter.
 | |
|  *
 | |
|  * @public
 | |
|  */
 | |
| class FindOperators {
 | |
|     /**
 | |
|      * Creates a new FindOperators object.
 | |
|      * @internal
 | |
|      */
 | |
|     constructor(bulkOperation) {
 | |
|         this.bulkOperation = bulkOperation;
 | |
|     }
 | |
|     /** Add a multiple update operation to the bulk operation */
 | |
|     update(updateDocument) {
 | |
|         const currentOp = buildCurrentOp(this.bulkOperation);
 | |
|         return this.bulkOperation.addToOperationsList(exports.BatchType.UPDATE, (0, update_1.makeUpdateStatement)(currentOp.selector, updateDocument, {
 | |
|             ...currentOp,
 | |
|             multi: true
 | |
|         }));
 | |
|     }
 | |
|     /** Add a single update operation to the bulk operation */
 | |
|     updateOne(updateDocument) {
 | |
|         if (!(0, utils_1.hasAtomicOperators)(updateDocument)) {
 | |
|             throw new error_1.MongoInvalidArgumentError('Update document requires atomic operators');
 | |
|         }
 | |
|         const currentOp = buildCurrentOp(this.bulkOperation);
 | |
|         return this.bulkOperation.addToOperationsList(exports.BatchType.UPDATE, (0, update_1.makeUpdateStatement)(currentOp.selector, updateDocument, { ...currentOp, multi: false }));
 | |
|     }
 | |
|     /** Add a replace one operation to the bulk operation */
 | |
|     replaceOne(replacement) {
 | |
|         if ((0, utils_1.hasAtomicOperators)(replacement)) {
 | |
|             throw new error_1.MongoInvalidArgumentError('Replacement document must not use atomic operators');
 | |
|         }
 | |
|         const currentOp = buildCurrentOp(this.bulkOperation);
 | |
|         return this.bulkOperation.addToOperationsList(exports.BatchType.UPDATE, (0, update_1.makeUpdateStatement)(currentOp.selector, replacement, { ...currentOp, multi: false }));
 | |
|     }
 | |
|     /** Add a delete one operation to the bulk operation */
 | |
|     deleteOne() {
 | |
|         const currentOp = buildCurrentOp(this.bulkOperation);
 | |
|         return this.bulkOperation.addToOperationsList(exports.BatchType.DELETE, (0, delete_1.makeDeleteStatement)(currentOp.selector, { ...currentOp, limit: 1 }));
 | |
|     }
 | |
|     /** Add a delete many operation to the bulk operation */
 | |
|     delete() {
 | |
|         const currentOp = buildCurrentOp(this.bulkOperation);
 | |
|         return this.bulkOperation.addToOperationsList(exports.BatchType.DELETE, (0, delete_1.makeDeleteStatement)(currentOp.selector, { ...currentOp, limit: 0 }));
 | |
|     }
 | |
|     /** Upsert modifier for update bulk operation, noting that this operation is an upsert. */
 | |
|     upsert() {
 | |
|         if (!this.bulkOperation.s.currentOp) {
 | |
|             this.bulkOperation.s.currentOp = {};
 | |
|         }
 | |
|         this.bulkOperation.s.currentOp.upsert = true;
 | |
|         return this;
 | |
|     }
 | |
|     /** Specifies the collation for the query condition. */
 | |
|     collation(collation) {
 | |
|         if (!this.bulkOperation.s.currentOp) {
 | |
|             this.bulkOperation.s.currentOp = {};
 | |
|         }
 | |
|         this.bulkOperation.s.currentOp.collation = collation;
 | |
|         return this;
 | |
|     }
 | |
|     /** Specifies arrayFilters for UpdateOne or UpdateMany bulk operations. */
 | |
|     arrayFilters(arrayFilters) {
 | |
|         if (!this.bulkOperation.s.currentOp) {
 | |
|             this.bulkOperation.s.currentOp = {};
 | |
|         }
 | |
|         this.bulkOperation.s.currentOp.arrayFilters = arrayFilters;
 | |
|         return this;
 | |
|     }
 | |
|     /** Specifies hint for the bulk operation. */
 | |
|     hint(hint) {
 | |
|         if (!this.bulkOperation.s.currentOp) {
 | |
|             this.bulkOperation.s.currentOp = {};
 | |
|         }
 | |
|         this.bulkOperation.s.currentOp.hint = hint;
 | |
|         return this;
 | |
|     }
 | |
| }
 | |
| 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;
 | |
|     }
 | |
|     execute(server, session, callback) {
 | |
|         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 executeCommands(this.bulkOperation, this.options, callback);
 | |
|     }
 | |
| }
 | |
| /** @public */
 | |
| class BulkOperationBase {
 | |
|     /**
 | |
|      * Create a new OrderedBulkOperation or UnorderedBulkOperation instance
 | |
|      * @internal
 | |
|      */
 | |
|     constructor(collection, options, isOrdered) {
 | |
|         // determine whether bulkOperation is ordered or unordered
 | |
|         this.isOrdered = isOrdered;
 | |
|         const topology = (0, utils_1.getTopology)(collection);
 | |
|         options = options == null ? {} : options;
 | |
|         // TODO Bring from driver information in hello
 | |
|         // Get the namespace for the write operations
 | |
|         const namespace = collection.s.namespace;
 | |
|         // Used to mark operation as executed
 | |
|         const executed = false;
 | |
|         // Current item
 | |
|         const currentOp = undefined;
 | |
|         // Set max byte size
 | |
|         const hello = topology.lastHello();
 | |
|         // If we have autoEncryption on, batch-splitting must be done on 2mb chunks, but single documents
 | |
|         // over 2mb are still allowed
 | |
|         const usingAutoEncryption = !!(topology.s.options && topology.s.options.autoEncrypter);
 | |
|         const maxBsonObjectSize = hello && hello.maxBsonObjectSize ? hello.maxBsonObjectSize : 1024 * 1024 * 16;
 | |
|         const maxBatchSizeBytes = usingAutoEncryption ? 1024 * 1024 * 2 : maxBsonObjectSize;
 | |
|         const maxWriteBatchSize = hello && hello.maxWriteBatchSize ? hello.maxWriteBatchSize : 1000;
 | |
|         // Calculates the largest possible size of an Array key, represented as a BSON string
 | |
|         // element. This calculation:
 | |
|         //     1 byte for BSON type
 | |
|         //     # of bytes = length of (string representation of (maxWriteBatchSize - 1))
 | |
|         //   + 1 bytes for null terminator
 | |
|         const maxKeySize = (maxWriteBatchSize - 1).toString(10).length + 2;
 | |
|         // Final options for retryable writes
 | |
|         let finalOptions = Object.assign({}, options);
 | |
|         finalOptions = (0, utils_1.applyRetryableWrites)(finalOptions, collection.s.db);
 | |
|         // Final results
 | |
|         const bulkResult = {
 | |
|             ok: 1,
 | |
|             writeErrors: [],
 | |
|             writeConcernErrors: [],
 | |
|             insertedIds: [],
 | |
|             nInserted: 0,
 | |
|             nUpserted: 0,
 | |
|             nMatched: 0,
 | |
|             nModified: 0,
 | |
|             nRemoved: 0,
 | |
|             upserted: []
 | |
|         };
 | |
|         // Internal state
 | |
|         this.s = {
 | |
|             // Final result
 | |
|             bulkResult,
 | |
|             // Current batch state
 | |
|             currentBatch: undefined,
 | |
|             currentIndex: 0,
 | |
|             // ordered specific
 | |
|             currentBatchSize: 0,
 | |
|             currentBatchSizeBytes: 0,
 | |
|             // unordered specific
 | |
|             currentInsertBatch: undefined,
 | |
|             currentUpdateBatch: undefined,
 | |
|             currentRemoveBatch: undefined,
 | |
|             batches: [],
 | |
|             // Write concern
 | |
|             writeConcern: write_concern_1.WriteConcern.fromOptions(options),
 | |
|             // Max batch size options
 | |
|             maxBsonObjectSize,
 | |
|             maxBatchSizeBytes,
 | |
|             maxWriteBatchSize,
 | |
|             maxKeySize,
 | |
|             // Namespace
 | |
|             namespace,
 | |
|             // Topology
 | |
|             topology,
 | |
|             // Options
 | |
|             options: finalOptions,
 | |
|             // BSON options
 | |
|             bsonOptions: (0, bson_1.resolveBSONOptions)(options),
 | |
|             // Current operation
 | |
|             currentOp,
 | |
|             // Executed
 | |
|             executed,
 | |
|             // Collection
 | |
|             collection,
 | |
|             // Fundamental error
 | |
|             err: undefined,
 | |
|             // check keys
 | |
|             checkKeys: typeof options.checkKeys === 'boolean' ? options.checkKeys : false
 | |
|         };
 | |
|         // bypass Validation
 | |
|         if (options.bypassDocumentValidation === true) {
 | |
|             this.s.bypassDocumentValidation = true;
 | |
|         }
 | |
|     }
 | |
|     /**
 | |
|      * Add a single insert document to the bulk operation
 | |
|      *
 | |
|      * @example
 | |
|      * ```ts
 | |
|      * const bulkOp = collection.initializeOrderedBulkOp();
 | |
|      *
 | |
|      * // Adds three inserts to the bulkOp.
 | |
|      * bulkOp
 | |
|      *   .insert({ a: 1 })
 | |
|      *   .insert({ b: 2 })
 | |
|      *   .insert({ c: 3 });
 | |
|      * await bulkOp.execute();
 | |
|      * ```
 | |
|      */
 | |
|     insert(document) {
 | |
|         if (document._id == null && !shouldForceServerObjectId(this)) {
 | |
|             document._id = new bson_1.ObjectId();
 | |
|         }
 | |
|         return this.addToOperationsList(exports.BatchType.INSERT, document);
 | |
|     }
 | |
|     /**
 | |
|      * Builds a find operation for an update/updateOne/delete/deleteOne/replaceOne.
 | |
|      * Returns a builder object used to complete the definition of the operation.
 | |
|      *
 | |
|      * @example
 | |
|      * ```ts
 | |
|      * const bulkOp = collection.initializeOrderedBulkOp();
 | |
|      *
 | |
|      * // Add an updateOne to the bulkOp
 | |
|      * bulkOp.find({ a: 1 }).updateOne({ $set: { b: 2 } });
 | |
|      *
 | |
|      * // Add an updateMany to the bulkOp
 | |
|      * bulkOp.find({ c: 3 }).update({ $set: { d: 4 } });
 | |
|      *
 | |
|      * // Add an upsert
 | |
|      * bulkOp.find({ e: 5 }).upsert().updateOne({ $set: { f: 6 } });
 | |
|      *
 | |
|      * // Add a deletion
 | |
|      * bulkOp.find({ g: 7 }).deleteOne();
 | |
|      *
 | |
|      * // Add a multi deletion
 | |
|      * bulkOp.find({ h: 8 }).delete();
 | |
|      *
 | |
|      * // Add a replaceOne
 | |
|      * bulkOp.find({ i: 9 }).replaceOne({writeConcern: { j: 10 }});
 | |
|      *
 | |
|      * // Update using a pipeline (requires Mongodb 4.2 or higher)
 | |
|      * bulk.find({ k: 11, y: { $exists: true }, z: { $exists: true } }).updateOne([
 | |
|      *   { $set: { total: { $sum: [ '$y', '$z' ] } } }
 | |
|      * ]);
 | |
|      *
 | |
|      * // All of the ops will now be executed
 | |
|      * await bulkOp.execute();
 | |
|      * ```
 | |
|      */
 | |
|     find(selector) {
 | |
|         if (!selector) {
 | |
|             throw new error_1.MongoInvalidArgumentError('Bulk find operation must specify a selector');
 | |
|         }
 | |
|         // Save a current selector
 | |
|         this.s.currentOp = {
 | |
|             selector: selector
 | |
|         };
 | |
|         return new FindOperators(this);
 | |
|     }
 | |
|     /** Specifies a raw operation to perform in the bulk write. */
 | |
|     raw(op) {
 | |
|         if (op == null || typeof op !== 'object') {
 | |
|             throw new error_1.MongoInvalidArgumentError('Operation must be an object with an operation key');
 | |
|         }
 | |
|         if ('insertOne' in op) {
 | |
|             const forceServerObjectId = shouldForceServerObjectId(this);
 | |
|             if (op.insertOne && op.insertOne.document == null) {
 | |
|                 // NOTE: provided for legacy support, but this is a malformed operation
 | |
|                 if (forceServerObjectId !== true && op.insertOne._id == null) {
 | |
|                     op.insertOne._id = new bson_1.ObjectId();
 | |
|                 }
 | |
|                 return this.addToOperationsList(exports.BatchType.INSERT, op.insertOne);
 | |
|             }
 | |
|             if (forceServerObjectId !== true && op.insertOne.document._id == null) {
 | |
|                 op.insertOne.document._id = new bson_1.ObjectId();
 | |
|             }
 | |
|             return this.addToOperationsList(exports.BatchType.INSERT, op.insertOne.document);
 | |
|         }
 | |
|         if ('replaceOne' in op || 'updateOne' in op || 'updateMany' in op) {
 | |
|             if ('replaceOne' in op) {
 | |
|                 if ('q' in op.replaceOne) {
 | |
|                     throw new error_1.MongoInvalidArgumentError('Raw operations are not allowed');
 | |
|                 }
 | |
|                 const updateStatement = (0, update_1.makeUpdateStatement)(op.replaceOne.filter, op.replaceOne.replacement, { ...op.replaceOne, multi: false });
 | |
|                 if ((0, utils_1.hasAtomicOperators)(updateStatement.u)) {
 | |
|                     throw new error_1.MongoInvalidArgumentError('Replacement document must not use atomic operators');
 | |
|                 }
 | |
|                 return this.addToOperationsList(exports.BatchType.UPDATE, updateStatement);
 | |
|             }
 | |
|             if ('updateOne' in op) {
 | |
|                 if ('q' in op.updateOne) {
 | |
|                     throw new error_1.MongoInvalidArgumentError('Raw operations are not allowed');
 | |
|                 }
 | |
|                 const updateStatement = (0, update_1.makeUpdateStatement)(op.updateOne.filter, op.updateOne.update, {
 | |
|                     ...op.updateOne,
 | |
|                     multi: false
 | |
|                 });
 | |
|                 if (!(0, utils_1.hasAtomicOperators)(updateStatement.u)) {
 | |
|                     throw new error_1.MongoInvalidArgumentError('Update document requires atomic operators');
 | |
|                 }
 | |
|                 return this.addToOperationsList(exports.BatchType.UPDATE, updateStatement);
 | |
|             }
 | |
|             if ('updateMany' in op) {
 | |
|                 if ('q' in op.updateMany) {
 | |
|                     throw new error_1.MongoInvalidArgumentError('Raw operations are not allowed');
 | |
|                 }
 | |
|                 const updateStatement = (0, update_1.makeUpdateStatement)(op.updateMany.filter, op.updateMany.update, {
 | |
|                     ...op.updateMany,
 | |
|                     multi: true
 | |
|                 });
 | |
|                 if (!(0, utils_1.hasAtomicOperators)(updateStatement.u)) {
 | |
|                     throw new error_1.MongoInvalidArgumentError('Update document requires atomic operators');
 | |
|                 }
 | |
|                 return this.addToOperationsList(exports.BatchType.UPDATE, updateStatement);
 | |
|             }
 | |
|         }
 | |
|         if ('deleteOne' in op) {
 | |
|             if ('q' in op.deleteOne) {
 | |
|                 throw new error_1.MongoInvalidArgumentError('Raw operations are not allowed');
 | |
|             }
 | |
|             return this.addToOperationsList(exports.BatchType.DELETE, (0, delete_1.makeDeleteStatement)(op.deleteOne.filter, { ...op.deleteOne, limit: 1 }));
 | |
|         }
 | |
|         if ('deleteMany' in op) {
 | |
|             if ('q' in op.deleteMany) {
 | |
|                 throw new error_1.MongoInvalidArgumentError('Raw operations are not allowed');
 | |
|             }
 | |
|             return this.addToOperationsList(exports.BatchType.DELETE, (0, delete_1.makeDeleteStatement)(op.deleteMany.filter, { ...op.deleteMany, limit: 0 }));
 | |
|         }
 | |
|         // otherwise an unknown operation was provided
 | |
|         throw new error_1.MongoInvalidArgumentError('bulkWrite only supports insertOne, updateOne, updateMany, deleteOne, deleteMany');
 | |
|     }
 | |
|     get bsonOptions() {
 | |
|         return this.s.bsonOptions;
 | |
|     }
 | |
|     get writeConcern() {
 | |
|         return this.s.writeConcern;
 | |
|     }
 | |
|     get batches() {
 | |
|         const batches = [...this.s.batches];
 | |
|         if (this.isOrdered) {
 | |
|             if (this.s.currentBatch)
 | |
|                 batches.push(this.s.currentBatch);
 | |
|         }
 | |
|         else {
 | |
|             if (this.s.currentInsertBatch)
 | |
|                 batches.push(this.s.currentInsertBatch);
 | |
|             if (this.s.currentUpdateBatch)
 | |
|                 batches.push(this.s.currentUpdateBatch);
 | |
|             if (this.s.currentRemoveBatch)
 | |
|                 batches.push(this.s.currentRemoveBatch);
 | |
|         }
 | |
|         return batches;
 | |
|     }
 | |
|     async execute(options = {}) {
 | |
|         if (this.s.executed) {
 | |
|             throw new error_1.MongoBatchReExecutionError();
 | |
|         }
 | |
|         const writeConcern = write_concern_1.WriteConcern.fromOptions(options);
 | |
|         if (writeConcern) {
 | |
|             this.s.writeConcern = writeConcern;
 | |
|         }
 | |
|         // If we have current batch
 | |
|         if (this.isOrdered) {
 | |
|             if (this.s.currentBatch)
 | |
|                 this.s.batches.push(this.s.currentBatch);
 | |
|         }
 | |
|         else {
 | |
|             if (this.s.currentInsertBatch)
 | |
|                 this.s.batches.push(this.s.currentInsertBatch);
 | |
|             if (this.s.currentUpdateBatch)
 | |
|                 this.s.batches.push(this.s.currentUpdateBatch);
 | |
|             if (this.s.currentRemoveBatch)
 | |
|                 this.s.batches.push(this.s.currentRemoveBatch);
 | |
|         }
 | |
|         // If we have no operations in the bulk raise an error
 | |
|         if (this.s.batches.length === 0) {
 | |
|             throw new error_1.MongoInvalidArgumentError('Invalid BulkOperation, Batch cannot be empty');
 | |
|         }
 | |
|         this.s.executed = true;
 | |
|         const finalOptions = { ...this.s.options, ...options };
 | |
|         const operation = new BulkWriteShimOperation(this, finalOptions);
 | |
|         return (0, execute_operation_1.executeOperation)(this.s.collection.s.db.s.client, operation);
 | |
|     }
 | |
|     /**
 | |
|      * Handles the write error before executing commands
 | |
|      * @internal
 | |
|      */
 | |
|     handleWriteError(callback, writeResult) {
 | |
|         if (this.s.bulkResult.writeErrors.length > 0) {
 | |
|             const msg = this.s.bulkResult.writeErrors[0].errmsg
 | |
|                 ? this.s.bulkResult.writeErrors[0].errmsg
 | |
|                 : 'write operation failed';
 | |
|             callback(new MongoBulkWriteError({
 | |
|                 message: msg,
 | |
|                 code: this.s.bulkResult.writeErrors[0].code,
 | |
|                 writeErrors: this.s.bulkResult.writeErrors
 | |
|             }, writeResult));
 | |
|             return true;
 | |
|         }
 | |
|         const writeConcernError = writeResult.getWriteConcernError();
 | |
|         if (writeConcernError) {
 | |
|             callback(new MongoBulkWriteError(writeConcernError, writeResult));
 | |
|             return true;
 | |
|         }
 | |
|         return false;
 | |
|     }
 | |
| }
 | |
| exports.BulkOperationBase = BulkOperationBase;
 | |
| Object.defineProperty(BulkOperationBase.prototype, 'length', {
 | |
|     enumerable: true,
 | |
|     get() {
 | |
|         return this.s.currentIndex;
 | |
|     }
 | |
| });
 | |
| function shouldForceServerObjectId(bulkOperation) {
 | |
|     if (typeof bulkOperation.s.options.forceServerObjectId === 'boolean') {
 | |
|         return bulkOperation.s.options.forceServerObjectId;
 | |
|     }
 | |
|     if (typeof bulkOperation.s.collection.s.db.options?.forceServerObjectId === 'boolean') {
 | |
|         return bulkOperation.s.collection.s.db.options?.forceServerObjectId;
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| function isInsertBatch(batch) {
 | |
|     return batch.batchType === exports.BatchType.INSERT;
 | |
| }
 | |
| function isUpdateBatch(batch) {
 | |
|     return batch.batchType === exports.BatchType.UPDATE;
 | |
| }
 | |
| function isDeleteBatch(batch) {
 | |
|     return batch.batchType === exports.BatchType.DELETE;
 | |
| }
 | |
| function buildCurrentOp(bulkOp) {
 | |
|     let { currentOp } = bulkOp.s;
 | |
|     bulkOp.s.currentOp = undefined;
 | |
|     if (!currentOp)
 | |
|         currentOp = {};
 | |
|     return currentOp;
 | |
| }
 | |
| //# sourceMappingURL=common.js.map
 |