'use strict'; const OperationBase = require('./operation').OperationBase; const applyRetryableWrites = require('../utils').applyRetryableWrites; const applyWriteConcern = require('../utils').applyWriteConcern; const decorateWithCollation = require('../utils').decorateWithCollation; const executeCommand = require('./db_ops').executeCommand; const formattedOrderClause = require('../utils').formattedOrderClause; const handleCallback = require('../utils').handleCallback; const ReadPreference = require('../core').ReadPreference; class FindAndModifyOperation extends OperationBase { constructor(collection, query, sort, doc, options) { super(options); this.collection = collection; this.query = query; this.sort = sort; this.doc = doc; } execute(callback) { const coll = this.collection; const query = this.query; const sort = formattedOrderClause(this.sort); const doc = this.doc; let options = this.options; // Create findAndModify command object const queryObject = { findAndModify: coll.collectionName, query: query }; if (sort) { queryObject.sort = sort; } queryObject.new = options.new ? true : false; queryObject.remove = options.remove ? true : false; queryObject.upsert = options.upsert ? true : false; const projection = options.projection || options.fields; if (projection) { queryObject.fields = projection; } if (options.arrayFilters) { queryObject.arrayFilters = options.arrayFilters; } if (doc && !options.remove) { queryObject.update = doc; } if (options.maxTimeMS) queryObject.maxTimeMS = options.maxTimeMS; // Either use override on the function, or go back to default on either the collection // level or db options.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions; // No check on the documents options.checkKeys = false; // Final options for retryable writes and write concern options = applyRetryableWrites(options, coll.s.db); options = applyWriteConcern(options, { db: coll.s.db, collection: coll }, options); // Decorate the findAndModify command with the write Concern if (options.writeConcern) { queryObject.writeConcern = options.writeConcern; } // Have we specified bypassDocumentValidation if (options.bypassDocumentValidation === true) { queryObject.bypassDocumentValidation = options.bypassDocumentValidation; } options.readPreference = ReadPreference.primary; // Have we specified collation try { decorateWithCollation(queryObject, coll, options); } catch (err) { return callback(err, null); } // Execute the command executeCommand(coll.s.db, queryObject, options, (err, result) => { if (err) return handleCallback(callback, err, null); return handleCallback(callback, null, result); }); } } module.exports = FindAndModifyOperation;