command_v2.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. 'use strict';
  2. const Aspect = require('./operation').Aspect;
  3. const OperationBase = require('./operation').OperationBase;
  4. const resolveReadPreference = require('../utils').resolveReadPreference;
  5. const ReadConcern = require('../read_concern');
  6. const WriteConcern = require('../write_concern');
  7. const maxWireVersion = require('../core/utils').maxWireVersion;
  8. const commandSupportsReadConcern = require('../core/sessions').commandSupportsReadConcern;
  9. const MongoError = require('../error').MongoError;
  10. const SUPPORTS_WRITE_CONCERN_AND_COLLATION = 5;
  11. class CommandOperationV2 extends OperationBase {
  12. constructor(parent, options, operationOptions) {
  13. super(options);
  14. this.ns = parent.s.namespace.withCollection('$cmd');
  15. this.readPreference = resolveReadPreference(parent, this.options);
  16. this.readConcern = resolveReadConcern(parent, this.options);
  17. this.writeConcern = resolveWriteConcern(parent, this.options);
  18. this.explain = false;
  19. if (operationOptions && typeof operationOptions.fullResponse === 'boolean') {
  20. this.fullResponse = true;
  21. }
  22. // TODO: A lot of our code depends on having the read preference in the options. This should
  23. // go away, but also requires massive test rewrites.
  24. this.options.readPreference = this.readPreference;
  25. // TODO(NODE-2056): make logger another "inheritable" property
  26. if (parent.s.logger) {
  27. this.logger = parent.s.logger;
  28. } else if (parent.s.db && parent.s.db.logger) {
  29. this.logger = parent.s.db.logger;
  30. }
  31. }
  32. executeCommand(server, cmd, callback) {
  33. // TODO: consider making this a non-enumerable property
  34. this.server = server;
  35. const options = this.options;
  36. const serverWireVersion = maxWireVersion(server);
  37. const inTransaction = this.session && this.session.inTransaction();
  38. if (this.readConcern && commandSupportsReadConcern(cmd) && !inTransaction) {
  39. Object.assign(cmd, { readConcern: this.readConcern });
  40. }
  41. if (options.collation && serverWireVersion < SUPPORTS_WRITE_CONCERN_AND_COLLATION) {
  42. callback(
  43. new MongoError(
  44. `Server ${server.name}, which reports wire version ${serverWireVersion}, does not support collation`
  45. )
  46. );
  47. return;
  48. }
  49. if (serverWireVersion >= SUPPORTS_WRITE_CONCERN_AND_COLLATION) {
  50. if (this.writeConcern && this.hasAspect(Aspect.WRITE_OPERATION)) {
  51. Object.assign(cmd, { writeConcern: this.writeConcern });
  52. }
  53. if (options.collation && typeof options.collation === 'object') {
  54. Object.assign(cmd, { collation: options.collation });
  55. }
  56. }
  57. if (typeof options.maxTimeMS === 'number') {
  58. cmd.maxTimeMS = options.maxTimeMS;
  59. }
  60. if (typeof options.comment === 'string') {
  61. cmd.comment = options.comment;
  62. }
  63. if (this.logger && this.logger.isDebug()) {
  64. this.logger.debug(`executing command ${JSON.stringify(cmd)} against ${this.ns}`);
  65. }
  66. server.command(this.ns.toString(), cmd, this.options, (err, result) => {
  67. if (err) {
  68. callback(err, null);
  69. return;
  70. }
  71. if (this.fullResponse) {
  72. callback(null, result);
  73. return;
  74. }
  75. callback(null, result.result);
  76. });
  77. }
  78. }
  79. function resolveWriteConcern(parent, options) {
  80. return WriteConcern.fromOptions(options) || parent.writeConcern;
  81. }
  82. function resolveReadConcern(parent, options) {
  83. return ReadConcern.fromOptions(options) || parent.readConcern;
  84. }
  85. module.exports = CommandOperationV2;