123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966 |
- "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 promise_provider_1 = require("../promise_provider");
- 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 {
- /**
- * Create a new BulkWriteResult instance
- * @internal
- */
- constructor(bulkResult) {
- this.result = bulkResult;
- }
- /** Number of documents inserted. */
- get insertedCount() {
- var _a;
- return (_a = this.result.nInserted) !== null && _a !== void 0 ? _a : 0;
- }
- /** Number of documents matched for update. */
- get matchedCount() {
- var _a;
- return (_a = this.result.nMatched) !== null && _a !== void 0 ? _a : 0;
- }
- /** Number of documents modified. */
- get modifiedCount() {
- var _a;
- return (_a = this.result.nModified) !== null && _a !== void 0 ? _a : 0;
- }
- /** Number of documents deleted. */
- get deletedCount() {
- var _a;
- return (_a = this.result.nRemoved) !== null && _a !== void 0 ? _a : 0;
- }
- /** Number of documents upserted. */
- get upsertedCount() {
- var _a;
- return (_a = this.result.upserted.length) !== null && _a !== void 0 ? _a : 0;
- }
- /** Upserted document generated Id's, hash key is the index of the originating operation */
- get upsertedIds() {
- var _a;
- const upserted = {};
- for (const doc of (_a = this.result.upserted) !== null && _a !== void 0 ? _a : []) {
- upserted[doc.index] = doc._id;
- }
- return upserted;
- }
- /** Inserted document generated Id's, hash key is the index of the originating operation */
- get insertedIds() {
- var _a;
- const inserted = {};
- for (const doc of (_a = this.result.insertedIds) !== null && _a !== void 0 ? _a : []) {
- inserted[doc.index] = doc._id;
- }
- return inserted;
- }
- /** 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 lastOp if available */
- getLastOp() {
- return this.result.opTime;
- }
- /** 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 });
- }
- }
- toJSON() {
- return this.result;
- }
- toString() {
- return `BulkWriteResult(${this.toJSON()})`;
- }
- 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;
- }
- /** @deprecated The `err` prop that contained a MongoServerError has been deprecated. */
- get err() {
- return this[kServerError];
- }
- 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;
- /** Converts the number to a Long or returns it. */
- function longOrConvert(value) {
- return typeof value === 'number' ? bson_1.Long.fromNumber(value) : value;
- }
- /** 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;
- }
- // The server write command specification states that lastOp is an optional
- // mongod only field that has a type of timestamp. Across various scarce specs
- // where opTime is mentioned, it is an "opaque" object that can have a "ts" and
- // "t" field with Timestamp and Long as their types respectively.
- // The "lastOp" field of the bulk write result is never mentioned in the driver
- // specifications or the bulk write spec, so we should probably just keep its
- // value consistent since it seems to vary.
- // See: https://github.com/mongodb/specifications/blob/master/source/driver-bulk-update.rst#results-object
- if (result.opTime || result.lastOp) {
- let opTime = result.lastOp || result.opTime;
- // If the opTime is a Timestamp, convert it to a consistent format to be
- // able to compare easily. Converting to the object from a timestamp is
- // much more straightforward than the other direction.
- if (opTime._bsontype === 'Timestamp') {
- opTime = { ts: opTime, t: bson_1.Long.ZERO };
- }
- // If there's no lastOp, just set it.
- if (!bulkResult.opTime) {
- bulkResult.opTime = opTime;
- }
- else {
- // First compare the ts values and set if the opTimeTS value is greater.
- const lastOpTS = longOrConvert(bulkResult.opTime.ts);
- const opTimeTS = longOrConvert(opTime.ts);
- if (opTimeTS.greaterThan(lastOpTS)) {
- bulkResult.opTime = opTime;
- }
- else if (opTimeTS.equals(lastOpTS)) {
- // If the ts values are equal, then compare using the t values.
- const lastOpT = longOrConvert(bulkResult.opTime.t);
- const opTimeT = longOrConvert(opTime.t);
- if (opTimeT.greaterThan(lastOpT)) {
- bulkResult.opTime = opTime;
- }
- }
- }
- }
- // 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
- const writeResult = new BulkWriteResult(bulkOperation.s.bulkResult);
- const mergeResult = mergeBatchResults(batch, bulkOperation.s.bulkResult, err, result);
- if (mergeResult != null) {
- return callback(undefined, writeResult);
- }
- 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) {
- var _a, _b;
- mergeBatchResults(batch, bulkResult, undefined, err.result);
- callback(new MongoBulkWriteError({
- message: (_a = err.result) === null || _a === void 0 ? void 0 : _a.writeConcernError.errmsg,
- code: (_b = err.result) === null || _b === void 0 ? void 0 : _b.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) {
- var _a;
- 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 = (_a = error.writeErrors) !== null && _a !== void 0 ? _a : [];
- }
- 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;
- }
- }
- 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
- * ```js
- * 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
- * ```js
- * 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;
- }
- execute(options, callback) {
- if (typeof options === 'function')
- (callback = options), (options = {});
- options = options !== null && options !== void 0 ? options : {};
- if (this.s.executed) {
- return handleEarlyError(new error_1.MongoBatchReExecutionError(), callback);
- }
- 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) {
- const emptyBatchError = new error_1.MongoInvalidArgumentError('Invalid BulkOperation, Batch cannot be empty');
- return handleEarlyError(emptyBatchError, callback);
- }
- 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, callback);
- }
- /**
- * 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;
- }
- });
- /** helper function to assist with promiseOrCallback behavior */
- function handleEarlyError(err, callback) {
- const Promise = promise_provider_1.PromiseProvider.get();
- if (typeof callback === 'function') {
- callback(err);
- return;
- }
- return Promise.reject(err);
- }
- function shouldForceServerObjectId(bulkOperation) {
- var _a, _b;
- if (typeof bulkOperation.s.options.forceServerObjectId === 'boolean') {
- return bulkOperation.s.options.forceServerObjectId;
- }
- if (typeof ((_a = bulkOperation.s.collection.s.db.options) === null || _a === void 0 ? void 0 : _a.forceServerObjectId) === 'boolean') {
- return (_b = bulkOperation.s.collection.s.db.options) === null || _b === void 0 ? void 0 : _b.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
|