mongodb 3.5.9 → 3.5.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/HISTORY.md CHANGED
@@ -1,7 +1,18 @@
1
- # Change Log
1
+ # Changelog
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [3.5.10](https://github.com/mongodb/node-mongodb-native/compare/v3.5.9...v3.5.10) (2020-07-30)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * db.command to not inherit options from parent ([f7a50e2](https://github.com/mongodb/node-mongodb-native/commit/f7a50e2f43375cc411d6f521e3b103c96ceca51a))
11
+ * ipv6 is not supported when using dns service discovery ([a1be593](https://github.com/mongodb/node-mongodb-native/commit/a1be59315c3dc65a04d3f83bb75fff2f1b9c16ef))
12
+ * ReadPreference maxStalenessSeconds from options ([72a743d](https://github.com/mongodb/node-mongodb-native/commit/72a743d536181867f770a88ea9cd68d30b3f97fd))
13
+ * silently ignore session with unacknowledged write ([8f1ea7b](https://github.com/mongodb/node-mongodb-native/commit/8f1ea7b69678c243a729267109ac3e50387914f8))
14
+ * **ChangeStream:** handle null changes ([306b5b3](https://github.com/mongodb/node-mongodb-native/commit/306b5b3f7103f91c6c07c08f95375876093ad897))
15
+
5
16
  <a name="3.5.9"></a>
6
17
  ## [3.5.9](https://github.com/mongodb/node-mongodb-native/compare/v3.5.8...v3.5.9) (2020-06-12)
7
18
 
@@ -326,8 +326,8 @@ class ChangeStreamCursor extends Cursor {
326
326
 
327
327
  _initializeCursor(callback) {
328
328
  super._initializeCursor((err, result) => {
329
- if (err) {
330
- callback(err);
329
+ if (err || result == null) {
330
+ callback(err, result);
331
331
  return;
332
332
  }
333
333
 
@@ -483,6 +483,11 @@ function waitForTopologyConnected(topology, options, callback) {
483
483
  function processNewChange(changeStream, change, callback) {
484
484
  const cursor = changeStream.cursor;
485
485
 
486
+ // a null change means the cursor has been notified, implicitly closing the change stream
487
+ if (change == null) {
488
+ changeStream.closed = true;
489
+ }
490
+
486
491
  if (changeStream.closed) {
487
492
  if (callback) callback(new MongoError('ChangeStream is closed'));
488
493
  return;
package/lib/collection.js CHANGED
@@ -16,7 +16,6 @@ const unordered = require('./bulk/unordered');
16
16
  const ordered = require('./bulk/ordered');
17
17
  const ChangeStream = require('./change_stream');
18
18
  const executeLegacyOperation = require('./utils').executeLegacyOperation;
19
- const resolveReadPreference = require('./utils').resolveReadPreference;
20
19
  const WriteConcern = require('./write_concern');
21
20
  const ReadConcern = require('./read_concern');
22
21
  const MongoDBNamespace = require('./utils').MongoDBNamespace;
@@ -399,7 +398,7 @@ Collection.prototype.find = deprecateOptions(
399
398
  newOptions.slaveOk = options.slaveOk != null ? options.slaveOk : this.s.db.slaveOk;
400
399
 
401
400
  // Add read preference if needed
402
- newOptions.readPreference = resolveReadPreference(this, newOptions);
401
+ newOptions.readPreference = ReadPreference.resolve(this, newOptions);
403
402
 
404
403
  // Set slave ok to true if read preference different from primary
405
404
  if (
@@ -1978,7 +1977,7 @@ Collection.prototype.parallelCollectionScan = deprecate(function(options, callba
1978
1977
 
1979
1978
  options = Object.assign({}, options);
1980
1979
  // Ensure we have the right read preference inheritance
1981
- options.readPreference = resolveReadPreference(this, options);
1980
+ options.readPreference = ReadPreference.resolve(this, options);
1982
1981
 
1983
1982
  // Add a promiseLibrary
1984
1983
  options.promiseLibrary = this.s.promiseLibrary;
@@ -464,50 +464,41 @@ class CoreCursor extends Readable {
464
464
  }
465
465
 
466
466
  const result = r.message;
467
- if (result.queryFailure) {
468
- return done(new MongoError(result.documents[0]), null);
469
- }
470
467
 
471
- // Check if we have a command cursor
472
- if (
473
- Array.isArray(result.documents) &&
474
- result.documents.length === 1 &&
475
- (!cursor.cmd.find || (cursor.cmd.find && cursor.cmd.virtual === false)) &&
476
- (typeof result.documents[0].cursor !== 'string' ||
477
- result.documents[0]['$err'] ||
478
- result.documents[0]['errmsg'] ||
479
- Array.isArray(result.documents[0].result))
480
- ) {
481
- // We have an error document, return the error
482
- if (result.documents[0]['$err'] || result.documents[0]['errmsg']) {
483
- return done(new MongoError(result.documents[0]), null);
468
+ if (Array.isArray(result.documents) && result.documents.length === 1) {
469
+ const document = result.documents[0];
470
+
471
+ if (result.queryFailure) {
472
+ return done(new MongoError(document), null);
484
473
  }
485
474
 
486
- // We have a cursor document
487
- if (result.documents[0].cursor != null && typeof result.documents[0].cursor !== 'string') {
488
- const id = result.documents[0].cursor.id;
489
- // If we have a namespace change set the new namespace for getmores
490
- if (result.documents[0].cursor.ns) {
491
- cursor.ns = result.documents[0].cursor.ns;
475
+ // Check if we have a command cursor
476
+ if (!cursor.cmd.find || (cursor.cmd.find && cursor.cmd.virtual === false)) {
477
+ // We have an error document, return the error
478
+ if (document.$err || document.errmsg) {
479
+ return done(new MongoError(document), null);
492
480
  }
493
- // Promote id to long if needed
494
- cursor.cursorState.cursorId = typeof id === 'number' ? Long.fromNumber(id) : id;
495
- cursor.cursorState.lastCursorId = cursor.cursorState.cursorId;
496
- cursor.cursorState.operationTime = result.documents[0].operationTime;
497
-
498
- // If we have a firstBatch set it
499
- if (Array.isArray(result.documents[0].cursor.firstBatch)) {
500
- cursor.cursorState.documents = result.documents[0].cursor.firstBatch; //.reverse();
501
- }
502
-
503
- // Return after processing command cursor
504
- return done(null, result);
505
- }
506
481
 
507
- if (Array.isArray(result.documents[0].result)) {
508
- cursor.cursorState.documents = result.documents[0].result;
509
- cursor.cursorState.cursorId = Long.ZERO;
510
- return done(null, result);
482
+ // We have a cursor document
483
+ if (document.cursor != null && typeof document.cursor !== 'string') {
484
+ const id = document.cursor.id;
485
+ // If we have a namespace change set the new namespace for getmores
486
+ if (document.cursor.ns) {
487
+ cursor.ns = document.cursor.ns;
488
+ }
489
+ // Promote id to long if needed
490
+ cursor.cursorState.cursorId = typeof id === 'number' ? Long.fromNumber(id) : id;
491
+ cursor.cursorState.lastCursorId = cursor.cursorState.cursorId;
492
+ cursor.cursorState.operationTime = document.operationTime;
493
+
494
+ // If we have a firstBatch set it
495
+ if (Array.isArray(document.cursor.firstBatch)) {
496
+ cursor.cursorState.documents = document.cursor.firstBatch; //.reverse();
497
+ }
498
+
499
+ // Return after processing command cursor
500
+ return done(null, result);
501
+ }
511
502
  }
512
503
  }
513
504
 
@@ -66,13 +66,12 @@ class Monitor extends EventEmitter {
66
66
  });
67
67
 
68
68
  // TODO: refactor this to pull it directly from the pool, requires new ConnectionPool integration
69
- const addressParts = server.description.address.split(':');
70
69
  this.connectOptions = Object.freeze(
71
70
  Object.assign(
72
71
  {
73
72
  id: '<monitor>',
74
- host: addressParts[0],
75
- port: parseInt(addressParts[1], 10),
73
+ host: server.description.host,
74
+ port: server.description.port,
76
75
  bson: server.s.bson,
77
76
  connectionType: Connection
78
77
  },
@@ -110,9 +110,8 @@ class Server extends EventEmitter {
110
110
 
111
111
  // create the connection pool
112
112
  // NOTE: this used to happen in `connect`, we supported overriding pool options there
113
- const addressParts = this.description.address.split(':');
114
113
  const poolOptions = Object.assign(
115
- { host: addressParts[0], port: parseInt(addressParts[1], 10), bson: this.s.bson },
114
+ { host: this.description.host, port: this.description.port, bson: this.s.bson },
116
115
  options
117
116
  );
118
117
 
@@ -113,6 +113,16 @@ class ServerDescription {
113
113
  return WRITABLE_SERVER_TYPES.has(this.type);
114
114
  }
115
115
 
116
+ get host() {
117
+ const chopLength = `:${this.port}`.length;
118
+ return this.address.slice(0, -chopLength);
119
+ }
120
+
121
+ get port() {
122
+ const port = this.address.split(':').pop();
123
+ return port ? Number.parseInt(port, 10) : port;
124
+ }
125
+
116
126
  /**
117
127
  * Determines if another `ServerDescription` is equal to this one per the rules defined
118
128
  * in the {@link https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#serverdescription|SDAM spec}
@@ -275,7 +275,7 @@ class Topology extends EventEmitter {
275
275
  // connect all known servers, then attempt server selection to connect
276
276
  connectServers(this, Array.from(this.s.description.servers.values()));
277
277
 
278
- translateReadPreference(options);
278
+ ReadPreference.translate(options);
279
279
  const readPreference = options.readPreference || ReadPreference.primary;
280
280
  this.selectServer(readPreferenceServerSelector(readPreference), options, err => {
281
281
  if (err) {
@@ -381,7 +381,7 @@ class Topology extends EventEmitter {
381
381
  } else if (typeof selector === 'string') {
382
382
  readPreference = new ReadPreference(selector);
383
383
  } else {
384
- translateReadPreference(options);
384
+ ReadPreference.translate(options);
385
385
  readPreference = options.readPreference || ReadPreference.primary;
386
386
  }
387
387
 
@@ -647,7 +647,7 @@ class Topology extends EventEmitter {
647
647
  (callback = options), (options = {}), (options = options || {});
648
648
  }
649
649
 
650
- translateReadPreference(options);
650
+ ReadPreference.translate(options);
651
651
  const readPreference = options.readPreference || ReadPreference.primary;
652
652
 
653
653
  this.selectServer(readPreferenceServerSelector(readPreference), options, (err, server) => {
@@ -708,7 +708,7 @@ class Topology extends EventEmitter {
708
708
  options = options || {};
709
709
  const topology = options.topology || this;
710
710
  const CursorClass = options.cursorFactory || this.s.Cursor;
711
- translateReadPreference(options);
711
+ ReadPreference.translate(options);
712
712
 
713
713
  return new CursorClass(topology, ns, cmd, options);
714
714
  }
@@ -939,28 +939,6 @@ function executeWriteOperation(args, options, callback) {
939
939
  });
940
940
  }
941
941
 
942
- function translateReadPreference(options) {
943
- if (options.readPreference == null) {
944
- return;
945
- }
946
-
947
- let r = options.readPreference;
948
- if (typeof r === 'string') {
949
- options.readPreference = new ReadPreference(r);
950
- } else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
951
- const mode = r.mode || r.preference;
952
- if (mode && typeof mode === 'string') {
953
- options.readPreference = new ReadPreference(mode, r.tags, {
954
- maxStalenessSeconds: r.maxStalenessSeconds
955
- });
956
- }
957
- } else if (!(r instanceof ReadPreference)) {
958
- throw new TypeError('Invalid read preference: ' + r);
959
- }
960
-
961
- return options;
962
- }
963
-
964
942
  function srvPollingHandler(topology) {
965
943
  return function handleSrvPolling(ev) {
966
944
  const previousTopologyDescription = topology.s.description;
@@ -708,6 +708,11 @@ function applySession(session, command, options) {
708
708
  return new MongoError('Cannot use a session that has ended');
709
709
  }
710
710
 
711
+ // SPEC-1019: silently ignore explicit session with unacknowledged write for backwards compatibility
712
+ if (options && options.writeConcern && options.writeConcern.w === 0) {
713
+ return;
714
+ }
715
+
711
716
  const serverSession = session.serverSession;
712
717
  serverSession.lastUse = now();
713
718
  command.lsid = serverSession.id;
@@ -91,20 +91,18 @@ const VALID_MODES = [
91
91
  * @return {ReadPreference}
92
92
  */
93
93
  ReadPreference.fromOptions = function(options) {
94
+ if (!options) return null;
94
95
  const readPreference = options.readPreference;
96
+ if (readPreference == null) return null;
95
97
  const readPreferenceTags = options.readPreferenceTags;
96
-
97
- if (readPreference == null) {
98
- return null;
99
- }
100
-
98
+ const maxStalenessSeconds = options.maxStalenessSeconds;
101
99
  if (typeof readPreference === 'string') {
102
100
  return new ReadPreference(readPreference, readPreferenceTags);
103
101
  } else if (!(readPreference instanceof ReadPreference) && typeof readPreference === 'object') {
104
102
  const mode = readPreference.mode || readPreference.preference;
105
103
  if (mode && typeof mode === 'string') {
106
104
  return new ReadPreference(mode, readPreference.tags, {
107
- maxStalenessSeconds: readPreference.maxStalenessSeconds
105
+ maxStalenessSeconds: readPreference.maxStalenessSeconds || maxStalenessSeconds
108
106
  });
109
107
  }
110
108
  }
@@ -112,6 +110,60 @@ ReadPreference.fromOptions = function(options) {
112
110
  return readPreference;
113
111
  };
114
112
 
113
+ /**
114
+ * Resolves a read preference based on well-defined inheritance rules. This method will not only
115
+ * determine the read preference (if there is one), but will also ensure the returned value is a
116
+ * properly constructed instance of `ReadPreference`.
117
+ *
118
+ * @param {Collection|Db|MongoClient} parent The parent of the operation on which to determine the read
119
+ * preference, used for determining the inherited read preference.
120
+ * @param {object} options The options passed into the method, potentially containing a read preference
121
+ * @returns {(ReadPreference|null)} The resolved read preference
122
+ */
123
+ ReadPreference.resolve = function(parent, options) {
124
+ options = options || {};
125
+ const session = options.session;
126
+
127
+ const inheritedReadPreference = parent && parent.readPreference;
128
+
129
+ let readPreference;
130
+ if (options.readPreference) {
131
+ readPreference = ReadPreference.fromOptions(options);
132
+ } else if (session && session.inTransaction() && session.transaction.options.readPreference) {
133
+ // The transaction’s read preference MUST override all other user configurable read preferences.
134
+ readPreference = session.transaction.options.readPreference;
135
+ } else if (inheritedReadPreference != null) {
136
+ readPreference = inheritedReadPreference;
137
+ } else {
138
+ readPreference = ReadPreference.primary;
139
+ }
140
+
141
+ return typeof readPreference === 'string' ? new ReadPreference(readPreference) : readPreference;
142
+ };
143
+
144
+ /**
145
+ * Replaces options.readPreference with a ReadPreference instance
146
+ */
147
+ ReadPreference.translate = function(options) {
148
+ if (options.readPreference == null) return options;
149
+ const r = options.readPreference;
150
+
151
+ if (typeof r === 'string') {
152
+ options.readPreference = new ReadPreference(r);
153
+ } else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
154
+ const mode = r.mode || r.preference;
155
+ if (mode && typeof mode === 'string') {
156
+ options.readPreference = new ReadPreference(mode, r.tags, {
157
+ maxStalenessSeconds: r.maxStalenessSeconds
158
+ });
159
+ }
160
+ } else if (!(r instanceof ReadPreference)) {
161
+ throw new TypeError('Invalid read preference: ' + r);
162
+ }
163
+
164
+ return options;
165
+ };
166
+
115
167
  /**
116
168
  * Validate if a mode is legal
117
169
  *
@@ -66,12 +66,7 @@ function _command(server, ns, cmd, options, callback) {
66
66
  finalCmd.$clusterTime = clusterTime;
67
67
  }
68
68
 
69
- if (
70
- isSharded(server) &&
71
- !shouldUseOpMsg &&
72
- readPreference &&
73
- readPreference.preference !== 'primary'
74
- ) {
69
+ if (isSharded(server) && !shouldUseOpMsg && readPreference && readPreference.mode !== 'primary') {
75
70
  finalCmd = {
76
71
  $query: finalCmd,
77
72
  $readPreference: readPreference.toJSON()
package/lib/db.js CHANGED
@@ -14,7 +14,6 @@ const Logger = require('./core').Logger;
14
14
  const Collection = require('./collection');
15
15
  const mergeOptionsAndWriteConcern = require('./utils').mergeOptionsAndWriteConcern;
16
16
  const executeLegacyOperation = require('./utils').executeLegacyOperation;
17
- const resolveReadPreference = require('./utils').resolveReadPreference;
18
17
  const ChangeStream = require('./change_stream');
19
18
  const deprecate = require('util').deprecate;
20
19
  const deprecateOptions = require('./utils').deprecateOptions;
@@ -35,6 +34,7 @@ const AggregateOperation = require('./operations/aggregate');
35
34
  const AddUserOperation = require('./operations/add_user');
36
35
  const CollectionsOperation = require('./operations/collections');
37
36
  const CommandOperation = require('./operations/command');
37
+ const RunCommandOperation = require('./operations/run_command');
38
38
  const CreateCollectionOperation = require('./operations/create_collection');
39
39
  const CreateIndexOperation = require('./operations/create_index');
40
40
  const DropCollectionOperation = require('./operations/drop').DropCollectionOperation;
@@ -290,7 +290,7 @@ Db.prototype.command = function(command, options, callback) {
290
290
  if (typeof options === 'function') (callback = options), (options = {});
291
291
  options = Object.assign({}, options);
292
292
 
293
- const commandOperation = new CommandOperation(this, options, null, command);
293
+ const commandOperation = new RunCommandOperation(this, command, options);
294
294
 
295
295
  return executeOperation(this.s.topology, commandOperation, callback);
296
296
  };
@@ -709,7 +709,7 @@ Db.prototype.collections = function(options, callback) {
709
709
  Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
710
710
  if (typeof options === 'function') (callback = options), (options = {});
711
711
  options = options || {};
712
- options.readPreference = resolveReadPreference(this, options);
712
+ options.readPreference = ReadPreference.resolve(this, options);
713
713
 
714
714
  const executeDbAdminCommandOperation = new ExecuteDbAdminCommandOperation(
715
715
  this,
@@ -8,7 +8,6 @@ const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
8
8
  const ensureIndexDb = require('./db_ops').ensureIndex;
9
9
  const evaluate = require('./db_ops').evaluate;
10
10
  const executeCommand = require('./db_ops').executeCommand;
11
- const resolveReadPreference = require('../utils').resolveReadPreference;
12
11
  const handleCallback = require('../utils').handleCallback;
13
12
  const indexInformationDb = require('./db_ops').indexInformation;
14
13
  const Long = require('../core').BSON.Long;
@@ -188,7 +187,7 @@ function group(coll, keys, condition, initial, reduce, finalize, command, option
188
187
 
189
188
  options = Object.assign({}, options);
190
189
  // Ensure we have the right read preference inheritance
191
- options.readPreference = resolveReadPreference(coll, options);
190
+ options.readPreference = ReadPreference.resolve(coll, options);
192
191
 
193
192
  // Do we have a readConcern specified
194
193
  decorateWithReadConcern(selector, coll, options);
@@ -7,7 +7,6 @@ const debugOptions = require('../utils').debugOptions;
7
7
  const handleCallback = require('../utils').handleCallback;
8
8
  const MongoError = require('../core').MongoError;
9
9
  const ReadPreference = require('../core').ReadPreference;
10
- const resolveReadPreference = require('../utils').resolveReadPreference;
11
10
  const MongoDBNamespace = require('../utils').MongoDBNamespace;
12
11
 
13
12
  const debugFields = [
@@ -38,9 +37,9 @@ class CommandOperation extends OperationBase {
38
37
 
39
38
  if (!this.hasAspect(Aspect.WRITE_OPERATION)) {
40
39
  if (collection != null) {
41
- this.options.readPreference = resolveReadPreference(collection, options);
40
+ this.options.readPreference = ReadPreference.resolve(collection, options);
42
41
  } else {
43
- this.options.readPreference = resolveReadPreference(db, options);
42
+ this.options.readPreference = ReadPreference.resolve(db, options);
44
43
  }
45
44
  } else {
46
45
  if (collection != null) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  const Aspect = require('./operation').Aspect;
4
4
  const OperationBase = require('./operation').OperationBase;
5
- const resolveReadPreference = require('../utils').resolveReadPreference;
5
+ const ReadPreference = require('../core').ReadPreference;
6
6
  const ReadConcern = require('../read_concern');
7
7
  const WriteConcern = require('../write_concern');
8
8
  const maxWireVersion = require('../core/utils').maxWireVersion;
@@ -16,9 +16,10 @@ class CommandOperationV2 extends OperationBase {
16
16
  super(options);
17
17
 
18
18
  this.ns = parent.s.namespace.withCollection('$cmd');
19
- this.readPreference = resolveReadPreference(parent, this.options);
20
- this.readConcern = resolveReadConcern(parent, this.options);
21
- this.writeConcern = resolveWriteConcern(parent, this.options);
19
+ const propertyProvider = this.hasAspect(Aspect.NO_INHERIT_OPTIONS) ? undefined : parent;
20
+ this.readPreference = ReadPreference.resolve(propertyProvider, this.options);
21
+ this.readConcern = resolveReadConcern(propertyProvider, this.options);
22
+ this.writeConcern = resolveWriteConcern(propertyProvider, this.options);
22
23
  this.explain = false;
23
24
 
24
25
  if (operationOptions && typeof operationOptions.fullResponse === 'boolean') {
@@ -97,11 +98,11 @@ class CommandOperationV2 extends OperationBase {
97
98
  }
98
99
 
99
100
  function resolveWriteConcern(parent, options) {
100
- return WriteConcern.fromOptions(options) || parent.writeConcern;
101
+ return WriteConcern.fromOptions(options) || (parent && parent.writeConcern);
101
102
  }
102
103
 
103
104
  function resolveReadConcern(parent, options) {
104
- return ReadConcern.fromOptions(options) || parent.readConcern;
105
+ return ReadConcern.fromOptions(options) || (parent && parent.readConcern);
105
106
  }
106
107
 
107
108
  module.exports = CommandOperationV2;
@@ -2,7 +2,6 @@
2
2
 
3
3
  const applyWriteConcern = require('../utils').applyWriteConcern;
4
4
  const Code = require('../core').BSON.Code;
5
- const resolveReadPreference = require('../utils').resolveReadPreference;
6
5
  const debugOptions = require('../utils').debugOptions;
7
6
  const handleCallback = require('../utils').handleCallback;
8
7
  const MongoError = require('../core').MongoError;
@@ -225,7 +224,7 @@ function executeCommand(db, command, options, callback) {
225
224
  const dbName = options.dbName || options.authdb || db.databaseName;
226
225
 
227
226
  // Convert the readPreference if its not a write
228
- options.readPreference = resolveReadPreference(db, options);
227
+ options.readPreference = ReadPreference.resolve(db, options);
229
228
 
230
229
  // Debug information
231
230
  if (db.s.logger.isDebug())
@@ -3,7 +3,7 @@
3
3
  const OperationBase = require('./operation').OperationBase;
4
4
  const Aspect = require('./operation').Aspect;
5
5
  const defineAspects = require('./operation').defineAspects;
6
- const resolveReadPreference = require('../utils').resolveReadPreference;
6
+ const ReadPreference = require('../core').ReadPreference;
7
7
 
8
8
  class FindOperation extends OperationBase {
9
9
  constructor(collection, ns, command, options) {
@@ -11,7 +11,7 @@ class FindOperation extends OperationBase {
11
11
 
12
12
  this.ns = ns;
13
13
  this.cmd = command;
14
- this.readPreference = resolveReadPreference(collection, this.options);
14
+ this.readPreference = ReadPreference.resolve(collection, this.options);
15
15
  }
16
16
 
17
17
  execute(server, callback) {
@@ -7,7 +7,7 @@ const decorateCommand = require('../utils').decorateCommand;
7
7
  const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
8
8
  const executeCommand = require('./db_ops').executeCommand;
9
9
  const handleCallback = require('../utils').handleCallback;
10
- const resolveReadPreference = require('../utils').resolveReadPreference;
10
+ const ReadPreference = require('../core').ReadPreference;
11
11
  const toError = require('../utils').toError;
12
12
 
13
13
  /**
@@ -58,7 +58,7 @@ class GeoHaystackSearchOperation extends OperationBase {
58
58
 
59
59
  options = Object.assign({}, options);
60
60
  // Ensure we have the right read preference inheritance
61
- options.readPreference = resolveReadPreference(coll, options);
61
+ options.readPreference = ReadPreference.resolve(coll, options);
62
62
 
63
63
  // Do we have a readConcern specified
64
64
  decorateWithReadConcern(commandObject, coll, options);
@@ -9,7 +9,7 @@ const handleCallback = require('../utils').handleCallback;
9
9
  const isObject = require('../utils').isObject;
10
10
  const loadDb = require('../dynamic_loaders').loadDb;
11
11
  const OperationBase = require('./operation').OperationBase;
12
- const resolveReadPreference = require('../utils').resolveReadPreference;
12
+ const ReadPreference = require('../core').ReadPreference;
13
13
  const toError = require('../utils').toError;
14
14
 
15
15
  const exclusionList = [
@@ -80,7 +80,7 @@ class MapReduceOperation extends OperationBase {
80
80
  options = Object.assign({}, options);
81
81
 
82
82
  // Ensure we have the right read preference inheritance
83
- options.readPreference = resolveReadPreference(coll, options);
83
+ options.readPreference = ReadPreference.resolve(coll, options);
84
84
 
85
85
  // If we have a read preference and inline is not set as output fail hard
86
86
  if (
@@ -4,7 +4,8 @@ const Aspect = {
4
4
  READ_OPERATION: Symbol('READ_OPERATION'),
5
5
  WRITE_OPERATION: Symbol('WRITE_OPERATION'),
6
6
  RETRYABLE: Symbol('RETRYABLE'),
7
- EXECUTE_WITH_SELECTION: Symbol('EXECUTE_WITH_SELECTION')
7
+ EXECUTE_WITH_SELECTION: Symbol('EXECUTE_WITH_SELECTION'),
8
+ NO_INHERIT_OPTIONS: Symbol('NO_INHERIT_OPTIONS')
8
9
  };
9
10
 
10
11
  /**
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ const CommandOperationV2 = require('./command_v2');
4
+ const defineAspects = require('./operation').defineAspects;
5
+ const Aspect = require('./operation').Aspect;
6
+
7
+ class RunCommandOperation extends CommandOperationV2 {
8
+ constructor(parent, command, options) {
9
+ super(parent, options);
10
+ this.command = command;
11
+ }
12
+ execute(server, callback) {
13
+ const command = this.command;
14
+ this.executeCommand(server, command, callback);
15
+ }
16
+ }
17
+ defineAspects(RunCommandOperation, [Aspect.EXECUTE_WITH_SELECTION, Aspect.NO_INHERIT_OPTIONS]);
18
+
19
+ module.exports = RunCommandOperation;
@@ -3,7 +3,7 @@
3
3
  const EventEmitter = require('events'),
4
4
  MongoError = require('../core').MongoError,
5
5
  f = require('util').format,
6
- translateReadPreference = require('../utils').translateReadPreference,
6
+ ReadPreference = require('../core').ReadPreference,
7
7
  ClientSession = require('../core').Sessions.ClientSession;
8
8
 
9
9
  // The store of ops
@@ -293,7 +293,7 @@ class TopologyBase extends EventEmitter {
293
293
 
294
294
  // Command
295
295
  command(ns, cmd, options, callback) {
296
- this.s.coreTopology.command(ns.toString(), cmd, translateReadPreference(options), callback);
296
+ this.s.coreTopology.command(ns.toString(), cmd, ReadPreference.translate(options), callback);
297
297
  }
298
298
 
299
299
  // Insert
@@ -314,7 +314,7 @@ class TopologyBase extends EventEmitter {
314
314
  // IsConnected
315
315
  isConnected(options) {
316
316
  options = options || {};
317
- options = translateReadPreference(options);
317
+ options = ReadPreference.translate(options);
318
318
 
319
319
  return this.s.coreTopology.isConnected(options);
320
320
  }
@@ -327,7 +327,7 @@ class TopologyBase extends EventEmitter {
327
327
  // Cursor
328
328
  cursor(ns, cmd, options) {
329
329
  options = options || {};
330
- options = translateReadPreference(options);
330
+ options = ReadPreference.translate(options);
331
331
  options.disconnectHandler = this.s.store;
332
332
  options.topology = this;
333
333
 
package/lib/utils.js CHANGED
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
  const MongoError = require('./core/error').MongoError;
3
- const ReadPreference = require('./core/topologies/read_preference');
4
3
  const WriteConcern = require('./write_concern');
5
4
 
6
5
  var shallowClone = function(obj) {
@@ -9,31 +8,6 @@ var shallowClone = function(obj) {
9
8
  return copy;
10
9
  };
11
10
 
12
- // Figure out the read preference
13
- var translateReadPreference = function(options) {
14
- var r = null;
15
- if (options.readPreference) {
16
- r = options.readPreference;
17
- } else {
18
- return options;
19
- }
20
-
21
- if (typeof r === 'string') {
22
- options.readPreference = new ReadPreference(r);
23
- } else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
24
- const mode = r.mode || r.preference;
25
- if (mode && typeof mode === 'string') {
26
- options.readPreference = new ReadPreference(mode, r.tags, {
27
- maxStalenessSeconds: r.maxStalenessSeconds
28
- });
29
- }
30
- } else if (!(r instanceof ReadPreference)) {
31
- throw new TypeError('Invalid read preference: ' + r);
32
- }
33
-
34
- return options;
35
- };
36
-
37
11
  // Set simple property
38
12
  var getSingleProperty = function(obj, name, value) {
39
13
  Object.defineProperty(obj, name, {
@@ -490,37 +464,6 @@ function applyWriteConcern(target, sources, options) {
490
464
  return target;
491
465
  }
492
466
 
493
- /**
494
- * Resolves a read preference based on well-defined inheritance rules. This method will not only
495
- * determine the read preference (if there is one), but will also ensure the returned value is a
496
- * properly constructed instance of `ReadPreference`.
497
- *
498
- * @param {Collection|Db|MongoClient} parent The parent of the operation on which to determine the read
499
- * preference, used for determining the inherited read preference.
500
- * @param {Object} options The options passed into the method, potentially containing a read preference
501
- * @returns {(ReadPreference|null)} The resolved read preference
502
- */
503
- function resolveReadPreference(parent, options) {
504
- options = options || {};
505
- const session = options.session;
506
-
507
- const inheritedReadPreference = parent.readPreference;
508
-
509
- let readPreference;
510
- if (options.readPreference) {
511
- readPreference = ReadPreference.fromOptions(options);
512
- } else if (session && session.inTransaction() && session.transaction.options.readPreference) {
513
- // The transaction’s read preference MUST override all other user configurable read preferences.
514
- readPreference = session.transaction.options.readPreference;
515
- } else if (inheritedReadPreference != null) {
516
- readPreference = inheritedReadPreference;
517
- } else {
518
- throw new Error('No readPreference was provided or inherited.');
519
- }
520
-
521
- return typeof readPreference === 'string' ? new ReadPreference(readPreference) : readPreference;
522
- }
523
-
524
467
  /**
525
468
  * Checks if a given value is a Promise
526
469
  *
@@ -843,7 +786,6 @@ module.exports = {
843
786
  debugOptions,
844
787
  MAX_JS_INT: Number.MAX_SAFE_INTEGER + 1,
845
788
  mergeOptionsAndWriteConcern,
846
- translateReadPreference,
847
789
  executeLegacyOperation,
848
790
  applyRetryableWrites,
849
791
  applyWriteConcern,
@@ -853,7 +795,6 @@ module.exports = {
853
795
  deprecateOptions,
854
796
  SUPPORTS,
855
797
  MongoDBNamespace,
856
- resolveReadPreference,
857
798
  emitDeprecationWarning,
858
799
  makeCounter,
859
800
  maybePromise,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mongodb",
3
- "version": "3.5.9",
3
+ "version": "3.5.10",
4
4
  "description": "The official MongoDB driver for Node.js",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -64,7 +64,7 @@
64
64
  "url": "https://github.com/mongodb/node-mongodb-native/issues"
65
65
  },
66
66
  "scripts": {
67
- "atlas": "node ./test/tools/atlas_connectivity_tests.js",
67
+ "atlas": "mocha --opts '{}' ./test/manual/atlas_connectivity.test.js",
68
68
  "test": "npm run lint && mocha --recursive test/functional test/unit test/core",
69
69
  "test-nolint": "mocha --recursive test/functional test/unit test/core",
70
70
  "coverage": "istanbul cover mongodb-test-runner -- -t 60000 test/core test/unit test/functional",