mongodb 3.6.10 → 3.7.1

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.
Files changed (44) hide show
  1. package/index.js +4 -0
  2. package/lib/bulk/common.js +6 -3
  3. package/lib/cmap/connection.js +34 -7
  4. package/lib/cmap/connection_pool.js +4 -2
  5. package/lib/collection.js +1 -1
  6. package/lib/core/auth/mongo_credentials.js +4 -1
  7. package/lib/core/auth/mongodb_aws.js +17 -15
  8. package/lib/core/auth/scram.js +1 -0
  9. package/lib/core/connection/connect.js +22 -5
  10. package/lib/core/connection/connection.js +2 -0
  11. package/lib/core/connection/pool.js +1 -0
  12. package/lib/core/connection/utils.js +35 -2
  13. package/lib/core/error.js +46 -46
  14. package/lib/core/index.js +10 -0
  15. package/lib/core/sdam/monitor.js +16 -2
  16. package/lib/core/sdam/server.js +2 -0
  17. package/lib/core/sdam/server_description.js +4 -0
  18. package/lib/core/sdam/topology.js +10 -2
  19. package/lib/core/sessions.js +11 -8
  20. package/lib/core/topologies/replset_state.js +5 -3
  21. package/lib/core/topologies/shared.js +4 -1
  22. package/lib/core/transactions.js +5 -1
  23. package/lib/core/uri_parser.js +14 -0
  24. package/lib/core/utils.js +1 -0
  25. package/lib/core/wireprotocol/command.js +24 -0
  26. package/lib/core/wireprotocol/kill_cursors.js +7 -2
  27. package/lib/core/wireprotocol/query.js +9 -5
  28. package/lib/cursor.js +4 -0
  29. package/lib/db.js +1 -0
  30. package/lib/encrypter.js +8 -3
  31. package/lib/error.js +21 -20
  32. package/lib/error_codes.js +36 -0
  33. package/lib/explain.js +5 -12
  34. package/lib/gridfs-stream/index.js +39 -24
  35. package/lib/gridfs-stream/upload.js +53 -46
  36. package/lib/mongo_client.js +30 -5
  37. package/lib/operations/connect.js +1 -0
  38. package/lib/operations/db_ops.js +10 -7
  39. package/lib/operations/estimated_document_count.js +47 -18
  40. package/lib/topologies/native_topology.js +4 -0
  41. package/lib/url_parser.js +8 -0
  42. package/lib/utils.js +10 -1
  43. package/package.json +7 -3
  44. package/HISTORY.md +0 -2900
@@ -1,14 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var core = require('../core');
4
- var crypto = require('crypto');
5
- var stream = require('stream');
6
- var util = require('util');
7
- var Buffer = require('safe-buffer').Buffer;
8
-
9
- var ERROR_NAMESPACE_NOT_FOUND = 26;
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
- function GridFSBucketWriteStream(bucket, filename, options) {
35
- options = options || {};
36
- stream.Writable.call(this, options);
37
- this.bucket = bucket;
38
- this.chunks = bucket.s._chunksCollection;
39
- this.filename = filename;
40
- this.files = bucket.s._filesCollection;
41
- this.options = options;
42
- // Signals the write is all done
43
- this.done = false;
44
-
45
- this.id = options.id ? options.id : core.BSON.ObjectId();
46
- this.chunkSizeBytes = this.options.chunkSizeBytes;
47
- this.bufToStore = Buffer.alloc(this.chunkSizeBytes);
48
- this.length = 0;
49
- this.md5 = !options.disableMD5 && crypto.createHash('md5');
50
- this.n = 0;
51
- this.pos = 0;
52
- this.state = {
53
- streamEnd: false,
54
- outstandingRequests: 0,
55
- errored: false,
56
- aborted: false,
57
- promiseLibrary: this.bucket.s.promiseLibrary
58
- };
59
-
60
- if (!this.bucket.s.calledOpenUploadStream) {
61
- this.bucket.s.calledOpenUploadStream = true;
62
-
63
- var _this = this;
64
- checkIndexes(this, function() {
65
- _this.bucket.s.checkedIndexes = true;
66
- _this.bucket.emit('index');
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 === ERROR_NAMESPACE_NOT_FOUND) {
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 === ERROR_NAMESPACE_NOT_FOUND) {
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;
@@ -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 && options.autoEncryption) require('./encrypter'); // Does CSFLE lib check
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: url,
203
- options: 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
@@ -138,6 +138,7 @@ const validOptionNames = [
138
138
  'auto_reconnect',
139
139
  'minSize',
140
140
  'monitorCommands',
141
+ 'serverApi',
141
142
  'retryWrites',
142
143
  'retryReads',
143
144
  'useNewUrlParser',
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const MONGODB_ERROR_CODES = require('../error_codes').MONGODB_ERROR_CODES;
3
4
  const applyWriteConcern = require('../utils').applyWriteConcern;
4
5
  const Code = require('../core').BSON.Code;
5
6
  const debugOptions = require('../utils').debugOptions;
@@ -75,12 +76,12 @@ function createIndex(db, name, fieldOrSpec, options, callback) {
75
76
  * 197 = 'InvalidIndexSpecificationOption' (`_id` with `background: true`)
76
77
  */
77
78
  if (
78
- err.code === 67 ||
79
- err.code === 11000 ||
80
- err.code === 85 ||
81
- err.code === 86 ||
82
- err.code === 11600 ||
83
- err.code === 197
79
+ err.code === MONGODB_ERROR_CODES.CannotCreateIndex ||
80
+ err.code === MONGODB_ERROR_CODES.DuplicateKey ||
81
+ err.code === MONGODB_ERROR_CODES.IndexOptionsConflict ||
82
+ err.code === MONGODB_ERROR_CODES.IndexKeySpecsConflict ||
83
+ err.code === MONGODB_ERROR_CODES.InterruptedAtShutdown ||
84
+ err.code === MONGODB_ERROR_CODES.InvalidIndexSpecificationOption
84
85
  ) {
85
86
  return handleCallback(callback, err, result);
86
87
  }
@@ -147,7 +148,9 @@ function ensureIndex(db, name, fieldOrSpec, options, callback) {
147
148
 
148
149
  // Check if the index already exists
149
150
  indexInformation(db, name, finalOptions, (err, indexInformation) => {
150
- if (err != null && err.code !== 26) return handleCallback(callback, err, null);
151
+ if (err != null && err.code !== MONGODB_ERROR_CODES.NamespaceNotFound) {
152
+ return handleCallback(callback, err, null);
153
+ }
151
154
  // If the index does not exist, create it
152
155
  if (indexInformation == null || !indexInformation[index_name]) {
153
156
  createIndex(db, name, fieldOrSpec, options, callback);
@@ -1,43 +1,72 @@
1
1
  'use strict';
2
2
 
3
+ const MONGODB_ERROR_CODES = require('../error_codes').MONGODB_ERROR_CODES;
3
4
  const Aspect = require('./operation').Aspect;
4
5
  const defineAspects = require('./operation').defineAspects;
5
6
  const CommandOperationV2 = require('./command_v2');
7
+ const maxWireVersion = require('../core/utils').maxWireVersion;
8
+ const CountDocumentsOperation = require('./count_documents');
6
9
 
7
10
  class EstimatedDocumentCountOperation extends CommandOperationV2 {
8
- constructor(collection, query, options) {
9
- if (typeof options === 'undefined') {
10
- options = query;
11
- query = undefined;
12
- }
13
-
11
+ constructor(collection, options) {
14
12
  super(collection, options);
13
+ this.collection = collection;
15
14
  this.collectionName = collection.s.namespace.collection;
16
- if (query) {
17
- this.query = query;
18
- }
19
15
  }
20
16
 
21
17
  execute(server, callback) {
22
- const options = this.options;
23
- const cmd = { count: this.collectionName };
18
+ if (maxWireVersion(server) < 12) {
19
+ return this.executeLegacy(server, callback);
20
+ }
21
+ // if the user specifies a filter, use a CountDocumentsOperation instead
22
+ if (this.options.query) {
23
+ const op = new CountDocumentsOperation(this.collection, this.options.query, this.options);
24
+ return op.execute(server, callback);
25
+ }
26
+ const pipeline = [{ $collStats: { count: {} } }, { $group: { _id: 1, n: { $sum: '$count' } } }];
27
+ const cmd = { aggregate: this.collectionName, pipeline, cursor: {} };
24
28
 
25
- if (this.query) {
26
- cmd.query = this.query;
29
+ if (typeof this.options.maxTimeMS === 'number') {
30
+ cmd.maxTimeMS = this.options.maxTimeMS;
27
31
  }
28
32
 
33
+ super.executeCommand(server, cmd, (err, response) => {
34
+ if (err && err.code !== MONGODB_ERROR_CODES.NamespaceNotFound) {
35
+ callback(err);
36
+ return;
37
+ }
38
+
39
+ callback(
40
+ undefined,
41
+ (response &&
42
+ response.cursor &&
43
+ response.cursor.firstBatch &&
44
+ response.cursor.firstBatch[0].n) ||
45
+ 0
46
+ );
47
+ });
48
+ }
49
+
50
+ executeLegacy(server, callback) {
51
+ const cmd = { count: this.collectionName };
52
+
53
+ const options = this.options;
54
+ if (options.query) {
55
+ cmd.query = options.query;
56
+ }
57
+ if (options.hint) {
58
+ cmd.hint = options.hint;
59
+ }
60
+ if (typeof options.maxTimeMS === 'number') {
61
+ cmd.maxTimeMS = options.maxTimeMS;
62
+ }
29
63
  if (typeof options.skip === 'number') {
30
64
  cmd.skip = options.skip;
31
65
  }
32
-
33
66
  if (typeof options.limit === 'number') {
34
67
  cmd.limit = options.limit;
35
68
  }
36
69
 
37
- if (options.hint) {
38
- cmd.hint = options.hint;
39
- }
40
-
41
70
  super.executeCommand(server, cmd, (err, response) => {
42
71
  if (err) {
43
72
  callback(err);
@@ -44,6 +44,10 @@ class NativeTopology extends Topology {
44
44
  // Translate all the options to the core types
45
45
  clonedOptions = translateOptions(clonedOptions, socketOptions);
46
46
 
47
+ clonedOptions.serverApi = options.serverApi;
48
+
49
+ clonedOptions.useUnifiedTopology = options.useUnifiedTopology;
50
+
47
51
  super(servers, clonedOptions);
48
52
  }
49
53
 
package/lib/url_parser.js CHANGED
@@ -101,6 +101,9 @@ module.exports = function(url, options, callback) {
101
101
  record = record[0].join('');
102
102
  const parsedRecord = qs.parse(record);
103
103
  const items = Object.keys(parsedRecord);
104
+ if (Object.keys(items).some(k => k.toLowerCase() === 'loadbalanced')) {
105
+ return callback(new MongoParseError('Load balancer mode requires driver version 4+'));
106
+ }
104
107
  if (items.some(item => item !== 'authSource' && item !== 'replicaSet')) {
105
108
  return callback(
106
109
  new MongoParseError('Text record must only set `authSource` or `replicaSet`')
@@ -378,6 +381,11 @@ function parseConnectionString(url, options) {
378
381
  object.dbName = dbName || 'admin';
379
382
  // Split up all the options
380
383
  urlOptions = (query_string_part || '').split(/[&;]/);
384
+
385
+ if (urlOptions.some(k => k.toLowerCase() === 'loadbalanced')) {
386
+ throw new MongoParseError('Load balancer mode requires driver version 4+');
387
+ }
388
+
381
389
  // Ugh, we have to figure out which options go to which constructor manually.
382
390
  urlOptions.forEach(function(opt) {
383
391
  if (!opt) return;
package/lib/utils.js CHANGED
@@ -946,6 +946,14 @@ function deepCopy(value) {
946
946
 
947
947
  return value;
948
948
  }
949
+ /**
950
+ * @param {{version: string}} pkg
951
+ * @returns {{ major: number; minor: number; patch: number }}
952
+ */
953
+ function parsePackageVersion(pkg) {
954
+ const versionParts = pkg.version.split('.').map(n => Number.parseInt(n, 10));
955
+ return { major: versionParts[0], minor: versionParts[1], patch: versionParts[2] };
956
+ }
949
957
 
950
958
  module.exports = {
951
959
  filterOptions,
@@ -984,5 +992,6 @@ module.exports = {
984
992
  MONGODB_WARNING_CODE,
985
993
  emitWarning,
986
994
  emitWarningOnce,
987
- deepCopy
995
+ deepCopy,
996
+ parsePackageVersion
988
997
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mongodb",
3
- "version": "3.6.10",
3
+ "version": "3.7.1",
4
4
  "description": "The official MongoDB driver for Node.js",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -16,6 +16,10 @@
16
16
  "driver",
17
17
  "official"
18
18
  ],
19
+ "author": {
20
+ "name": "The MongoDB NodeJS Team",
21
+ "email": "dbx-node@mongodb.com"
22
+ },
19
23
  "peerDependenciesMeta": {
20
24
  "kerberos": {
21
25
  "optional": true
@@ -83,7 +87,7 @@
83
87
  "node": ">=4"
84
88
  },
85
89
  "bugs": {
86
- "url": "https://github.com/mongodb/node-mongodb-native/issues"
90
+ "url": "https://jira.mongodb.org/projects/NODE/issues/"
87
91
  },
88
92
  "scripts": {
89
93
  "build:evergreen": "node .evergreen/generate_evergreen_tasks.js",
@@ -98,7 +102,7 @@
98
102
  "check:tls": "mocha --opts '{}' test/manual/tls_support.test.js",
99
103
  "format": "npm run check:lint -- --fix",
100
104
  "release": "standard-version -i HISTORY.md",
101
- "test": "npm run lint && mocha --recursive test/functional test/unit"
105
+ "test": "npm run check:lint && mocha --recursive test/functional test/unit"
102
106
  },
103
107
  "homepage": "https://github.com/mongodb/node-mongodb-native",
104
108
  "optionalDependencies": {