mongodb 3.6.11 → 3.7.2
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/index.js +4 -0
- package/lib/cmap/connection.js +34 -7
- package/lib/cmap/connection_pool.js +4 -2
- package/lib/collection.js +1 -1
- package/lib/core/auth/mongo_credentials.js +4 -1
- package/lib/core/auth/mongodb_aws.js +16 -15
- package/lib/core/connection/connect.js +22 -5
- package/lib/core/connection/connection.js +2 -0
- package/lib/core/connection/pool.js +1 -0
- package/lib/core/connection/utils.js +35 -2
- package/lib/core/error.js +46 -46
- package/lib/core/index.js +9 -0
- package/lib/core/sdam/monitor.js +16 -2
- package/lib/core/sdam/server.js +2 -0
- package/lib/core/sdam/server_description.js +4 -0
- package/lib/core/sdam/topology.js +10 -2
- package/lib/core/sessions.js +11 -8
- package/lib/core/topologies/replset_state.js +5 -3
- package/lib/core/topologies/shared.js +4 -1
- package/lib/core/transactions.js +5 -1
- package/lib/core/uri_parser.js +14 -0
- package/lib/core/wireprotocol/command.js +24 -0
- package/lib/core/wireprotocol/kill_cursors.js +7 -2
- package/lib/core/wireprotocol/query.js +9 -5
- package/lib/cursor.js +4 -0
- package/lib/db.js +1 -0
- package/lib/error.js +21 -20
- package/lib/error_codes.js +36 -0
- package/lib/explain.js +5 -12
- package/lib/gridfs-stream/index.js +39 -24
- package/lib/gridfs-stream/upload.js +53 -46
- package/lib/mongo_client.js +30 -5
- package/lib/operations/connect.js +1 -0
- package/lib/operations/db_ops.js +10 -7
- package/lib/operations/estimated_document_count.js +47 -18
- package/lib/topologies/native_topology.js +4 -0
- package/lib/url_parser.js +8 -0
- package/lib/utils.js +10 -1
- package/package.json +3 -3
- package/HISTORY.md +0 -2908
|
@@ -34,7 +34,7 @@ var ReplSetState = function(options) {
|
|
|
34
34
|
// Add event listener
|
|
35
35
|
EventEmitter.call(this);
|
|
36
36
|
// Topology state
|
|
37
|
-
this.topologyType = TopologyType.ReplicaSetNoPrimary;
|
|
37
|
+
this.topologyType = options.setName ? TopologyType.ReplicaSetNoPrimary : TopologyType.Unknown;
|
|
38
38
|
this.setName = options.setName;
|
|
39
39
|
|
|
40
40
|
// Server set
|
|
@@ -218,7 +218,8 @@ const isArbiter = ismaster => ismaster.arbiterOnly && ismaster.setName;
|
|
|
218
218
|
ReplSetState.prototype.update = function(server) {
|
|
219
219
|
var self = this;
|
|
220
220
|
// Get the current ismaster
|
|
221
|
-
|
|
221
|
+
const ismaster = server.lastIsMaster();
|
|
222
|
+
if (ismaster && ismaster.isWritablePrimary) ismaster.ismaster = ismaster.isWritablePrimary;
|
|
222
223
|
|
|
223
224
|
// Get the server name and lowerCase it
|
|
224
225
|
var serverName = server.name.toLowerCase();
|
|
@@ -358,7 +359,8 @@ ReplSetState.prototype.update = function(server) {
|
|
|
358
359
|
// Standalone server, destroy and return
|
|
359
360
|
//
|
|
360
361
|
if (ismaster && ismaster.ismaster && !ismaster.setName) {
|
|
361
|
-
|
|
362
|
+
// We should not mark the topology as Unknown because of one standalone
|
|
363
|
+
// we should just remove this server from the set
|
|
362
364
|
this.remove(server, { force: true });
|
|
363
365
|
return false;
|
|
364
366
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
|
|
3
|
+
const MONGODB_ERROR_CODES = require('../../error_codes').MONGODB_ERROR_CODES;
|
|
2
4
|
const ReadPreference = require('./read_preference');
|
|
3
5
|
const TopologyType = require('../sdam/common').TopologyType;
|
|
4
6
|
const MongoError = require('../error').MongoError;
|
|
5
7
|
const isRetryableWriteError = require('../error').isRetryableWriteError;
|
|
6
8
|
const maxWireVersion = require('../utils').maxWireVersion;
|
|
7
9
|
const MongoNetworkError = require('../error').MongoNetworkError;
|
|
8
|
-
|
|
10
|
+
|
|
11
|
+
const MMAPv1_RETRY_WRITES_ERROR_CODE = MONGODB_ERROR_CODES.IllegalOperation;
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Emit event if it exists
|
package/lib/core/transactions.js
CHANGED
|
@@ -150,7 +150,11 @@ class Transaction {
|
|
|
150
150
|
const nextStates = stateMachine[this.state];
|
|
151
151
|
if (nextStates && nextStates.indexOf(nextState) !== -1) {
|
|
152
152
|
this.state = nextState;
|
|
153
|
-
if (
|
|
153
|
+
if (
|
|
154
|
+
this.state === TxnState.NO_TRANSACTION ||
|
|
155
|
+
this.state === TxnState.STARTING_TRANSACTION ||
|
|
156
|
+
this.state === TxnState.TRANSACTION_ABORTED
|
|
157
|
+
) {
|
|
154
158
|
this.unpinServer();
|
|
155
159
|
}
|
|
156
160
|
return;
|
package/lib/core/uri_parser.js
CHANGED
|
@@ -106,6 +106,11 @@ function parseSrvConnectionString(uri, options, callback) {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
record = qs.parse(record[0].join(''));
|
|
109
|
+
|
|
110
|
+
if (Object.keys(record).some(k => k.toLowerCase() === 'loadbalanced')) {
|
|
111
|
+
return callback(new MongoParseError('Load balancer mode requires driver version 4+'));
|
|
112
|
+
}
|
|
113
|
+
|
|
109
114
|
if (Object.keys(record).some(key => key !== 'authSource' && key !== 'replicaSet')) {
|
|
110
115
|
return callback(
|
|
111
116
|
new MongoParseError('Text record must only set `authSource` or `replicaSet`')
|
|
@@ -432,6 +437,11 @@ function parseQueryString(query, options) {
|
|
|
432
437
|
}
|
|
433
438
|
|
|
434
439
|
const normalizedKey = key.toLowerCase();
|
|
440
|
+
if (normalizedKey === 'serverapi') {
|
|
441
|
+
throw new MongoParseError(
|
|
442
|
+
'URI cannot contain `serverApi`, it can only be passed to the client'
|
|
443
|
+
);
|
|
444
|
+
}
|
|
435
445
|
const parsedValue = FILE_PATH_OPTIONS.has(normalizedKey)
|
|
436
446
|
? value
|
|
437
447
|
: parseQueryStringItemValue(normalizedKey, value);
|
|
@@ -593,6 +603,10 @@ function parseConnectionString(uri, options, callback) {
|
|
|
593
603
|
|
|
594
604
|
parsedOptions = Object.assign({}, parsedOptions, options);
|
|
595
605
|
|
|
606
|
+
if (Object.keys(parsedOptions).some(k => k.toLowerCase() === 'loadbalanced')) {
|
|
607
|
+
return callback(new MongoParseError('Load balancer mode requires driver version 4+'));
|
|
608
|
+
}
|
|
609
|
+
|
|
596
610
|
if (protocol === PROTOCOL_MONGODB_SRV) {
|
|
597
611
|
return parseSrvConnectionString(uri, parsedOptions, callback);
|
|
598
612
|
}
|
|
@@ -48,6 +48,18 @@ function _command(server, ns, cmd, options, callback) {
|
|
|
48
48
|
const serverClusterTime = server.clusterTime;
|
|
49
49
|
let clusterTime = serverClusterTime;
|
|
50
50
|
let finalCmd = Object.assign({}, cmd);
|
|
51
|
+
|
|
52
|
+
const serverApi = options.serverApi;
|
|
53
|
+
if (serverApi) {
|
|
54
|
+
finalCmd.apiVersion = serverApi.version || serverApi;
|
|
55
|
+
if (serverApi.strict != null) {
|
|
56
|
+
finalCmd.apiStrict = serverApi.strict;
|
|
57
|
+
}
|
|
58
|
+
if (serverApi.deprecationErrors != null) {
|
|
59
|
+
finalCmd.apiDeprecationErrors = serverApi.deprecationErrors;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
51
63
|
if (hasSessionSupport(server) && session) {
|
|
52
64
|
const sessionClusterTime = session.clusterTime;
|
|
53
65
|
if (
|
|
@@ -60,6 +72,18 @@ function _command(server, ns, cmd, options, callback) {
|
|
|
60
72
|
clusterTime = sessionClusterTime;
|
|
61
73
|
}
|
|
62
74
|
|
|
75
|
+
// We need to unpin any read or write commands that happen outside of a pinned
|
|
76
|
+
// transaction, so we check if we have a pinned transaction that is no longer
|
|
77
|
+
// active, and unpin for all except start or commit.
|
|
78
|
+
if (
|
|
79
|
+
!session.transaction.isActive &&
|
|
80
|
+
session.transaction.isPinned &&
|
|
81
|
+
!finalCmd.startTransaction &&
|
|
82
|
+
!finalCmd.commitTransaction
|
|
83
|
+
) {
|
|
84
|
+
session.transaction.unpinServer();
|
|
85
|
+
}
|
|
86
|
+
|
|
63
87
|
const err = applySession(session, finalCmd, options);
|
|
64
88
|
if (err) {
|
|
65
89
|
return callback(err);
|
|
@@ -8,8 +8,13 @@ const maxWireVersion = require('../utils').maxWireVersion;
|
|
|
8
8
|
const emitWarning = require('../utils').emitWarning;
|
|
9
9
|
const command = require('./command');
|
|
10
10
|
|
|
11
|
-
function killCursors(server, ns, cursorState, callback) {
|
|
11
|
+
function killCursors(server, ns, cursorState, defaultOptions, callback) {
|
|
12
|
+
if (typeof defaultOptions === 'function') {
|
|
13
|
+
callback = defaultOptions;
|
|
14
|
+
defaultOptions = {};
|
|
15
|
+
}
|
|
12
16
|
callback = typeof callback === 'function' ? callback : () => {};
|
|
17
|
+
|
|
13
18
|
const cursorId = cursorState.cursorId;
|
|
14
19
|
|
|
15
20
|
if (maxWireVersion(server) < 4) {
|
|
@@ -45,7 +50,7 @@ function killCursors(server, ns, cursorState, callback) {
|
|
|
45
50
|
cursors: [cursorId]
|
|
46
51
|
};
|
|
47
52
|
|
|
48
|
-
const options = {};
|
|
53
|
+
const options = defaultOptions || {};
|
|
49
54
|
if (typeof cursorState.session === 'object') options.session = cursorState.session;
|
|
50
55
|
|
|
51
56
|
command(server, ns, killCursorCmd, options, (err, result) => {
|
|
@@ -37,9 +37,13 @@ function query(server, ns, cmd, cursorState, options, callback) {
|
|
|
37
37
|
|
|
38
38
|
// If we have explain, we need to rewrite the find command
|
|
39
39
|
// to wrap it in the explain command
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
try {
|
|
41
|
+
const explain = Explain.fromOptions(options);
|
|
42
|
+
if (explain) {
|
|
43
|
+
findCmd = decorateWithExplain(findCmd, explain);
|
|
44
|
+
}
|
|
45
|
+
} catch (err) {
|
|
46
|
+
return callback(err);
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
// NOTE: This actually modifies the passed in cmd, and our code _depends_ on this
|
|
@@ -140,8 +144,8 @@ function prepareFindCommand(server, ns, cmd, cursorState) {
|
|
|
140
144
|
if (cmd.maxTimeMS) findCmd.maxTimeMS = cmd.maxTimeMS;
|
|
141
145
|
if (cmd.min) findCmd.min = cmd.min;
|
|
142
146
|
if (cmd.max) findCmd.max = cmd.max;
|
|
143
|
-
|
|
144
|
-
|
|
147
|
+
if (typeof cmd.returnKey === 'boolean') findCmd.returnKey = cmd.returnKey;
|
|
148
|
+
if (typeof cmd.showDiskLoc === 'boolean') findCmd.showRecordId = cmd.showDiskLoc;
|
|
145
149
|
if (cmd.snapshot) findCmd.snapshot = cmd.snapshot;
|
|
146
150
|
if (cmd.tailable) findCmd.tailable = cmd.tailable;
|
|
147
151
|
if (cmd.oplogReplay) findCmd.oplogReplay = cmd.oplogReplay;
|
package/lib/cursor.js
CHANGED
|
@@ -165,6 +165,10 @@ class Cursor extends CoreCursor {
|
|
|
165
165
|
return this.cmd.sort;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
set session(clientSession) {
|
|
169
|
+
this.cursorState.session = clientSession;
|
|
170
|
+
}
|
|
171
|
+
|
|
168
172
|
_initializeCursor(callback) {
|
|
169
173
|
if (this.operation && this.operation.session != null) {
|
|
170
174
|
this.cursorState.session = this.operation.session;
|
package/lib/db.js
CHANGED
|
@@ -951,6 +951,7 @@ Db.prototype.indexInformation = function(name, options, callback) {
|
|
|
951
951
|
/**
|
|
952
952
|
* Unref all sockets
|
|
953
953
|
* @method
|
|
954
|
+
* @deprecated This function is deprecated and will be removed in the next major version.
|
|
954
955
|
*/
|
|
955
956
|
Db.prototype.unref = function() {
|
|
956
957
|
this.s.topology.unref();
|
package/lib/error.js
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const MongoNetworkError = require('./core').MongoNetworkError;
|
|
4
|
+
const MONGODB_ERROR_CODES = require('./error_codes').MONGODB_ERROR_CODES;
|
|
4
5
|
|
|
5
6
|
// From spec@https://github.com/mongodb/specifications/blob/f93d78191f3db2898a59013a7ed5650352ef6da8/source/change-streams/change-streams.rst#resumable-error
|
|
6
7
|
const GET_MORE_RESUMABLE_CODES = new Set([
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
8
|
+
MONGODB_ERROR_CODES.HostUnreachable,
|
|
9
|
+
MONGODB_ERROR_CODES.HostNotFound,
|
|
10
|
+
MONGODB_ERROR_CODES.NetworkTimeout,
|
|
11
|
+
MONGODB_ERROR_CODES.ShutdownInProgress,
|
|
12
|
+
MONGODB_ERROR_CODES.PrimarySteppedDown,
|
|
13
|
+
MONGODB_ERROR_CODES.ExceededTimeLimit,
|
|
14
|
+
MONGODB_ERROR_CODES.SocketException,
|
|
15
|
+
MONGODB_ERROR_CODES.NotMaster,
|
|
16
|
+
MONGODB_ERROR_CODES.InterruptedAtShutdown,
|
|
17
|
+
MONGODB_ERROR_CODES.InterruptedDueToReplStateChange,
|
|
18
|
+
MONGODB_ERROR_CODES.NotMasterNoSlaveOk,
|
|
19
|
+
MONGODB_ERROR_CODES.NotMasterOrSecondary,
|
|
20
|
+
MONGODB_ERROR_CODES.StaleShardVersion,
|
|
21
|
+
MONGODB_ERROR_CODES.StaleEpoch,
|
|
22
|
+
MONGODB_ERROR_CODES.StaleConfig,
|
|
23
|
+
MONGODB_ERROR_CODES.RetryChangeStream,
|
|
24
|
+
MONGODB_ERROR_CODES.FailedToSatisfyReadPreference,
|
|
25
|
+
MONGODB_ERROR_CODES.CursorNotFound
|
|
25
26
|
]);
|
|
26
27
|
|
|
27
28
|
function isResumableError(error, wireVersion) {
|
|
@@ -31,7 +32,7 @@ function isResumableError(error, wireVersion) {
|
|
|
31
32
|
|
|
32
33
|
if (wireVersion >= 9) {
|
|
33
34
|
// DRIVERS-1308: For 4.4 drivers running against 4.4 servers, drivers will add a special case to treat the CursorNotFound error code as resumable
|
|
34
|
-
if (error.code ===
|
|
35
|
+
if (error.code === MONGODB_ERROR_CODES.CursorNotFound) {
|
|
35
36
|
return true;
|
|
36
37
|
}
|
|
37
38
|
return error.hasErrorLabel('ResumableChangeStreamError');
|
|
@@ -40,4 +41,4 @@ function isResumableError(error, wireVersion) {
|
|
|
40
41
|
return GET_MORE_RESUMABLE_CODES.has(error.code);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
module.exports = { GET_MORE_RESUMABLE_CODES, isResumableError };
|
|
44
|
+
module.exports = { GET_MORE_RESUMABLE_CODES, isResumableError, MONGODB_ERROR_CODES };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MONGODB_ERROR_CODES = Object.freeze({
|
|
4
|
+
HostUnreachable: 6,
|
|
5
|
+
HostNotFound: 7,
|
|
6
|
+
NetworkTimeout: 89,
|
|
7
|
+
ShutdownInProgress: 91,
|
|
8
|
+
PrimarySteppedDown: 189,
|
|
9
|
+
ExceededTimeLimit: 262,
|
|
10
|
+
SocketException: 9001,
|
|
11
|
+
NotMaster: 10107,
|
|
12
|
+
InterruptedAtShutdown: 11600,
|
|
13
|
+
InterruptedDueToReplStateChange: 11602,
|
|
14
|
+
NotMasterNoSlaveOk: 13435,
|
|
15
|
+
NotMasterOrSecondary: 13436,
|
|
16
|
+
StaleShardVersion: 63,
|
|
17
|
+
StaleEpoch: 150,
|
|
18
|
+
StaleConfig: 13388,
|
|
19
|
+
RetryChangeStream: 234,
|
|
20
|
+
FailedToSatisfyReadPreference: 133,
|
|
21
|
+
CursorNotFound: 43,
|
|
22
|
+
LegacyNotPrimary: 10058,
|
|
23
|
+
WriteConcernFailed: 64,
|
|
24
|
+
NamespaceNotFound: 26,
|
|
25
|
+
IllegalOperation: 20,
|
|
26
|
+
MaxTimeMSExpired: 50,
|
|
27
|
+
UnknownReplWriteConcern: 79,
|
|
28
|
+
UnsatisfiableWriteConcern: 100,
|
|
29
|
+
DuplicateKey: 11000,
|
|
30
|
+
CannotCreateIndex: 67,
|
|
31
|
+
IndexOptionsConflict: 85,
|
|
32
|
+
IndexKeySpecsConflict: 86,
|
|
33
|
+
InvalidIndexSpecificationOption: 197
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
module.exports = Object.freeze({ MONGODB_ERROR_CODES });
|
package/lib/explain.js
CHANGED
|
@@ -2,16 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const MongoError = require('./core/error').MongoError;
|
|
4
4
|
|
|
5
|
-
const ExplainVerbosity = {
|
|
6
|
-
queryPlanner: 'queryPlanner',
|
|
7
|
-
queryPlannerExtended: 'queryPlannerExtended',
|
|
8
|
-
executionStats: 'executionStats',
|
|
9
|
-
allPlansExecution: 'allPlansExecution'
|
|
10
|
-
};
|
|
11
|
-
|
|
12
5
|
/**
|
|
13
6
|
* @class
|
|
14
|
-
* @property {
|
|
7
|
+
* @property {string} verbosity The verbosity mode for the explain output, e.g.: 'queryPlanner', 'queryPlannerExtended', 'executionStats', 'allPlansExecution'.
|
|
15
8
|
*/
|
|
16
9
|
class Explain {
|
|
17
10
|
/**
|
|
@@ -21,7 +14,7 @@ class Explain {
|
|
|
21
14
|
* and false as "queryPlanner". Prior to server version 3.6, aggregate()
|
|
22
15
|
* ignores the verbosity parameter and executes in "queryPlanner".
|
|
23
16
|
*
|
|
24
|
-
* @param {
|
|
17
|
+
* @param {string|boolean} [verbosity] The verbosity mode for the explain output.
|
|
25
18
|
*/
|
|
26
19
|
constructor(verbosity) {
|
|
27
20
|
if (typeof verbosity === 'boolean') {
|
|
@@ -35,7 +28,7 @@ class Explain {
|
|
|
35
28
|
* Construct an Explain given an options object.
|
|
36
29
|
*
|
|
37
30
|
* @param {object} [options] The options object from which to extract the explain.
|
|
38
|
-
* @param {
|
|
31
|
+
* @param {string|boolean} [options.explain] The verbosity mode for the explain output.
|
|
39
32
|
* @return {Explain}
|
|
40
33
|
*/
|
|
41
34
|
static fromOptions(options) {
|
|
@@ -44,11 +37,11 @@ class Explain {
|
|
|
44
37
|
}
|
|
45
38
|
|
|
46
39
|
const explain = options.explain;
|
|
47
|
-
if (typeof explain === 'boolean' || explain
|
|
40
|
+
if (typeof explain === 'boolean' || typeof explain === 'string') {
|
|
48
41
|
return new Explain(options.explain);
|
|
49
42
|
}
|
|
50
43
|
|
|
51
|
-
throw new MongoError(`explain must be
|
|
44
|
+
throw new MongoError(`explain must be a string or a boolean`);
|
|
52
45
|
}
|
|
53
46
|
}
|
|
54
47
|
|
|
@@ -7,6 +7,7 @@ var shallowClone = require('../utils').shallowClone;
|
|
|
7
7
|
var toError = require('../utils').toError;
|
|
8
8
|
var util = require('util');
|
|
9
9
|
var executeLegacyOperation = require('../utils').executeLegacyOperation;
|
|
10
|
+
const deprecateOptions = require('../utils').deprecateOptions;
|
|
10
11
|
|
|
11
12
|
var DEFAULT_GRIDFS_BUCKET_OPTIONS = {
|
|
12
13
|
bucketName: 'fs',
|
|
@@ -79,21 +80,28 @@ util.inherits(GridFSBucket, Emitter);
|
|
|
79
80
|
* @param {object} [options.metadata] Optional object to store in the file document's `metadata` field
|
|
80
81
|
* @param {string} [options.contentType] Optional string to store in the file document's `contentType` field
|
|
81
82
|
* @param {array} [options.aliases] Optional array of strings to store in the file document's `aliases` field
|
|
82
|
-
* @param {boolean} [options.disableMD5=false] If true, disables adding an md5 field to file data
|
|
83
|
+
* @param {boolean} [options.disableMD5=false] **Deprecated** If true, disables adding an md5 field to file data
|
|
83
84
|
* @return {GridFSBucketWriteStream}
|
|
84
85
|
*/
|
|
85
86
|
|
|
86
|
-
GridFSBucket.prototype.openUploadStream =
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
options
|
|
87
|
+
GridFSBucket.prototype.openUploadStream = deprecateOptions(
|
|
88
|
+
{
|
|
89
|
+
name: 'GridFSBucket.openUploadStream',
|
|
90
|
+
deprecatedOptions: ['disableMD5'],
|
|
91
|
+
optionsIndex: 1
|
|
92
|
+
},
|
|
93
|
+
function(filename, options) {
|
|
94
|
+
if (options) {
|
|
95
|
+
options = shallowClone(options);
|
|
96
|
+
} else {
|
|
97
|
+
options = {};
|
|
98
|
+
}
|
|
99
|
+
if (!options.chunkSizeBytes) {
|
|
100
|
+
options.chunkSizeBytes = this.s.options.chunkSizeBytes;
|
|
101
|
+
}
|
|
102
|
+
return new GridFSBucketWriteStream(this, filename, options);
|
|
94
103
|
}
|
|
95
|
-
|
|
96
|
-
};
|
|
104
|
+
);
|
|
97
105
|
|
|
98
106
|
/**
|
|
99
107
|
* Returns a writable stream (GridFSBucketWriteStream) for writing
|
|
@@ -107,25 +115,32 @@ GridFSBucket.prototype.openUploadStream = function(filename, options) {
|
|
|
107
115
|
* @param {object} [options.metadata] Optional object to store in the file document's `metadata` field
|
|
108
116
|
* @param {string} [options.contentType] Optional string to store in the file document's `contentType` field
|
|
109
117
|
* @param {array} [options.aliases] Optional array of strings to store in the file document's `aliases` field
|
|
110
|
-
* @param {boolean} [options.disableMD5=false] If true, disables adding an md5 field to file data
|
|
118
|
+
* @param {boolean} [options.disableMD5=false] **Deprecated** If true, disables adding an md5 field to file data
|
|
111
119
|
* @return {GridFSBucketWriteStream}
|
|
112
120
|
*/
|
|
113
121
|
|
|
114
|
-
GridFSBucket.prototype.openUploadStreamWithId =
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
122
|
+
GridFSBucket.prototype.openUploadStreamWithId = deprecateOptions(
|
|
123
|
+
{
|
|
124
|
+
name: 'GridFSBucket.openUploadStreamWithId',
|
|
125
|
+
deprecatedOptions: ['disableMD5'],
|
|
126
|
+
optionsIndex: 2
|
|
127
|
+
},
|
|
128
|
+
function(id, filename, options) {
|
|
129
|
+
if (options) {
|
|
130
|
+
options = shallowClone(options);
|
|
131
|
+
} else {
|
|
132
|
+
options = {};
|
|
133
|
+
}
|
|
120
134
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
135
|
+
if (!options.chunkSizeBytes) {
|
|
136
|
+
options.chunkSizeBytes = this.s.options.chunkSizeBytes;
|
|
137
|
+
}
|
|
124
138
|
|
|
125
|
-
|
|
139
|
+
options.id = id;
|
|
126
140
|
|
|
127
|
-
|
|
128
|
-
}
|
|
141
|
+
return new GridFSBucketWriteStream(this, filename, options);
|
|
142
|
+
}
|
|
143
|
+
);
|
|
129
144
|
|
|
130
145
|
/**
|
|
131
146
|
* Returns a readable stream (GridFSBucketReadStream) for streaming file
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
module.exports = GridFSBucketWriteStream;
|
|
3
|
+
const MONGODB_ERROR_CODES = require('../error_codes').MONGODB_ERROR_CODES;
|
|
4
|
+
const core = require('../core');
|
|
5
|
+
const crypto = require('crypto');
|
|
6
|
+
const stream = require('stream');
|
|
7
|
+
const util = require('util');
|
|
8
|
+
const Buffer = require('safe-buffer').Buffer;
|
|
9
|
+
const deprecateOptions = require('../utils').deprecateOptions;
|
|
12
10
|
|
|
13
11
|
/**
|
|
14
12
|
* A writable stream that enables you to write buffers to GridFS.
|
|
@@ -31,42 +29,49 @@ module.exports = GridFSBucketWriteStream;
|
|
|
31
29
|
* @fires GridFSBucketWriteStream#finish
|
|
32
30
|
*/
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
32
|
+
const GridFSBucketWriteStream = deprecateOptions(
|
|
33
|
+
{
|
|
34
|
+
name: 'GridFSBucketWriteStream',
|
|
35
|
+
deprecatedOptions: ['disableMD5'],
|
|
36
|
+
optionsIndex: 2
|
|
37
|
+
},
|
|
38
|
+
function(bucket, filename, options) {
|
|
39
|
+
options = options || {};
|
|
40
|
+
stream.Writable.call(this, options);
|
|
41
|
+
this.bucket = bucket;
|
|
42
|
+
this.chunks = bucket.s._chunksCollection;
|
|
43
|
+
this.filename = filename;
|
|
44
|
+
this.files = bucket.s._filesCollection;
|
|
45
|
+
this.options = options;
|
|
46
|
+
// Signals the write is all done
|
|
47
|
+
this.done = false;
|
|
48
|
+
|
|
49
|
+
this.id = options.id ? options.id : core.BSON.ObjectId();
|
|
50
|
+
this.chunkSizeBytes = this.options.chunkSizeBytes;
|
|
51
|
+
this.bufToStore = Buffer.alloc(this.chunkSizeBytes);
|
|
52
|
+
this.length = 0;
|
|
53
|
+
this.md5 = !options.disableMD5 && crypto.createHash('md5');
|
|
54
|
+
this.n = 0;
|
|
55
|
+
this.pos = 0;
|
|
56
|
+
this.state = {
|
|
57
|
+
streamEnd: false,
|
|
58
|
+
outstandingRequests: 0,
|
|
59
|
+
errored: false,
|
|
60
|
+
aborted: false,
|
|
61
|
+
promiseLibrary: this.bucket.s.promiseLibrary
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
if (!this.bucket.s.calledOpenUploadStream) {
|
|
65
|
+
this.bucket.s.calledOpenUploadStream = true;
|
|
66
|
+
|
|
67
|
+
var _this = this;
|
|
68
|
+
checkIndexes(this, function() {
|
|
69
|
+
_this.bucket.s.checkedIndexes = true;
|
|
70
|
+
_this.bucket.emit('index');
|
|
71
|
+
});
|
|
72
|
+
}
|
|
68
73
|
}
|
|
69
|
-
|
|
74
|
+
);
|
|
70
75
|
|
|
71
76
|
util.inherits(GridFSBucketWriteStream, stream.Writable);
|
|
72
77
|
|
|
@@ -210,7 +215,7 @@ function checkChunksIndex(_this, callback) {
|
|
|
210
215
|
_this.chunks.listIndexes().toArray(function(error, indexes) {
|
|
211
216
|
if (error) {
|
|
212
217
|
// Collection doesn't exist so create index
|
|
213
|
-
if (error.code ===
|
|
218
|
+
if (error.code === MONGODB_ERROR_CODES.NamespaceNotFound) {
|
|
214
219
|
var index = { files_id: 1, n: 1 };
|
|
215
220
|
_this.chunks.createIndex(index, { background: false, unique: true }, function(error) {
|
|
216
221
|
if (error) {
|
|
@@ -309,7 +314,7 @@ function checkIndexes(_this, callback) {
|
|
|
309
314
|
_this.files.listIndexes().toArray(function(error, indexes) {
|
|
310
315
|
if (error) {
|
|
311
316
|
// Collection doesn't exist so create index
|
|
312
|
-
if (error.code ===
|
|
317
|
+
if (error.code === MONGODB_ERROR_CODES.NamespaceNotFound) {
|
|
313
318
|
var index = { filename: 1, uploadDate: 1 };
|
|
314
319
|
_this.files.createIndex(index, { background: false }, function(error) {
|
|
315
320
|
if (error) {
|
|
@@ -539,3 +544,5 @@ function checkAborted(_this, callback) {
|
|
|
539
544
|
}
|
|
540
545
|
return false;
|
|
541
546
|
}
|
|
547
|
+
|
|
548
|
+
module.exports = GridFSBucketWriteStream;
|
package/lib/mongo_client.js
CHANGED
|
@@ -5,6 +5,7 @@ const Db = require('./db');
|
|
|
5
5
|
const EventEmitter = require('events').EventEmitter;
|
|
6
6
|
const inherits = require('util').inherits;
|
|
7
7
|
const MongoError = require('./core').MongoError;
|
|
8
|
+
const ValidServerApiVersions = require('./core').ValidServerApiVersions;
|
|
8
9
|
const deprecate = require('util').deprecate;
|
|
9
10
|
const WriteConcern = require('./write_concern');
|
|
10
11
|
const MongoDBNamespace = require('./utils').MongoDBNamespace;
|
|
@@ -156,6 +157,7 @@ const validOptions = require('./operations/connect').validOptions;
|
|
|
156
157
|
* @property {number} [numberOfRetries] (**default**: 5) The number of retries for a tailable cursor
|
|
157
158
|
* @property {boolean} [auto_reconnect] (**default**: true) Enable auto reconnecting for single server instances
|
|
158
159
|
* @property {boolean} [monitorCommands] (**default**: false) Enable command monitoring for this client
|
|
160
|
+
* @property {string|ServerApi} [serverApi] (**default**: undefined) The server API version
|
|
159
161
|
* @property {number} [minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
|
|
160
162
|
* @property {boolean} [useNewUrlParser] (**default**: true) Determines whether or not to use the new url parser. Enables the new, spec-compliant, url parser shipped in the core driver. This url parser fixes a number of problems with the original parser, and aims to outright replace that parser in the near future. Defaults to true, and must be explicitly set to false to use the legacy url parser.
|
|
161
163
|
* @property {boolean} [useUnifiedTopology] Enables the new unified topology layer
|
|
@@ -191,16 +193,38 @@ const validOptions = require('./operations/connect').validOptions;
|
|
|
191
193
|
* @param {MongoClientOptions} [options] Optional settings
|
|
192
194
|
*/
|
|
193
195
|
function MongoClient(url, options) {
|
|
196
|
+
options = options || {};
|
|
194
197
|
if (!(this instanceof MongoClient)) return new MongoClient(url, options);
|
|
195
198
|
// Set up event emitter
|
|
196
199
|
EventEmitter.call(this);
|
|
197
200
|
|
|
198
|
-
if (options
|
|
201
|
+
if (options.autoEncryption) require('./encrypter'); // Does CSFLE lib check
|
|
202
|
+
|
|
203
|
+
if (options.serverApi) {
|
|
204
|
+
const serverApiToValidate =
|
|
205
|
+
typeof options.serverApi === 'string' ? { version: options.serverApi } : options.serverApi;
|
|
206
|
+
const versionToValidate = serverApiToValidate && serverApiToValidate.version;
|
|
207
|
+
if (!versionToValidate) {
|
|
208
|
+
throw new MongoError(
|
|
209
|
+
`Invalid \`serverApi\` property; must specify a version from the following enum: ["${ValidServerApiVersions.join(
|
|
210
|
+
'", "'
|
|
211
|
+
)}"]`
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
if (!ValidServerApiVersions.some(v => v === versionToValidate)) {
|
|
215
|
+
throw new MongoError(
|
|
216
|
+
`Invalid server API version=${versionToValidate}; must be in the following enum: ["${ValidServerApiVersions.join(
|
|
217
|
+
'", "'
|
|
218
|
+
)}"]`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
options.serverApi = serverApiToValidate;
|
|
222
|
+
}
|
|
199
223
|
|
|
200
224
|
// The internal state
|
|
201
225
|
this.s = {
|
|
202
|
-
url
|
|
203
|
-
options
|
|
226
|
+
url,
|
|
227
|
+
options,
|
|
204
228
|
promiseLibrary: (options && options.promiseLibrary) || Promise,
|
|
205
229
|
dbCache: new Map(),
|
|
206
230
|
sessions: new Set(),
|
|
@@ -364,17 +388,18 @@ MongoClient.prototype.db = function(dbName, options) {
|
|
|
364
388
|
* Check if MongoClient is connected
|
|
365
389
|
*
|
|
366
390
|
* @method
|
|
391
|
+
* @deprecated
|
|
367
392
|
* @param {object} [options] Optional settings.
|
|
368
393
|
* @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
|
|
369
394
|
* @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
|
|
370
395
|
* @return {boolean}
|
|
371
396
|
*/
|
|
372
|
-
MongoClient.prototype.isConnected = function(options) {
|
|
397
|
+
MongoClient.prototype.isConnected = deprecate(function(options) {
|
|
373
398
|
options = options || {};
|
|
374
399
|
|
|
375
400
|
if (!this.topology) return false;
|
|
376
401
|
return this.topology.isConnected(options);
|
|
377
|
-
};
|
|
402
|
+
}, 'isConnected is deprecated and will be removed in the next major version');
|
|
378
403
|
|
|
379
404
|
/**
|
|
380
405
|
* Connect to MongoDB using a url as documented at
|