mongodb 3.6.4 → 3.6.8
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 +43 -0
- package/README.md +63 -67
- package/lib/bulk/common.js +76 -0
- package/lib/cmap/connection.js +36 -32
- package/lib/collection.js +50 -34
- package/lib/core/auth/mongo_credentials.js +5 -5
- package/lib/core/auth/scram.js +2 -1
- package/lib/core/connection/connect.js +1 -1
- package/lib/core/connection/logger.js +1 -0
- package/lib/core/connection/msg.js +3 -1
- package/lib/core/connection/utils.js +9 -14
- package/lib/core/error.js +2 -2
- package/lib/core/index.js +1 -1
- package/lib/core/sdam/monitor.js +8 -3
- package/lib/core/sdam/topology.js +2 -2
- package/lib/core/sdam/topology_description.js +24 -6
- package/lib/core/tools/smoke_plugin.js +1 -0
- package/lib/core/topologies/read_preference.js +2 -1
- package/lib/core/topologies/replset.js +1 -1
- package/lib/core/uri_parser.js +2 -1
- package/lib/core/utils.js +2 -5
- package/lib/core/wireprotocol/command.js +10 -5
- package/lib/core/wireprotocol/kill_cursors.js +2 -1
- package/lib/db.js +9 -3
- package/lib/encrypter.js +163 -0
- package/lib/gridfs-stream/upload.js +1 -0
- package/lib/mongo_client.js +123 -172
- package/lib/operations/add_user.js +2 -1
- package/lib/operations/bulk_write.js +0 -8
- package/lib/operations/connect.js +14 -61
- package/lib/operations/execute_operation.js +47 -69
- package/lib/operations/find.js +3 -0
- package/lib/operations/find_one_and_replace.js +8 -2
- package/lib/operations/find_one_and_update.js +8 -3
- package/lib/operations/insert_many.js +1 -5
- package/lib/operations/operation.js +1 -1
- package/lib/utils.js +88 -30
- package/lib/write_concern.js +5 -1
- package/package.json +22 -22
package/lib/collection.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const deprecate = require('util').deprecate;
|
|
4
4
|
const deprecateOptions = require('./utils').deprecateOptions;
|
|
5
|
+
const emitWarningOnce = require('./utils').emitWarningOnce;
|
|
5
6
|
const checkCollectionName = require('./utils').checkCollectionName;
|
|
6
7
|
const ObjectID = require('./core').BSON.ObjectID;
|
|
7
8
|
const MongoError = require('./core').MongoError;
|
|
@@ -323,7 +324,7 @@ Collection.prototype.find = deprecateOptions(
|
|
|
323
324
|
function(query, options, callback) {
|
|
324
325
|
if (typeof callback === 'object') {
|
|
325
326
|
// TODO(MAJOR): throw in the future
|
|
326
|
-
|
|
327
|
+
emitWarningOnce('Third parameter to `find()` must be a callback or undefined');
|
|
327
328
|
}
|
|
328
329
|
|
|
329
330
|
let selector = query;
|
|
@@ -1092,7 +1093,7 @@ Collection.prototype.findOne = deprecateOptions(
|
|
|
1092
1093
|
function(query, options, callback) {
|
|
1093
1094
|
if (typeof callback === 'object') {
|
|
1094
1095
|
// TODO(MAJOR): throw in the future
|
|
1095
|
-
|
|
1096
|
+
emitWarningOnce('Third parameter to `findOne()` must be a callback or undefined');
|
|
1096
1097
|
}
|
|
1097
1098
|
|
|
1098
1099
|
if (typeof query === 'function') (callback = query), (query = {}), (options = {});
|
|
@@ -1654,7 +1655,7 @@ Collection.prototype.stats = function(options, callback) {
|
|
|
1654
1655
|
|
|
1655
1656
|
/**
|
|
1656
1657
|
* @typedef {Object} Collection~findAndModifyWriteOpResult
|
|
1657
|
-
* @property {object} value Document returned from the `findAndModify` command. If no documents were found, `value` will be `null` by default
|
|
1658
|
+
* @property {object} value Document returned from the `findAndModify` command. If no documents were found, `value` will be `null` by default even if a document was upserted unless `returnDocument` is specified as `'after'`, in which case the upserted document will be returned.
|
|
1658
1659
|
* @property {object} lastErrorObject The raw lastErrorObject returned from the command. See {@link https://docs.mongodb.com/manual/reference/command/findAndModify/index.html#lasterrorobject|findAndModify command documentation}.
|
|
1659
1660
|
* @property {Number} ok Is 1 if the command executed correctly.
|
|
1660
1661
|
*/
|
|
@@ -1715,7 +1716,8 @@ Collection.prototype.findOneAndDelete = function(filter, options, callback) {
|
|
|
1715
1716
|
* @param {object} [options.projection] Limits the fields to return for all matching documents.
|
|
1716
1717
|
* @param {object} [options.sort] Determines which document the operation modifies if the query selects multiple documents.
|
|
1717
1718
|
* @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
|
|
1718
|
-
* @param {
|
|
1719
|
+
* @param {'before'|'after'} [options.returnDocument='before'] When set to `'after'`, returns the updated document rather than the original. The default is `'before'`.
|
|
1720
|
+
* @param {boolean} [options.returnOriginal=true] **Deprecated** Use `options.returnDocument` instead.
|
|
1719
1721
|
* @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
|
1720
1722
|
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
|
1721
1723
|
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
@@ -1724,22 +1726,29 @@ Collection.prototype.findOneAndDelete = function(filter, options, callback) {
|
|
|
1724
1726
|
* @param {Collection~findAndModifyCallback} [callback] The collection result callback
|
|
1725
1727
|
* @return {Promise<Collection~findAndModifyWriteOpResultObject>} returns Promise if no callback passed
|
|
1726
1728
|
*/
|
|
1727
|
-
Collection.prototype.findOneAndReplace =
|
|
1728
|
-
|
|
1729
|
-
|
|
1729
|
+
Collection.prototype.findOneAndReplace = deprecateOptions(
|
|
1730
|
+
{
|
|
1731
|
+
name: 'collection.findOneAndReplace',
|
|
1732
|
+
deprecatedOptions: ['returnOriginal'],
|
|
1733
|
+
optionsIndex: 2
|
|
1734
|
+
},
|
|
1735
|
+
function(filter, replacement, options, callback) {
|
|
1736
|
+
if (typeof options === 'function') (callback = options), (options = {});
|
|
1737
|
+
options = options || {};
|
|
1730
1738
|
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1739
|
+
// Add ignoreUndefined
|
|
1740
|
+
if (this.s.options.ignoreUndefined) {
|
|
1741
|
+
options = Object.assign({}, options);
|
|
1742
|
+
options.ignoreUndefined = this.s.options.ignoreUndefined;
|
|
1743
|
+
}
|
|
1736
1744
|
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
}
|
|
1745
|
+
return executeOperation(
|
|
1746
|
+
this.s.topology,
|
|
1747
|
+
new FindOneAndReplaceOperation(this, filter, replacement, options),
|
|
1748
|
+
callback
|
|
1749
|
+
);
|
|
1750
|
+
}
|
|
1751
|
+
);
|
|
1743
1752
|
|
|
1744
1753
|
/**
|
|
1745
1754
|
* Find a document and update it in one atomic operation. Requires a write lock for the duration of the operation.
|
|
@@ -1756,7 +1765,8 @@ Collection.prototype.findOneAndReplace = function(filter, replacement, options,
|
|
|
1756
1765
|
* @param {object} [options.projection] Limits the fields to return for all matching documents.
|
|
1757
1766
|
* @param {object} [options.sort] Determines which document the operation modifies if the query selects multiple documents.
|
|
1758
1767
|
* @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
|
|
1759
|
-
* @param {
|
|
1768
|
+
* @param {'before'|'after'} [options.returnDocument='before'] When set to `'after'`, returns the updated document rather than the original. The default is `'before'`.
|
|
1769
|
+
* @param {boolean} [options.returnOriginal=true] **Deprecated** Use `options.returnDocument` instead.
|
|
1760
1770
|
* @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
|
1761
1771
|
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
|
1762
1772
|
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
@@ -1765,22 +1775,29 @@ Collection.prototype.findOneAndReplace = function(filter, replacement, options,
|
|
|
1765
1775
|
* @param {Collection~findAndModifyCallback} [callback] The collection result callback
|
|
1766
1776
|
* @return {Promise<Collection~findAndModifyWriteOpResultObject>} returns Promise if no callback passed
|
|
1767
1777
|
*/
|
|
1768
|
-
Collection.prototype.findOneAndUpdate =
|
|
1769
|
-
|
|
1770
|
-
|
|
1778
|
+
Collection.prototype.findOneAndUpdate = deprecateOptions(
|
|
1779
|
+
{
|
|
1780
|
+
name: 'collection.findOneAndUpdate',
|
|
1781
|
+
deprecatedOptions: ['returnOriginal'],
|
|
1782
|
+
optionsIndex: 2
|
|
1783
|
+
},
|
|
1784
|
+
function(filter, update, options, callback) {
|
|
1785
|
+
if (typeof options === 'function') (callback = options), (options = {});
|
|
1786
|
+
options = options || {};
|
|
1771
1787
|
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1788
|
+
// Add ignoreUndefined
|
|
1789
|
+
if (this.s.options.ignoreUndefined) {
|
|
1790
|
+
options = Object.assign({}, options);
|
|
1791
|
+
options.ignoreUndefined = this.s.options.ignoreUndefined;
|
|
1792
|
+
}
|
|
1777
1793
|
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
}
|
|
1794
|
+
return executeOperation(
|
|
1795
|
+
this.s.topology,
|
|
1796
|
+
new FindOneAndUpdateOperation(this, filter, update, options),
|
|
1797
|
+
callback
|
|
1798
|
+
);
|
|
1799
|
+
}
|
|
1800
|
+
);
|
|
1784
1801
|
|
|
1785
1802
|
/**
|
|
1786
1803
|
* Find and update a document.
|
|
@@ -2198,7 +2215,6 @@ Collection.prototype.initializeUnorderedBulkOp = function(options) {
|
|
|
2198
2215
|
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
|
2199
2216
|
* @param {ClientSession} [options.session] optional session to use for this operation
|
|
2200
2217
|
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
2201
|
-
* @param {OrderedBulkOperation} callback The command result callback
|
|
2202
2218
|
* @return {null}
|
|
2203
2219
|
*/
|
|
2204
2220
|
Collection.prototype.initializeOrderedBulkOp = function(options) {
|
|
@@ -49,16 +49,16 @@ class MongoCredentials {
|
|
|
49
49
|
this.mechanism = options.mechanism || 'default';
|
|
50
50
|
this.mechanismProperties = options.mechanismProperties || {};
|
|
51
51
|
|
|
52
|
-
if (
|
|
53
|
-
if (this.username
|
|
52
|
+
if (/MONGODB-AWS/i.test(this.mechanism)) {
|
|
53
|
+
if (!this.username && process.env.AWS_ACCESS_KEY_ID) {
|
|
54
54
|
this.username = process.env.AWS_ACCESS_KEY_ID;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
if (this.password
|
|
57
|
+
if (!this.password && process.env.AWS_SECRET_ACCESS_KEY) {
|
|
58
58
|
this.password = process.env.AWS_SECRET_ACCESS_KEY;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
if (this.mechanismProperties.AWS_SESSION_TOKEN
|
|
61
|
+
if (!this.mechanismProperties.AWS_SESSION_TOKEN && process.env.AWS_SESSION_TOKEN) {
|
|
62
62
|
this.mechanismProperties.AWS_SESSION_TOKEN = process.env.AWS_SESSION_TOKEN;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -90,7 +90,7 @@ class MongoCredentials {
|
|
|
90
90
|
*/
|
|
91
91
|
resolveAuthMechanism(ismaster) {
|
|
92
92
|
// If the mechanism is not "default", then it does not need to be resolved
|
|
93
|
-
if (
|
|
93
|
+
if (/DEFAULT/i.test(this.mechanism)) {
|
|
94
94
|
return new MongoCredentials({
|
|
95
95
|
username: this.username,
|
|
96
96
|
password: this.password,
|
package/lib/core/auth/scram.js
CHANGED
|
@@ -4,6 +4,7 @@ const Buffer = require('safe-buffer').Buffer;
|
|
|
4
4
|
const retrieveBSON = require('../connection/utils').retrieveBSON;
|
|
5
5
|
const MongoError = require('../error').MongoError;
|
|
6
6
|
const AuthProvider = require('./auth_provider').AuthProvider;
|
|
7
|
+
const emitWarningOnce = require('../../utils').emitWarning;
|
|
7
8
|
|
|
8
9
|
const BSON = retrieveBSON();
|
|
9
10
|
const Binary = BSON.Binary;
|
|
@@ -24,7 +25,7 @@ class ScramSHA extends AuthProvider {
|
|
|
24
25
|
prepare(handshakeDoc, authContext, callback) {
|
|
25
26
|
const cryptoMethod = this.cryptoMethod;
|
|
26
27
|
if (cryptoMethod === 'sha256' && saslprep == null) {
|
|
27
|
-
|
|
28
|
+
emitWarningOnce('Warning: no saslprep library specified. Passwords will not be sanitized');
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
crypto.randomBytes(24, (err, nonce) => {
|
|
@@ -243,7 +243,7 @@ function parseSslOptions(family, options) {
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
// Set default sni servername to be the same as host
|
|
246
|
-
if (result.servername == null) {
|
|
246
|
+
if (result.servername == null && !net.isIP(result.host)) {
|
|
247
247
|
result.servername = result.host;
|
|
248
248
|
}
|
|
249
249
|
|
|
@@ -31,6 +31,7 @@ const Buffer = require('safe-buffer').Buffer;
|
|
|
31
31
|
const opcodes = require('../wireprotocol/shared').opcodes;
|
|
32
32
|
const databaseNamespace = require('../wireprotocol/shared').databaseNamespace;
|
|
33
33
|
const ReadPreference = require('../topologies/read_preference');
|
|
34
|
+
const MongoError = require('../../core/error').MongoError;
|
|
34
35
|
|
|
35
36
|
// Incrementing request id
|
|
36
37
|
let _requestId = 0;
|
|
@@ -196,7 +197,8 @@ class BinMsg {
|
|
|
196
197
|
while (this.index < this.data.length) {
|
|
197
198
|
const payloadType = this.data.readUInt8(this.index++);
|
|
198
199
|
if (payloadType === 1) {
|
|
199
|
-
|
|
200
|
+
// It was decided that no driver makes use of payload type 1
|
|
201
|
+
throw new MongoError('OP_MSG Payload Type 1 detected unsupported protocol');
|
|
200
202
|
} else if (payloadType === 0) {
|
|
201
203
|
const bsonSize = this.data.readUInt32LE(this.index);
|
|
202
204
|
const bin = this.data.slice(this.index, this.index + bsonSize);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const require_optional = require('
|
|
3
|
+
const require_optional = require('optional-require')(require);
|
|
4
4
|
|
|
5
5
|
function debugOptions(debugFields, options) {
|
|
6
|
-
|
|
6
|
+
const finaloptions = {};
|
|
7
7
|
debugFields.forEach(function(n) {
|
|
8
8
|
finaloptions[n] = options[n];
|
|
9
9
|
});
|
|
@@ -12,16 +12,14 @@ function debugOptions(debugFields, options) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function retrieveBSON() {
|
|
15
|
-
|
|
15
|
+
const BSON = require('bson');
|
|
16
16
|
BSON.native = false;
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
} catch (err) {} // eslint-disable-line
|
|
18
|
+
const optionalBSON = require_optional('bson-ext');
|
|
19
|
+
if (optionalBSON) {
|
|
20
|
+
optionalBSON.native = true;
|
|
21
|
+
return optionalBSON;
|
|
22
|
+
}
|
|
25
23
|
|
|
26
24
|
return BSON;
|
|
27
25
|
}
|
|
@@ -35,10 +33,7 @@ function noSnappyWarning() {
|
|
|
35
33
|
|
|
36
34
|
// Facilitate loading Snappy optionally
|
|
37
35
|
function retrieveSnappy() {
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
snappy = require_optional('snappy');
|
|
41
|
-
} catch (error) {} // eslint-disable-line
|
|
36
|
+
let snappy = require_optional('snappy');
|
|
42
37
|
if (!snappy) {
|
|
43
38
|
snappy = {
|
|
44
39
|
compress: noSnappyWarning,
|
package/lib/core/error.js
CHANGED
|
@@ -102,8 +102,8 @@ class MongoNetworkError extends MongoError {
|
|
|
102
102
|
super(message);
|
|
103
103
|
this.name = 'MongoNetworkError';
|
|
104
104
|
|
|
105
|
-
if (options && options.beforeHandshake ===
|
|
106
|
-
this[kBeforeHandshake] =
|
|
105
|
+
if (options && typeof options.beforeHandshake === 'boolean') {
|
|
106
|
+
this[kBeforeHandshake] = options.beforeHandshake;
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
}
|
package/lib/core/index.js
CHANGED
package/lib/core/sdam/monitor.js
CHANGED
|
@@ -91,6 +91,10 @@ class Monitor extends EventEmitter {
|
|
|
91
91
|
|
|
92
92
|
// ensure no authentication is used for monitoring
|
|
93
93
|
delete connectOptions.credentials;
|
|
94
|
+
|
|
95
|
+
// ensure encryption is not requested for monitoring
|
|
96
|
+
delete connectOptions.autoEncrypter;
|
|
97
|
+
|
|
94
98
|
this.connectOptions = Object.freeze(connectOptions);
|
|
95
99
|
}
|
|
96
100
|
|
|
@@ -222,9 +226,10 @@ function checkServer(monitor, callback) {
|
|
|
222
226
|
}
|
|
223
227
|
|
|
224
228
|
const isMaster = result.result;
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
229
|
+
const rttPinger = monitor[kRTTPinger];
|
|
230
|
+
|
|
231
|
+
const duration =
|
|
232
|
+
isAwaitable && rttPinger ? rttPinger.roundTripTime : calculateDurationInMs(start);
|
|
228
233
|
|
|
229
234
|
monitor.emit(
|
|
230
235
|
'serverHeartbeatSucceeded',
|
|
@@ -27,6 +27,7 @@ const ServerSessionPool = require('../sessions').ServerSessionPool;
|
|
|
27
27
|
const makeClientMetadata = require('../utils').makeClientMetadata;
|
|
28
28
|
const CMAP_EVENT_NAMES = require('../../cmap/events').CMAP_EVENT_NAMES;
|
|
29
29
|
const compareTopologyVersion = require('./server_description').compareTopologyVersion;
|
|
30
|
+
const emitWarning = require('../../utils').emitWarning;
|
|
30
31
|
|
|
31
32
|
const common = require('./common');
|
|
32
33
|
const drainTimerQueue = common.drainTimerQueue;
|
|
@@ -358,7 +359,6 @@ class Topology extends EventEmitter {
|
|
|
358
359
|
this.emit('topologyClosed', new events.TopologyClosedEvent(this.s.id));
|
|
359
360
|
|
|
360
361
|
stateTransition(this, STATE_CLOSED);
|
|
361
|
-
this.emit('close');
|
|
362
362
|
|
|
363
363
|
if (typeof callback === 'function') {
|
|
364
364
|
callback(err);
|
|
@@ -739,7 +739,7 @@ class Topology extends EventEmitter {
|
|
|
739
739
|
}
|
|
740
740
|
|
|
741
741
|
unref() {
|
|
742
|
-
|
|
742
|
+
emitWarning('not implemented: `unref`');
|
|
743
743
|
}
|
|
744
744
|
|
|
745
745
|
// NOTE: There are many places in code where we explicitly check the last isMaster
|
|
@@ -72,12 +72,30 @@ class TopologyDescription {
|
|
|
72
72
|
// value among ServerDescriptions of all data-bearing server types. If any have a null
|
|
73
73
|
// logicalSessionTimeoutMinutes, then TopologyDescription.logicalSessionTimeoutMinutes MUST be
|
|
74
74
|
// set to null.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
this.logicalSessionTimeoutMinutes = null;
|
|
76
|
+
for (const addressServerTuple of this.servers) {
|
|
77
|
+
const server = addressServerTuple[1];
|
|
78
|
+
if (server.isReadable) {
|
|
79
|
+
if (server.logicalSessionTimeoutMinutes == null) {
|
|
80
|
+
// If any of the servers have a null logicalSessionsTimeout, then the whole topology does
|
|
81
|
+
this.logicalSessionTimeoutMinutes = null;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (this.logicalSessionTimeoutMinutes == null) {
|
|
86
|
+
// First server with a non null logicalSessionsTimeout
|
|
87
|
+
this.logicalSessionTimeoutMinutes = server.logicalSessionTimeoutMinutes;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Always select the smaller of the:
|
|
92
|
+
// current server logicalSessionsTimeout and the topologies logicalSessionsTimeout
|
|
93
|
+
this.logicalSessionTimeoutMinutes = Math.min(
|
|
94
|
+
this.logicalSessionTimeoutMinutes,
|
|
95
|
+
server.logicalSessionTimeoutMinutes
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
81
99
|
}
|
|
82
100
|
|
|
83
101
|
/**
|
|
@@ -52,6 +52,7 @@ exports.attachToRunner = function(runner, outputFile) {
|
|
|
52
52
|
fs.writeFileSync(outputFile, JSON.stringify(smokeOutput));
|
|
53
53
|
|
|
54
54
|
// Standard NodeJS uncaught exception handler
|
|
55
|
+
// eslint-disable-next-line no-console
|
|
55
56
|
console.error(err.stack);
|
|
56
57
|
process.exit(1);
|
|
57
58
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
const emitWarningOnce = require('../../utils').emitWarningOnce;
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* The **ReadPreference** class is a class that represents a MongoDB ReadPreference and is
|
|
@@ -20,7 +21,7 @@ const ReadPreference = function(mode, tags, options) {
|
|
|
20
21
|
|
|
21
22
|
// TODO(major): tags MUST be an array of tagsets
|
|
22
23
|
if (tags && !Array.isArray(tags)) {
|
|
23
|
-
|
|
24
|
+
emitWarningOnce(
|
|
24
25
|
'ReadPreference tags must be an array, this will change in the next major version'
|
|
25
26
|
);
|
|
26
27
|
|
|
@@ -558,7 +558,7 @@ var monitorServer = function(host, self, options) {
|
|
|
558
558
|
self.s.options.secondaryOnlyConnectionAllowed) ||
|
|
559
559
|
self.s.replicaSetState.hasPrimary())
|
|
560
560
|
) {
|
|
561
|
-
stateTransition(self,
|
|
561
|
+
stateTransition(self, CONNECTING);
|
|
562
562
|
|
|
563
563
|
// Rexecute any stalled operation
|
|
564
564
|
rexecuteOperations(self);
|
package/lib/core/uri_parser.js
CHANGED
|
@@ -4,6 +4,7 @@ const qs = require('querystring');
|
|
|
4
4
|
const dns = require('dns');
|
|
5
5
|
const MongoParseError = require('./error').MongoParseError;
|
|
6
6
|
const ReadPreference = require('./topologies/read_preference');
|
|
7
|
+
const emitWarningOnce = require('../utils').emitWarningOnce;
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* The following regular expression validates a connection string and breaks the
|
|
@@ -438,7 +439,7 @@ function parseQueryString(query, options) {
|
|
|
438
439
|
// special cases for known deprecated options
|
|
439
440
|
if (result.wtimeout && result.wtimeoutms) {
|
|
440
441
|
delete result.wtimeout;
|
|
441
|
-
|
|
442
|
+
emitWarningOnce('Unsupported option `wtimeout` specified');
|
|
442
443
|
}
|
|
443
444
|
|
|
444
445
|
return Object.keys(result).length ? result : null;
|
package/lib/core/utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const os = require('os');
|
|
3
3
|
const crypto = require('crypto');
|
|
4
|
-
const requireOptional = require('
|
|
4
|
+
const requireOptional = require('optional-require')(require);
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Generate a UUIDv4
|
|
@@ -46,10 +46,7 @@ const noEJSONError = function() {
|
|
|
46
46
|
|
|
47
47
|
// Facilitate loading EJSON optionally
|
|
48
48
|
function retrieveEJSON() {
|
|
49
|
-
let EJSON =
|
|
50
|
-
try {
|
|
51
|
-
EJSON = requireOptional('mongodb-extjson');
|
|
52
|
-
} catch (error) {} // eslint-disable-line
|
|
49
|
+
let EJSON = requireOptional('mongodb-extjson');
|
|
53
50
|
if (!EJSON) {
|
|
54
51
|
EJSON = {
|
|
55
52
|
parse: noEJSONError,
|
|
@@ -45,14 +45,19 @@ function _command(server, ns, cmd, options, callback) {
|
|
|
45
45
|
const shouldUseOpMsg = supportsOpMsg(server);
|
|
46
46
|
const session = options.session;
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
const serverClusterTime = server.clusterTime;
|
|
49
|
+
let clusterTime = serverClusterTime;
|
|
49
50
|
let finalCmd = Object.assign({}, cmd);
|
|
50
51
|
if (hasSessionSupport(server) && session) {
|
|
52
|
+
const sessionClusterTime = session.clusterTime;
|
|
51
53
|
if (
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
serverClusterTime &&
|
|
55
|
+
serverClusterTime.clusterTime &&
|
|
56
|
+
sessionClusterTime &&
|
|
57
|
+
sessionClusterTime.clusterTime &&
|
|
58
|
+
sessionClusterTime.clusterTime.greaterThan(serverClusterTime.clusterTime)
|
|
54
59
|
) {
|
|
55
|
-
clusterTime =
|
|
60
|
+
clusterTime = sessionClusterTime;
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
const err = applySession(session, finalCmd, options);
|
|
@@ -61,8 +66,8 @@ function _command(server, ns, cmd, options, callback) {
|
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
68
|
|
|
64
|
-
// if we have a known cluster time, gossip it
|
|
65
69
|
if (clusterTime) {
|
|
70
|
+
// if we have a known cluster time, gossip it
|
|
66
71
|
finalCmd.$clusterTime = clusterTime;
|
|
67
72
|
}
|
|
68
73
|
|
|
@@ -5,6 +5,7 @@ const MongoError = require('../error').MongoError;
|
|
|
5
5
|
const MongoNetworkError = require('../error').MongoNetworkError;
|
|
6
6
|
const collectionNamespace = require('./shared').collectionNamespace;
|
|
7
7
|
const maxWireVersion = require('../utils').maxWireVersion;
|
|
8
|
+
const emitWarning = require('../utils').emitWarning;
|
|
8
9
|
const command = require('./command');
|
|
9
10
|
|
|
10
11
|
function killCursors(server, ns, cursorState, callback) {
|
|
@@ -31,7 +32,7 @@ function killCursors(server, ns, cursorState, callback) {
|
|
|
31
32
|
if (typeof callback === 'function') {
|
|
32
33
|
callback(err, null);
|
|
33
34
|
} else {
|
|
34
|
-
|
|
35
|
+
emitWarning(err);
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
}
|
package/lib/db.js
CHANGED
|
@@ -12,7 +12,7 @@ const MongoError = require('./core').MongoError;
|
|
|
12
12
|
const ObjectID = require('./core').ObjectID;
|
|
13
13
|
const Logger = require('./core').Logger;
|
|
14
14
|
const Collection = require('./collection');
|
|
15
|
-
const
|
|
15
|
+
const conditionallyMergeWriteConcern = require('./utils').conditionallyMergeWriteConcern;
|
|
16
16
|
const executeLegacyOperation = require('./utils').executeLegacyOperation;
|
|
17
17
|
const ChangeStream = require('./change_stream');
|
|
18
18
|
const deprecate = require('util').deprecate;
|
|
@@ -382,7 +382,7 @@ Db.prototype.admin = function() {
|
|
|
382
382
|
* @param {AggregationCursor} cursor The cursor if the aggregation command was executed successfully.
|
|
383
383
|
*/
|
|
384
384
|
|
|
385
|
-
const
|
|
385
|
+
const COLLECTION_OPTION_KEYS = [
|
|
386
386
|
'pkFactory',
|
|
387
387
|
'readPreference',
|
|
388
388
|
'serializeFunctions',
|
|
@@ -433,8 +433,14 @@ Db.prototype.collection = function(name, options, callback) {
|
|
|
433
433
|
options.ignoreUndefined = this.s.options.ignoreUndefined;
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
+
for (const collectionOptionKey of COLLECTION_OPTION_KEYS) {
|
|
437
|
+
if (!(collectionOptionKey in options) && this.s.options[collectionOptionKey] !== undefined) {
|
|
438
|
+
options[collectionOptionKey] = this.s.options[collectionOptionKey];
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
436
442
|
// Merge in all needed options and ensure correct writeConcern merging from db level
|
|
437
|
-
options =
|
|
443
|
+
options = conditionallyMergeWriteConcern(options, this.s.options);
|
|
438
444
|
|
|
439
445
|
// Execute
|
|
440
446
|
if (options == null || !options.strict) {
|