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.
126 lines
4.2 KiB
126 lines
4.2 KiB
2 months ago
|
'use strict';
|
||
|
|
||
|
const Aspect = require('./operation').Aspect;
|
||
|
const OperationBase = require('./operation').OperationBase;
|
||
|
const ReadPreference = require('../core').ReadPreference;
|
||
|
const ReadConcern = require('../read_concern');
|
||
|
const WriteConcern = require('../write_concern');
|
||
|
const maxWireVersion = require('../core/utils').maxWireVersion;
|
||
|
const decorateWithExplain = require('../utils').decorateWithExplain;
|
||
|
const commandSupportsReadConcern = require('../core/sessions').commandSupportsReadConcern;
|
||
|
const MongoError = require('../core/error').MongoError;
|
||
|
const extractCommand = require('../command_utils').extractCommand;
|
||
|
|
||
|
const SUPPORTS_WRITE_CONCERN_AND_COLLATION = 5;
|
||
|
|
||
|
class CommandOperationV2 extends OperationBase {
|
||
|
constructor(parent, options, operationOptions) {
|
||
|
super(options);
|
||
|
|
||
|
this.ns = parent.s.namespace.withCollection('$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);
|
||
|
|
||
|
if (operationOptions && typeof operationOptions.fullResponse === 'boolean') {
|
||
|
this.fullResponse = true;
|
||
|
}
|
||
|
|
||
|
// TODO: A lot of our code depends on having the read preference in the options. This should
|
||
|
// go away, but also requires massive test rewrites.
|
||
|
this.options.readPreference = this.readPreference;
|
||
|
|
||
|
// TODO(NODE-2056): make logger another "inheritable" property
|
||
|
if (parent.s.logger) {
|
||
|
this.logger = parent.s.logger;
|
||
|
} else if (parent.s.db && parent.s.db.logger) {
|
||
|
this.logger = parent.s.db.logger;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
executeCommand(server, cmd, callback) {
|
||
|
// TODO: consider making this a non-enumerable property
|
||
|
this.server = server;
|
||
|
|
||
|
const options = this.options;
|
||
|
const serverWireVersion = maxWireVersion(server);
|
||
|
const inTransaction = this.session && this.session.inTransaction();
|
||
|
|
||
|
if (this.readConcern && commandSupportsReadConcern(cmd) && !inTransaction) {
|
||
|
Object.assign(cmd, { readConcern: this.readConcern });
|
||
|
}
|
||
|
|
||
|
if (options.collation && serverWireVersion < SUPPORTS_WRITE_CONCERN_AND_COLLATION) {
|
||
|
callback(
|
||
|
new MongoError(
|
||
|
`Server ${server.name}, which reports wire version ${serverWireVersion}, does not support collation`
|
||
|
)
|
||
|
);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (serverWireVersion >= SUPPORTS_WRITE_CONCERN_AND_COLLATION) {
|
||
|
if (this.writeConcern && this.hasAspect(Aspect.WRITE_OPERATION)) {
|
||
|
Object.assign(cmd, { writeConcern: this.writeConcern });
|
||
|
}
|
||
|
|
||
|
if (options.collation && typeof options.collation === 'object') {
|
||
|
Object.assign(cmd, { collation: options.collation });
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (typeof options.maxTimeMS === 'number') {
|
||
|
cmd.maxTimeMS = options.maxTimeMS;
|
||
|
}
|
||
|
|
||
|
if (typeof options.comment === 'string') {
|
||
|
cmd.comment = options.comment;
|
||
|
}
|
||
|
|
||
|
if (this.hasAspect(Aspect.EXPLAINABLE) && this.explain) {
|
||
|
if (serverWireVersion < 6 && cmd.aggregate) {
|
||
|
// Prior to 3.6, with aggregate, verbosity is ignored, and we must pass in "explain: true"
|
||
|
cmd.explain = true;
|
||
|
} else {
|
||
|
cmd = decorateWithExplain(cmd, this.explain);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (this.logger && this.logger.isDebug()) {
|
||
|
const extractedCommand = extractCommand(cmd);
|
||
|
this.logger.debug(
|
||
|
`executing command ${JSON.stringify(
|
||
|
extractedCommand.shouldRedact ? `${extractedCommand.name} details REDACTED` : cmd
|
||
|
)} against ${this.ns}`
|
||
|
);
|
||
|
}
|
||
|
|
||
|
server.command(this.ns.toString(), cmd, this.options, (err, result) => {
|
||
|
if (err) {
|
||
|
callback(err, null);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (this.fullResponse) {
|
||
|
callback(null, result);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
callback(null, result.result);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function resolveWriteConcern(parent, options) {
|
||
|
return WriteConcern.fromOptions(options) || (parent && parent.writeConcern);
|
||
|
}
|
||
|
|
||
|
function resolveReadConcern(parent, options) {
|
||
|
return ReadConcern.fromOptions(options) || (parent && parent.readConcern);
|
||
|
}
|
||
|
|
||
|
module.exports = CommandOperationV2;
|