Skip to content

refactor: unify means of applying ignoreUndefined #2589

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/bson.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { OperationParent } from './operations/command';
// import type * as _BSON from 'bson';
// let BSON: typeof _BSON = require('bson');
// try {
Expand Down Expand Up @@ -69,3 +70,25 @@ export function pluckBSONSerializeOptions(options: BSONSerializeOptions): BSONSe
raw
};
}

/**
* Merge the given BSONSerializeOptions, preferring options over the parent's options, and
* substituting defaults for values not set.
*
* @internal
*/
export function resolveBSONOptions(
options?: BSONSerializeOptions,
parent?: OperationParent
): BSONSerializeOptions {
const parentOptions = parent?.bsonOptions;
return {
raw: options?.raw ?? parentOptions?.raw ?? false,
promoteLongs: options?.promoteLongs ?? parentOptions?.promoteLongs ?? true,
promoteValues: options?.promoteValues ?? parentOptions?.promoteValues ?? true,
promoteBuffers: options?.promoteBuffers ?? parentOptions?.promoteBuffers ?? false,
ignoreUndefined: options?.ignoreUndefined ?? parentOptions?.ignoreUndefined ?? false,
serializeFunctions: options?.serializeFunctions ?? parentOptions?.serializeFunctions ?? false,
fieldsAsRaw: options?.fieldsAsRaw ?? parentOptions?.fieldsAsRaw ?? {}
};
}
89 changes: 10 additions & 79 deletions src/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
MongoDBNamespace,
Callback
} from './utils';
import { ObjectId, Document, BSONSerializeOptions } from './bson';
import { ObjectId, Document, BSONSerializeOptions, resolveBSONOptions } from './bson';
import { MongoError } from './error';
import { UnorderedBulkOperation } from './bulk/unordered';
import { OrderedBulkOperation } from './bulk/ordered';
Expand Down Expand Up @@ -126,13 +126,8 @@ export interface CollectionPrivate {
options: any;
namespace: MongoDBNamespace;
readPreference?: ReadPreference;
bsonOptions: BSONSerializeOptions;
slaveOk?: boolean;
serializeFunctions?: boolean;
raw?: boolean;
promoteLongs?: boolean;
promoteValues?: boolean;
promoteBuffers?: boolean;
ignoreUndefined?: boolean;
collectionHint?: Hint;
readConcern?: ReadConcern;
writeConcern?: WriteConcern;
Expand Down Expand Up @@ -188,30 +183,10 @@ export class Collection implements OperationParent {
}
},
readPreference: ReadPreference.fromOptions(options),
bsonOptions: resolveBSONOptions(options, db),
readConcern: ReadConcern.fromOptions(options),
writeConcern: WriteConcern.fromOptions(options),
slaveOk: options == null || options.slaveOk == null ? db.slaveOk : options.slaveOk,
serializeFunctions:
options == null || options.serializeFunctions == null
? db.s.options?.serializeFunctions
: options.serializeFunctions,
raw: options == null || options.raw == null ? db.s.options?.raw : options.raw,
promoteLongs:
options == null || options.promoteLongs == null
? db.s.options?.promoteLongs
: options.promoteLongs,
promoteValues:
options == null || options.promoteValues == null
? db.s.options?.promoteValues
: options.promoteValues,
promoteBuffers:
options == null || options.promoteBuffers == null
? db.s.options?.promoteBuffers
: options.promoteBuffers,
ignoreUndefined:
options == null || options.ignoreUndefined == null
? db.s.options?.ignoreUndefined
: options.ignoreUndefined
slaveOk: options == null || options.slaveOk == null ? db.slaveOk : options.slaveOk
};
}

Expand Down Expand Up @@ -260,6 +235,10 @@ export class Collection implements OperationParent {
return this.s.readPreference;
}

get bsonOptions(): BSONSerializeOptions {
return this.s.bsonOptions;
}

/**
* The current writeConcern of the collection. If not explicitly defined for
* this collection, will be inherited from the parent DB
Expand Down Expand Up @@ -301,12 +280,6 @@ export class Collection implements OperationParent {
if (typeof options === 'function') (callback = options), (options = {});
options = options || {};

// Add ignoreUndefined
if (this.s.options.ignoreUndefined) {
options = Object.assign({}, options);
options.ignoreUndefined = this.s.options.ignoreUndefined;
}

return executeOperation(this.s.topology, new InsertOneOperation(this, doc, options), callback);
}

Expand Down Expand Up @@ -428,12 +401,6 @@ export class Collection implements OperationParent {
if (typeof options === 'function') (callback = options), (options = {});
options = Object.assign({}, options);

// Add ignoreUndefined
if (this.s.options.ignoreUndefined) {
options = Object.assign({}, options);
options.ignoreUndefined = this.s.options.ignoreUndefined;
}

return executeOperation(
this.s.topology,
new UpdateOneOperation(this, filter, update, options),
Expand Down Expand Up @@ -471,12 +438,6 @@ export class Collection implements OperationParent {
if (typeof options === 'function') (callback = options), (options = {});
options = Object.assign({}, options);

// Add ignoreUndefined
if (this.s.options.ignoreUndefined) {
options = Object.assign({}, options);
options.ignoreUndefined = this.s.options.ignoreUndefined;
}

return executeOperation(
this.s.topology,
new ReplaceOneOperation(this, filter, replacement, options),
Expand Down Expand Up @@ -510,12 +471,6 @@ export class Collection implements OperationParent {
if (typeof options === 'function') (callback = options), (options = {});
options = Object.assign({}, options);

// Add ignoreUndefined
if (this.s.options.ignoreUndefined) {
options = Object.assign({}, options);
options.ignoreUndefined = this.s.options.ignoreUndefined;
}

return executeOperation(
this.s.topology,
new UpdateManyOperation(this, filter, update, options),
Expand All @@ -542,12 +497,6 @@ export class Collection implements OperationParent {
if (typeof options === 'function') (callback = options), (options = {});
options = Object.assign({}, options);

// Add ignoreUndefined
if (this.s.options.ignoreUndefined) {
options = Object.assign({}, options);
options.ignoreUndefined = this.s.options.ignoreUndefined;
}

return executeOperation(
this.s.topology,
new DeleteOneOperation(this, filter, options),
Expand Down Expand Up @@ -586,12 +535,6 @@ export class Collection implements OperationParent {

options = Object.assign({}, options);

// Add ignoreUndefined
if (this.s.options.ignoreUndefined) {
options = Object.assign({}, options);
options.ignoreUndefined = this.s.options.ignoreUndefined;
}

return executeOperation(
this.s.topology,
new DeleteManyOperation(this, filter, options),
Expand Down Expand Up @@ -1344,7 +1287,7 @@ export class Collection implements OperationParent {
options = options || {};
// Give function's options precedence over session options.
if (options.ignoreUndefined == null) {
options.ignoreUndefined = this.s.options.ignoreUndefined;
options.ignoreUndefined = this.bsonOptions.ignoreUndefined;
}

return new UnorderedBulkOperation(this, options);
Expand All @@ -1355,7 +1298,7 @@ export class Collection implements OperationParent {
options = options || {};
// Give function's options precedence over session's options.
if (options.ignoreUndefined == null) {
options.ignoreUndefined = this.s.options.ignoreUndefined;
options.ignoreUndefined = this.bsonOptions.ignoreUndefined;
}

return new OrderedBulkOperation(this, options);
Expand Down Expand Up @@ -1414,12 +1357,6 @@ export class Collection implements OperationParent {
if (typeof options === 'function') (callback = options), (options = {});
options = options || {};

// Add ignoreUndefined
if (this.s.options.ignoreUndefined) {
options = Object.assign({}, options);
options.ignoreUndefined = this.s.options.ignoreUndefined;
}

return this.updateMany(selector, update, options, callback);
}

Expand All @@ -1439,12 +1376,6 @@ export class Collection implements OperationParent {
if (typeof options === 'function') (callback = options), (options = {});
options = options || {};

// Add ignoreUndefined
if (this.s.options.ignoreUndefined) {
options = Object.assign({}, options);
options.ignoreUndefined = this.s.options.ignoreUndefined;
}

return this.deleteMany(selector, options, callback);
}

Expand Down
14 changes: 8 additions & 6 deletions src/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { deprecate } from 'util';
import { emitDeprecatedOptionWarning, Callback } from './utils';
import { loadAdmin } from './dynamic_loaders';
import { AggregationCursor, CommandCursor } from './cursor';
import { ObjectId, Code, Document, BSONSerializeOptions } from './bson';
import { ObjectId, Code, Document, BSONSerializeOptions, resolveBSONOptions } from './bson';
import { ReadPreference, ReadPreferenceLike } from './read_preference';
import { MongoError } from './error';
import { Collection, CollectionOptions } from './collection';
Expand Down Expand Up @@ -94,6 +94,7 @@ export interface DbPrivate {
readPreference?: ReadPreference;
pkFactory: PkFactory;
readConcern?: ReadConcern;
bsonOptions: BSONSerializeOptions;
writeConcern?: WriteConcern;
namespace: MongoDBNamespace;
}
Expand Down Expand Up @@ -171,6 +172,8 @@ export class Db implements OperationParent {
logger: new Logger('Db', options),
// Unpack read preference
readPreference: ReadPreference.fromOptions(options),
// Merge bson options TODO: include client bson options, after NODE-2850
bsonOptions: resolveBSONOptions(options),
// Set up the primary key factory or fallback to ObjectId
pkFactory: options?.pkFactory ?? {
createPk() {
Expand Down Expand Up @@ -218,6 +221,10 @@ export class Db implements OperationParent {
return this.s.readPreference;
}

get bsonOptions(): BSONSerializeOptions {
return this.s.bsonOptions;
}

// get the write Concern
get writeConcern(): WriteConcern | undefined {
return this.s.writeConcern;
Expand Down Expand Up @@ -340,11 +347,6 @@ export class Db implements OperationParent {
// If we have not set a collection level readConcern set the db level one
options.readConcern = ReadConcern.fromOptions(options) ?? this.readConcern;

// Do we have ignoreUndefined set
if (this.s.options?.ignoreUndefined) {
options.ignoreUndefined = this.s.options.ignoreUndefined;
}

// Merge in all needed options and ensure correct writeConcern merging from db level
const finalOptions = mergeOptionsAndWriteConcern(
options,
Expand Down
8 changes: 7 additions & 1 deletion src/mongo_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { connect, validOptions } from './operations/connect';
import { PromiseProvider } from './promise_provider';
import { Logger } from './logger';
import { ReadConcern, ReadConcernLevelLike, ReadConcernLike } from './read_concern';
import type { BSONSerializeOptions, Document } from './bson';
import { BSONSerializeOptions, Document, resolveBSONOptions } from './bson';
import type { AutoEncryptionOptions } from './deps';
import type { CompressorName } from './cmap/wire_protocol/compression';
import type { AuthMechanism } from './cmap/auth/defaultAuthProviders';
Expand Down Expand Up @@ -222,6 +222,7 @@ export interface MongoClientPrivate {
readConcern?: ReadConcern;
writeConcern?: WriteConcern;
readPreference: ReadPreference;
bsonOptions: BSONSerializeOptions;
namespace: MongoDBNamespace;
logger: Logger;
}
Expand Down Expand Up @@ -284,6 +285,7 @@ export class MongoClient extends EventEmitter implements OperationParent {
readConcern: ReadConcern.fromOptions(options),
writeConcern: WriteConcern.fromOptions(options),
readPreference: ReadPreference.fromOptions(options) || ReadPreference.primary,
bsonOptions: resolveBSONOptions(options),
namespace: new MongoDBNamespace('admin'),
logger: options?.logger ?? new Logger('MongoClient')
};
Expand All @@ -301,6 +303,10 @@ export class MongoClient extends EventEmitter implements OperationParent {
return this.s.readPreference;
}

get bsonOptions(): BSONSerializeOptions {
return this.s.bsonOptions;
}

get logger(): Logger {
return this.s.logger;
}
Expand Down
12 changes: 5 additions & 7 deletions src/operations/bulk_write.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { applyRetryableWrites, applyWriteConcern, Callback } from '../utils';
import { OperationBase } from './operation';
import { resolveBSONOptions } from '../bson';
import { WriteConcern } from '../write_concern';
import type { Collection } from '../collection';
import type {
Expand All @@ -24,18 +25,15 @@ export class BulkWriteOperation extends OperationBase<BulkWriteOptions, BulkWrit

this.collection = collection;
this.operations = operations;

// Assign BSON serialize options to OperationBase, preferring options over collection options
this.bsonOptions = resolveBSONOptions(options, collection);
}

execute(server: Server, callback: Callback<BulkWriteResult>): void {
const coll = this.collection;
const operations = this.operations;
let options = this.options;

// Add ignoreUndefined
if (coll.s.options.ignoreUndefined) {
options = Object.assign({}, options);
options.ignoreUndefined = coll.s.options.ignoreUndefined;
}
const options = { ...this.options, ...this.bsonOptions };

// Create the bulk operation
const bulk: BulkOperationBase =
Expand Down
8 changes: 6 additions & 2 deletions src/operations/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { commandSupportsReadConcern } from '../sessions';
import { MongoError } from '../error';
import type { Logger } from '../logger';
import type { Server } from '../sdam/server';
import type { Document } from '../bson';
import { BSONSerializeOptions, Document, resolveBSONOptions } from '../bson';
import type { CollationOptions } from '../cmap/wire_protocol/write_command';
import type { ReadConcernLike } from './../read_concern';

Expand Down Expand Up @@ -42,6 +42,7 @@ export interface OperationParent {
writeConcern?: WriteConcern;
readPreference?: ReadPreference;
logger?: Logger;
bsonOptions?: BSONSerializeOptions;
}

/** @internal */
Expand Down Expand Up @@ -90,6 +91,9 @@ 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<TResult>): void;
Expand All @@ -98,7 +102,7 @@ export abstract class CommandOperation<
// TODO: consider making this a non-enumerable property
this.server = server;

const options = this.options;
const options = { ...this.options, ...this.bsonOptions };
const serverWireVersion = maxWireVersion(server);
const inTransaction = this.session && this.session.inTransaction();

Expand Down
3 changes: 2 additions & 1 deletion src/operations/common_functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ export function updateDocuments(
// Do we return the actual result document
// Either use override on the function, or go back to default on either the collection
// level or db
finalOptions.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions;
finalOptions.serializeFunctions =
options.serializeFunctions || coll.bsonOptions.serializeFunctions;

// Execute the operation
const op: Document = { q: selector, u: document };
Expand Down
4 changes: 2 additions & 2 deletions src/operations/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class DeleteOneOperation extends CommandOperation<DeleteOptions, DeleteRe
execute(server: Server, callback: Callback<DeleteResult>): void {
const coll = this.collection;
const filter = this.filter;
const options = this.options;
const options = { ...this.options, ...this.bsonOptions };

options.single = true;
removeDocuments(server, coll, filter, options, (err, r) => {
Expand Down Expand Up @@ -99,7 +99,7 @@ export class DeleteManyOperation extends CommandOperation<DeleteOptions, DeleteR
execute(server: Server, callback: Callback<DeleteResult>): void {
const coll = this.collection;
const filter = this.filter;
const options = this.options;
const options = { ...this.options, ...this.bsonOptions };

// a user can pass `single: true` in to `deleteMany` to remove a single document, theoretically
if (typeof options.single !== 'boolean') {
Expand Down
Loading