diff --git a/src/collection.ts b/src/collection.ts index df7c437397c..abc1ca6da32 100644 --- a/src/collection.ts +++ b/src/collection.ts @@ -1,4 +1,4 @@ -import { emitDeprecatedOptionWarning } from './utils'; +import { emitDeprecatedOptionWarning, resolveOptions } from './utils'; import { ReadPreference, ReadPreferenceLike } from './read_preference'; import { deprecate } from 'util'; import { @@ -280,11 +280,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new InsertOneOperation(this, doc, options), + new InsertOneOperation(this, doc, resolveOptions(this, options)), callback ); } @@ -405,11 +404,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = Object.assign({}, options); return executeOperation( getTopology(this), - new UpdateOneOperation(this, filter, update, options), + new UpdateOneOperation(this, filter, update, resolveOptions(this, options)), callback ); } @@ -442,11 +440,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = Object.assign({}, options); return executeOperation( getTopology(this), - new ReplaceOneOperation(this, filter, replacement, options), + new ReplaceOneOperation(this, filter, replacement, resolveOptions(this, options)), callback ); } @@ -475,11 +472,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = Object.assign({}, options); return executeOperation( getTopology(this), - new UpdateManyOperation(this, filter, update, options), + new UpdateManyOperation(this, filter, update, resolveOptions(this, options)), callback ); } @@ -501,11 +497,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = Object.assign({}, options); return executeOperation( getTopology(this), - new DeleteOneOperation(this, filter, options), + new DeleteOneOperation(this, filter, resolveOptions(this, options)), callback ); } @@ -539,11 +534,9 @@ export class Collection implements OperationParent { options = {}; } - options = Object.assign({}, options); - return executeOperation( getTopology(this), - new DeleteManyOperation(this, filter, options), + new DeleteManyOperation(this, filter, resolveOptions(this, options)), callback ); } @@ -551,6 +544,9 @@ export class Collection implements OperationParent { /** * Rename the collection. * + * @remarks + * This operation does not inherit options from the Db or MongoClient. + * * @param newName - New name of of the collection. * @param options - Optional settings for the command * @param callback - An optional callback, a Promise will be returned if none is provided @@ -565,11 +561,11 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = Object.assign({}, options, { readPreference: ReadPreference.PRIMARY }); + // Intentionally, we do not inherit options from parent for this operation. return executeOperation( getTopology(this), - new RenameOperation(this, newName, options), + new RenameOperation(this, newName, { ...options, readPreference: ReadPreference.PRIMARY }), callback ); } @@ -624,11 +620,10 @@ export class Collection implements OperationParent { (callback = query as Callback), (query = {}), (options = {}); if (typeof options === 'function') (callback = options), (options = {}); query = query || {}; - options = options || {}; return executeOperation( getTopology(this), - new FindOneOperation(this, query, options), + new FindOneOperation(this, query, resolveOptions(this, options)), callback ); } @@ -649,6 +644,7 @@ export class Collection implements OperationParent { throw new TypeError('`options` parameter must not be function'); } + options = resolveOptions(this, options); return new Cursor( getTopology(this), new FindOperation(this, this.s.namespace, filter, options), @@ -671,9 +667,12 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; - return executeOperation(getTopology(this), new OptionsOperation(this, options), callback); + return executeOperation( + getTopology(this), + new OptionsOperation(this, resolveOptions(this, options)), + callback + ); } /** @@ -691,9 +690,12 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; - return executeOperation(getTopology(this), new IsCappedOperation(this, options), callback); + return executeOperation( + getTopology(this), + new IsCappedOperation(this, resolveOptions(this, options)), + callback + ); } /** @@ -739,11 +741,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new CreateIndexOperation(this, this.collectionName, indexSpec, options), + new CreateIndexOperation(this, this.collectionName, indexSpec, resolveOptions(this, options)), callback ); } @@ -799,7 +800,12 @@ export class Collection implements OperationParent { return executeOperation( getTopology(this), - new CreateIndexesOperation(this, this.collectionName, indexSpecs, options), + new CreateIndexesOperation( + this, + this.collectionName, + indexSpecs, + resolveOptions(this, options) + ), callback ); } @@ -821,7 +827,7 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; + options = resolveOptions(this, options); // Run only against primary options.readPreference = ReadPreference.primary; @@ -848,9 +854,12 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options ? Object.assign({}, options) : {}; - return executeOperation(getTopology(this), new DropIndexesOperation(this, options), callback); + return executeOperation( + getTopology(this), + new DropIndexesOperation(this, resolveOptions(this, options)), + callback + ); } /** @@ -859,6 +868,7 @@ export class Collection implements OperationParent { * @param options - Optional settings for the command */ listIndexes(options?: ListIndexesOptions): CommandCursor { + options = resolveOptions(this, options); const cursor = new CommandCursor( getTopology(this), new ListIndexesOperation(this, options), @@ -889,11 +899,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new IndexExistsOperation(this, indexes, options), + new IndexExistsOperation(this, indexes, resolveOptions(this, options)), callback ); } @@ -913,11 +922,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new IndexInformationOperation(this.s.db, this.collectionName, options), + new IndexInformationOperation(this.s.db, this.collectionName, resolveOptions(this, options)), callback ); } @@ -937,11 +945,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new EstimatedDocumentCountOperation(this, options), + new EstimatedDocumentCountOperation(this, resolveOptions(this, options)), callback ); } @@ -994,10 +1001,13 @@ export class Collection implements OperationParent { } query = query || {}; - options = options || {}; return executeOperation( getTopology(this), - new CountDocumentsOperation(this, query as Document, options as CountDocumentsOptions), + new CountDocumentsOperation( + this, + query as Document, + resolveOptions(this, options as CountDocumentsOptions) + ), callback ); } @@ -1036,10 +1046,14 @@ export class Collection implements OperationParent { } query = query || {}; - options = options || {}; return executeOperation( getTopology(this), - new DistinctOperation(this, key, query as Document, options as DistinctOptions), + new DistinctOperation( + this, + key, + query as Document, + resolveOptions(this, options as DistinctOptions) + ), callback ); } @@ -1059,9 +1073,12 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; - return executeOperation(getTopology(this), new IndexesOperation(this, options), callback); + return executeOperation( + getTopology(this), + new IndexesOperation(this, resolveOptions(this, options)), + callback + ); } /** @@ -1105,11 +1122,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new FindOneAndDeleteOperation(this, filter, options), + new FindOneAndDeleteOperation(this, filter, resolveOptions(this, options)), callback ); } @@ -1142,11 +1158,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new FindOneAndReplaceOperation(this, filter, replacement, options), + new FindOneAndReplaceOperation(this, filter, replacement, resolveOptions(this, options)), callback ); } @@ -1179,11 +1194,10 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new FindOneAndUpdateOperation(this, filter, update, options), + new FindOneAndUpdateOperation(this, filter, update, resolveOptions(this, options)), callback ); } @@ -1205,8 +1219,7 @@ export class Collection implements OperationParent { throw new TypeError('`options` parameter must not be function'); } - options = options || {}; - + options = resolveOptions(this, options); return new AggregationCursor( getTopology(this), new AggregateOperation(this, pipeline, options), @@ -1292,7 +1305,7 @@ export class Collection implements OperationParent { return executeOperation( getTopology(this), - new MapReduceOperation(this, map, reduce, options), + new MapReduceOperation(this, map, reduce, resolveOptions(this, options)), callback ); } @@ -1396,11 +1409,15 @@ export class Collection implements OperationParent { callback: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new EnsureIndexOperation(this.s.db, this.collectionName, fieldOrSpec, options), + new EnsureIndexOperation( + this.s.db, + this.collectionName, + fieldOrSpec, + resolveOptions(this, options) + ), callback ); } @@ -1436,10 +1453,9 @@ export class Collection implements OperationParent { } query = query || {}; - options = options || {}; return executeOperation( getTopology(this), - new EstimatedDocumentCountOperation(this, query, options), + new EstimatedDocumentCountOperation(this, query, resolveOptions(this, options)), callback ); } @@ -1483,6 +1499,7 @@ export class Collection implements OperationParent { options = {}; } + options = resolveOptions(this, options); // Add the remove option options.remove = true; @@ -1518,7 +1535,7 @@ export class Collection implements OperationParent { let reduce = args.length ? args.shift() : undefined; let finalize = args.length ? args.shift() : undefined; let command = args.length ? args.shift() : undefined; - const options = args.length ? args.shift() || {} : {}; + let options = args.length ? args.shift() || {} : {}; // Make sure we are backward compatible if (!(typeof finalize === 'function')) { @@ -1546,6 +1563,8 @@ export class Collection implements OperationParent { // Set up the command as default command = command == null ? true : command; + options = resolveOptions(this, options); + if (command == null) { return executeOperation( getTopology(this), @@ -1600,7 +1619,7 @@ export class Collection implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; + options = resolveOptions(this, options); // Force read preference primary options.readPreference = ReadPreference.primary; diff --git a/src/db.ts b/src/db.ts index 96520303a5f..0c8feaf5475 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,5 +1,13 @@ import { deprecate } from 'util'; -import { emitDeprecatedOptionWarning, Callback } from './utils'; +import { + emitDeprecatedOptionWarning, + Callback, + resolveOptions, + filterOptions, + deprecateOptions, + MongoDBNamespace, + getTopology +} from './utils'; import { loadAdmin } from './dynamic_loaders'; import { AggregationCursor, CommandCursor } from './cursor'; import { ObjectId, Code, Document, BSONSerializeOptions, resolveBSONOptions } from './bson'; @@ -11,13 +19,6 @@ import * as CONSTANTS from './constants'; import { WriteConcern, WriteConcernOptions } from './write_concern'; import { ReadConcern } from './read_concern'; import { Logger, LoggerOptions } from './logger'; -import { - filterOptions, - mergeOptionsAndWriteConcern, - deprecateOptions, - MongoDBNamespace, - getTopology -} from './utils'; import { AggregateOperation, AggregateOptions } from './operations/aggregate'; import { AddUserOperation, AddUserOptions } from './operations/add_user'; import { CollectionsOperation } from './operations/collections'; @@ -254,12 +255,10 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; - options.readConcern = ReadConcern.fromOptions(options) ?? this.readConcern; return executeOperation( getTopology(this), - new CreateCollectionOperation(this, name, options), + new CreateCollectionOperation(this, name, resolveOptions(this, options)), callback ); } @@ -267,6 +266,9 @@ export class Db implements OperationParent { /** * Execute a command * + * @remarks + * This command does not inherit options from the MongoClient. + * * @param command - The command to run * @param options - Optional settings for the command * @param callback - An optional callback, a Promise will be returned if none is provided @@ -281,11 +283,11 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; + // Intentionally, we do not inherit options from parent for this operation. return executeOperation( getTopology(this), - new RunCommandOperation(this, command, options), + new RunCommandOperation(this, command, options ?? {}), callback ); } @@ -307,8 +309,7 @@ export class Db implements OperationParent { throw new TypeError('`options` parameter must not be function'); } - options = options || {}; - + options = resolveOptions(this, options); const cursor = new AggregationCursor( getTopology(this), new AggregateOperation(this, pipeline, options), @@ -341,21 +342,10 @@ export class Db implements OperationParent { callback?: Callback ): Collection | void { if (typeof options === 'function') (callback = options), (options = {}); - options = Object.assign({}, options); - - // If we have not set a collection level readConcern set the db level one - options.readConcern = ReadConcern.fromOptions(options) ?? this.readConcern; - - // Merge in all needed options and ensure correct writeConcern merging from db level - const finalOptions = mergeOptionsAndWriteConcern( - options, - this.s.options ?? {}, - collectionKeys, - true - ) as CollectionOptions; + const finalOptions = resolveOptions(this, options); // Execute - if (finalOptions == null || !finalOptions.strict) { + if (!finalOptions.strict) { try { const collection = new Collection(this, name, finalOptions); if (callback) callback(undefined, collection); @@ -414,9 +404,11 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; - - return executeOperation(getTopology(this), new DbStatsOperation(this, options), callback); + return executeOperation( + getTopology(this), + new DbStatsOperation(this, resolveOptions(this, options)), + callback + ); } /** @@ -427,7 +419,7 @@ export class Db implements OperationParent { */ listCollections(filter?: Document, options?: ListCollectionsOptions): CommandCursor { filter = filter || {}; - options = options || {}; + options = resolveOptions(this, options); return new CommandCursor( getTopology(this), @@ -439,6 +431,9 @@ export class Db implements OperationParent { /** * Rename a collection. * + * @remarks + * This operation does not inherit options from the MongoClient. + * * @param fromCollection - Name of current collection to rename * @param toCollection - New name of of the collection * @param options - Optional settings for the command @@ -468,7 +463,9 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = Object.assign({}, options, { readPreference: ReadPreference.PRIMARY }); + + // Intentionally, we do not inherit options from parent for this operation. + options = { ...options, readPreference: ReadPreference.PRIMARY }; // Add return new collection options.new_collection = true; @@ -497,11 +494,10 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new DropCollectionOperation(this, name, options), + new DropCollectionOperation(this, name, resolveOptions(this, options)), callback ); } @@ -521,9 +517,12 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; - return executeOperation(getTopology(this), new DropDatabaseOperation(this, options), callback); + return executeOperation( + getTopology(this), + new DropDatabaseOperation(this, resolveOptions(this, options)), + callback + ); } /** @@ -541,14 +540,20 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; - return executeOperation(getTopology(this), new CollectionsOperation(this, options), callback); + return executeOperation( + getTopology(this), + new CollectionsOperation(this, resolveOptions(this, options)), + callback + ); } /** * Runs a command on the database as admin. * + * @remarks + * This command does not inherit options from the MongoClient. + * * @param command - The command to run * @param options - Optional settings for the command * @param callback - An optional callback, a Promise will be returned if none is provided @@ -567,11 +572,11 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; + // Intentionally, we do not inherit options from parent for this operation. return executeOperation( getTopology(this), - new RunAdminCommandOperation(this, command, options), + new RunAdminCommandOperation(this, command, options ?? {}), callback ); } @@ -604,11 +609,10 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options ? Object.assign({}, options) : {}; return executeOperation( getTopology(this), - new CreateIndexOperation(this, name, indexSpec, options), + new CreateIndexOperation(this, name, indexSpec, resolveOptions(this, options)), callback ); } @@ -652,10 +656,9 @@ export class Db implements OperationParent { if (typeof options === 'function') (callback = options), (options = {}); } - options = options || {}; return executeOperation( getTopology(this), - new AddUserOperation(this, username, password, options), + new AddUserOperation(this, username, password, resolveOptions(this, options)), callback ); } @@ -677,11 +680,10 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new RemoveUserOperation(this, username, options), + new RemoveUserOperation(this, username, resolveOptions(this, options)), callback ); } @@ -710,11 +712,10 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new SetProfilingLevelOperation(this, level, options), + new SetProfilingLevelOperation(this, level, resolveOptions(this, options)), callback ); } @@ -734,11 +735,10 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new ProfilingLevelOperation(this, options), + new ProfilingLevelOperation(this, resolveOptions(this, options)), callback ); } @@ -764,11 +764,10 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new IndexInformationOperation(this, name, options), + new IndexInformationOperation(this, name, resolveOptions(this, options)), callback ); } @@ -835,11 +834,10 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new EvalOperation(this, code, parameters, options), + new EvalOperation(this, code, parameters, resolveOptions(this, options)), callback ); } @@ -873,11 +871,10 @@ export class Db implements OperationParent { callback?: Callback ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); - options = options || {}; return executeOperation( getTopology(this), - new EnsureIndexOperation(this, name, fieldOrSpec, options), + new EnsureIndexOperation(this, name, fieldOrSpec, resolveOptions(this, options)), callback ); } @@ -905,18 +902,6 @@ export class Db implements OperationParent { } } -const collectionKeys = [ - 'pkFactory', - 'readPreference', - 'serializeFunctions', - 'strict', - 'readConcern', - 'ignoreUndefined', - 'promoteValues', - 'promoteBuffers', - 'promoteLongs' -]; - Db.prototype.createCollection = deprecateOptions( { name: 'Db.createCollection', diff --git a/src/operations/command.ts b/src/operations/command.ts index 818610402ac..0d89485c680 100644 --- a/src/operations/command.ts +++ b/src/operations/command.ts @@ -73,12 +73,13 @@ export abstract class CommandOperation< : new MongoDBNamespace('admin', '$cmd'); } - const propertyProvider = this.hasAspect(Aspect.NO_INHERIT_OPTIONS) ? undefined : parent; this.readPreference = this.hasAspect(Aspect.WRITE_OPERATION) ? ReadPreference.primary - : ReadPreference.resolve(propertyProvider, this.options); - this.readConcern = resolveReadConcern(propertyProvider, this.options); - this.writeConcern = resolveWriteConcern(propertyProvider, this.options); + : ReadPreference.fromOptions(options) ?? ReadPreference.primary; + this.readConcern = ReadConcern.fromOptions(options); + this.writeConcern = WriteConcern.fromOptions(options); + this.bsonOptions = resolveBSONOptions(options); + this.explain = false; this.fullResponse = options && typeof options.fullResponse === 'boolean' ? options.fullResponse : false; @@ -91,9 +92,6 @@ export abstract class CommandOperation< if (parent && parent.logger) { this.logger = parent.logger; } - - // Assign BSON serialize options to OperationBase, preferring options over parent options. - this.bsonOptions = resolveBSONOptions(options, parent); } abstract execute(server: Server, callback: Callback): void; @@ -149,11 +147,3 @@ export abstract class CommandOperation< ); } } - -function resolveWriteConcern(parent: OperationParent | undefined, options: any) { - return WriteConcern.fromOptions(options) || parent?.writeConcern; -} - -function resolveReadConcern(parent: OperationParent | undefined, options: any) { - return ReadConcern.fromOptions(options) || parent?.readConcern; -} diff --git a/src/operations/create_collection.ts b/src/operations/create_collection.ts index 24d0aaa1184..4c5962dd5f9 100644 --- a/src/operations/create_collection.ts +++ b/src/operations/create_collection.ts @@ -16,13 +16,19 @@ const ILLEGAL_COMMAND_FIELDS = new Set([ 'j', 'fsync', 'autoIndexId', - 'serializeFunctions', 'pkFactory', 'raw', 'readPreference', 'session', 'readConcern', - 'writeConcern' + 'writeConcern', + 'raw', + 'fieldsAsRaw', + 'promoteLongs', + 'promoteValues', + 'promoteBuffers', + 'serializeFunctions', + 'ignoreUndefined' ]); /** @public */ diff --git a/src/operations/find.ts b/src/operations/find.ts index 9f0a39b3ad0..4e3ef22f173 100644 --- a/src/operations/find.ts +++ b/src/operations/find.ts @@ -1,5 +1,4 @@ import { Aspect, defineAspects, Hint } from './operation'; -import { ReadPreference } from '../read_preference'; import { maxWireVersion, MongoDBNamespace, Callback, normalizeHintField } from '../utils'; import { MongoError } from '../error'; import type { Document } from '../bson'; @@ -64,7 +63,6 @@ const SUPPORTS_WRITE_CONCERN_AND_COLLATION = 5; export class FindOperation extends CommandOperation { cmd: Document; filter: Document; - readPreference: ReadPreference; hint?: Hint; @@ -76,7 +74,6 @@ export class FindOperation extends CommandOperation { ) { super(collection, options); this.ns = ns; - this.readPreference = ReadPreference.resolve(collection, this.options); if (typeof filter !== 'object' || Array.isArray(filter)) { throw new MongoError('Query filter must be a plain object or ObjectId'); diff --git a/src/operations/map_reduce.ts b/src/operations/map_reduce.ts index c04f083876f..2534958d4aa 100644 --- a/src/operations/map_reduce.ts +++ b/src/operations/map_reduce.ts @@ -17,12 +17,20 @@ import type { ObjectId } from '../bson'; const exclusionList = [ 'readPreference', + 'readConcern', 'session', 'bypassDocumentValidation', 'w', 'wtimeout', 'j', 'writeConcern', + 'raw', + 'fieldsAsRaw', + 'promoteLongs', + 'promoteValues', + 'promoteBuffers', + 'serializeFunctions', + 'ignoreUndefined', 'scope' // this option is reformatted thus exclude the original ]; @@ -121,13 +129,9 @@ export class MapReduceOperation extends CommandOperation 0 && keys[0][0] === '$'; } + +/** + * Merge inherited properties from parent into options, prioritizing values from options, + * then values from parent. + * @internal + */ +export function resolveOptions( + parent: OperationParent | undefined, + options?: T +): T { + const result: T = Object.assign({}, options, resolveBSONOptions(options, parent)); + + // Users cannot pass a readConcern/writeConcern to operations in a transaction + const session = options?.session; + if (!session?.inTransaction()) { + const readConcern = ReadConcern.fromOptions(options) ?? parent?.readConcern; + if (readConcern) { + result.readConcern = readConcern; + } + + const writeConcern = WriteConcern.fromOptions(options) ?? parent?.writeConcern; + if (writeConcern) { + result.writeConcern = writeConcern; + } + } + + const readPreference = ReadPreference.fromOptions(options) ?? parent?.readPreference; + if (readPreference) { + result.readPreference = readPreference; + } + + return result; +}