mongodb 3.5.3 → 3.5.7

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/lib/cursor.js CHANGED
@@ -9,16 +9,12 @@ const MongoError = require('./core').MongoError;
9
9
  const CoreCursor = require('./core/cursor').CoreCursor;
10
10
  const CursorState = require('./core/cursor').CursorState;
11
11
  const Map = require('./core').BSON.Map;
12
+ const maybePromise = require('./utils').maybePromise;
13
+ const executeOperation = require('./operations/execute_operation');
14
+ const formattedOrderClause = require('./utils').formattedOrderClause;
12
15
 
13
16
  const each = require('./operations/cursor_ops').each;
14
-
15
17
  const CountOperation = require('./operations/count');
16
- const ExplainOperation = require('./operations/explain');
17
- const HasNextOperation = require('./operations/has_next');
18
- const NextOperation = require('./operations/next');
19
- const ToArrayOperation = require('./operations/to_array');
20
-
21
- const executeOperation = require('./operations/execute_operation');
22
18
 
23
19
  /**
24
20
  * @fileOverview The **Cursor** class is an internal class that embodies a cursor on MongoDB
@@ -128,8 +124,6 @@ class Cursor extends CoreCursor {
128
124
  state: CursorState.INIT,
129
125
  // Promise library
130
126
  promiseLibrary,
131
- // Current doc
132
- currentDoc: null,
133
127
  // explicitlyIgnoreSession
134
128
  explicitlyIgnoreSession: !!options.explicitlyIgnoreSession
135
129
  };
@@ -199,9 +193,33 @@ class Cursor extends CoreCursor {
199
193
  * @return {Promise} returns Promise if no callback passed
200
194
  */
201
195
  hasNext(callback) {
202
- const hasNextOperation = new HasNextOperation(this);
196
+ if (this.s.state === CursorState.CLOSED || (this.isDead && this.isDead())) {
197
+ throw MongoError.create({ message: 'Cursor is closed', driver: true });
198
+ }
199
+
200
+ return maybePromise(this, callback, cb => {
201
+ const cursor = this;
202
+ if (cursor.isNotified()) {
203
+ return cb(null, false);
204
+ }
203
205
 
204
- return executeOperation(this.topology, hasNextOperation, callback);
206
+ cursor._next((err, doc) => {
207
+ if (err) return cb(err);
208
+ if (doc == null || cursor.s.state === Cursor.CLOSED || cursor.isDead()) {
209
+ return cb(null, false);
210
+ }
211
+
212
+ cursor.s.state = CursorState.OPEN;
213
+
214
+ // NODE-2482: merge this into the core cursor implementation
215
+ cursor.cursorState.cursorIndex--;
216
+ if (cursor.cursorState.limit > 0) {
217
+ cursor.cursorState.currentLimit--;
218
+ }
219
+
220
+ cb(null, true);
221
+ });
222
+ });
205
223
  }
206
224
 
207
225
  /**
@@ -212,9 +230,27 @@ class Cursor extends CoreCursor {
212
230
  * @return {Promise} returns Promise if no callback passed
213
231
  */
214
232
  next(callback) {
215
- const nextOperation = new NextOperation(this);
233
+ return maybePromise(this, callback, cb => {
234
+ const cursor = this;
235
+ if (cursor.s.state === CursorState.CLOSED || (cursor.isDead && cursor.isDead())) {
236
+ cb(MongoError.create({ message: 'Cursor is closed', driver: true }));
237
+ return;
238
+ }
216
239
 
217
- return executeOperation(this.topology, nextOperation, callback);
240
+ if (cursor.s.state === CursorState.INIT && cursor.cmd.sort) {
241
+ try {
242
+ cursor.cmd.sort = formattedOrderClause(cursor.cmd.sort);
243
+ } catch (err) {
244
+ return cb(err);
245
+ }
246
+ }
247
+
248
+ cursor._next((err, doc) => {
249
+ if (err) return cb(err);
250
+ cursor.s.state = CursorState.OPEN;
251
+ cb(null, doc);
252
+ });
253
+ });
218
254
  }
219
255
 
220
256
  /**
@@ -784,9 +820,43 @@ class Cursor extends CoreCursor {
784
820
  });
785
821
  }
786
822
 
787
- const toArrayOperation = new ToArrayOperation(this);
823
+ return maybePromise(this, callback, cb => {
824
+ const cursor = this;
825
+ const items = [];
826
+
827
+ // Reset cursor
828
+ cursor.rewind();
829
+ cursor.s.state = CursorState.INIT;
830
+
831
+ // Fetch all the documents
832
+ const fetchDocs = () => {
833
+ cursor._next((err, doc) => {
834
+ if (err) {
835
+ return cursor._endSession
836
+ ? cursor._endSession(() => handleCallback(cb, err))
837
+ : handleCallback(cb, err);
838
+ }
839
+
840
+ if (doc == null) {
841
+ return cursor.close({ skipKillCursors: true }, () => handleCallback(cb, null, items));
842
+ }
843
+
844
+ // Add doc to items
845
+ items.push(doc);
846
+
847
+ // Get all buffered objects
848
+ if (cursor.bufferedCount() > 0) {
849
+ let docs = cursor.readBufferedDocuments(cursor.bufferedCount());
850
+ Array.prototype.push.apply(items, docs);
851
+ }
852
+
853
+ // Attempt a fetch
854
+ fetchDocs();
855
+ });
856
+ };
788
857
 
789
- return executeOperation(this.topology, toArrayOperation, callback);
858
+ fetchDocs();
859
+ });
790
860
  }
791
861
 
792
862
  /**
@@ -971,10 +1041,9 @@ class Cursor extends CoreCursor {
971
1041
  if (this.cmd.readConcern) {
972
1042
  delete this.cmd['readConcern'];
973
1043
  }
974
-
975
- const explainOperation = new ExplainOperation(this);
976
-
977
- return executeOperation(this.topology, explainOperation, callback);
1044
+ return maybePromise(this, callback, cb => {
1045
+ CoreCursor.prototype._next.apply(this, [cb]);
1046
+ });
978
1047
  }
979
1048
 
980
1049
  /**
@@ -3,17 +3,16 @@
3
3
  const ChangeStream = require('./change_stream');
4
4
  const Db = require('./db');
5
5
  const EventEmitter = require('events').EventEmitter;
6
- const executeOperation = require('./operations/execute_operation');
7
6
  const inherits = require('util').inherits;
8
7
  const MongoError = require('./core').MongoError;
9
8
  const deprecate = require('util').deprecate;
10
9
  const WriteConcern = require('./write_concern');
11
10
  const MongoDBNamespace = require('./utils').MongoDBNamespace;
12
11
  const ReadPreference = require('./core/topologies/read_preference');
13
-
14
- // Operations
15
- const ConnectOperation = require('./operations/connect');
16
- const CloseOperation = require('./operations/close');
12
+ const maybePromise = require('./utils').maybePromise;
13
+ const NativeTopology = require('./topologies/native_topology');
14
+ const connect = require('./operations/connect').connect;
15
+ const validOptions = require('./operations/connect').validOptions;
17
16
 
18
17
  /**
19
18
  * @fileOverview The **MongoClient** class is a class that allows for making Connections to MongoDB.
@@ -144,6 +143,9 @@ const CloseOperation = require('./operations/close');
144
143
  * @param {number} [options.minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
145
144
  * @param {boolean} [options.useNewUrlParser=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.
146
145
  * @param {boolean} [options.useUnifiedTopology] Enables the new unified topology layer
146
+ * @param {Number} [options.localThresholdMS=15] **Only applies to the unified topology** The size of the latency window for selecting among multiple suitable servers
147
+ * @param {Number} [options.serverSelectionTimeoutMS=30000] **Only applies to the unified topology** How long to block for server selection before throwing an error
148
+ * @param {Number} [options.heartbeatFrequencyMS=10000] **Only applies to the unified topology** The frequency with which topology updates are scheduled
147
149
  * @param {AutoEncrypter~AutoEncryptionOptions} [options.autoEncryption] Optionally enable client side auto encryption
148
150
  * @param {DriverInfoOptions} [options.driverInfo] Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver
149
151
  * @param {MongoClient~connectCallback} [callback] The command result callback
@@ -158,18 +160,12 @@ function MongoClient(url, options) {
158
160
  this.s = {
159
161
  url: url,
160
162
  options: options || {},
161
- promiseLibrary: null,
163
+ promiseLibrary: (options && options.promiseLibrary) || Promise,
162
164
  dbCache: new Map(),
163
165
  sessions: new Set(),
164
166
  writeConcern: WriteConcern.fromOptions(options),
165
167
  namespace: new MongoDBNamespace('admin')
166
168
  };
167
-
168
- // Get the promiseLibrary
169
- const promiseLibrary = this.s.options.promiseLibrary || Promise;
170
-
171
- // Add the promise to the internal state
172
- this.s.promiseLibrary = promiseLibrary;
173
169
  }
174
170
 
175
171
  /**
@@ -214,9 +210,16 @@ MongoClient.prototype.connect = function(callback) {
214
210
  throw new TypeError('`connect` only accepts a callback');
215
211
  }
216
212
 
217
- const operation = new ConnectOperation(this);
213
+ const client = this;
214
+ return maybePromise(this, callback, cb => {
215
+ const err = validOptions(client.s.options);
216
+ if (err) return cb(err);
218
217
 
219
- return executeOperation(this, operation, callback);
218
+ connect(client, client.s.url, client.s.options, err => {
219
+ if (err) return cb(err);
220
+ cb(null, client);
221
+ });
222
+ });
220
223
  };
221
224
 
222
225
  MongoClient.prototype.logout = deprecate(function(options, callback) {
@@ -232,9 +235,41 @@ MongoClient.prototype.logout = deprecate(function(options, callback) {
232
235
  * @return {Promise} returns Promise if no callback passed
233
236
  */
234
237
  MongoClient.prototype.close = function(force, callback) {
235
- if (typeof force === 'function') (callback = force), (force = false);
236
- const operation = new CloseOperation(this, force);
237
- return executeOperation(this, operation, callback);
238
+ if (typeof force === 'function') {
239
+ callback = force;
240
+ force = false;
241
+ }
242
+
243
+ const client = this;
244
+ return maybePromise(this, callback, cb => {
245
+ const completeClose = err => {
246
+ client.emit('close', client);
247
+
248
+ if (!(client.topology instanceof NativeTopology)) {
249
+ for (const item of client.s.dbCache) {
250
+ item[1].emit('close', client);
251
+ }
252
+ }
253
+
254
+ client.removeAllListeners('close');
255
+ cb(err);
256
+ };
257
+
258
+ if (client.topology == null) {
259
+ completeClose();
260
+ return;
261
+ }
262
+
263
+ client.topology.close(force, err => {
264
+ const autoEncrypter = client.topology.s.options.autoEncrypter;
265
+ if (!autoEncrypter) {
266
+ completeClose(err);
267
+ return;
268
+ }
269
+
270
+ autoEncrypter.teardown(force, err2 => completeClose(err || err2));
271
+ });
272
+ });
238
273
  };
239
274
 
240
275
  /**
@@ -312,7 +347,7 @@ MongoClient.prototype.isConnected = function(options) {
312
347
  * @param {object} [options] Optional settings
313
348
  * @param {number} [options.poolSize=5] The maximum size of the individual server pool
314
349
  * @param {boolean} [options.ssl=false] Enable SSL connection. *deprecated* use `tls` variants
315
- * @param {boolean} [options.sslValidate=false] Validate mongod server certificate against Certificate Authority *deprecated* use `tls` variants
350
+ * @param {boolean} [options.sslValidate=false] Validate mongod server certificate against Certificate Authority
316
351
  * @param {buffer} [options.sslCA=undefined] SSL Certificate store binary buffer *deprecated* use `tls` variants
317
352
  * @param {buffer} [options.sslCert=undefined] SSL Certificate binary buffer *deprecated* use `tls` variants
318
353
  * @param {buffer} [options.sslKey=undefined] SSL Key file binary buffer *deprecated* use `tls` variants
@@ -329,7 +364,7 @@ MongoClient.prototype.isConnected = function(options) {
329
364
  * @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
330
365
  * @param {boolean} [options.noDelay=true] TCP Connection no delay
331
366
  * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
332
- * @param {boolean} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
367
+ * @param {number} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
333
368
  * @param {number} [options.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
334
369
  * @param {number} [options.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
335
370
  * @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
@@ -373,7 +408,15 @@ MongoClient.prototype.isConnected = function(options) {
373
408
  * @param {array} [options.readPreferenceTags] Read preference tags
374
409
  * @param {number} [options.numberOfRetries=5] The number of retries for a tailable cursor
375
410
  * @param {boolean} [options.auto_reconnect=true] Enable auto reconnecting for single server instances
411
+ * @param {boolean} [options.monitorCommands=false] Enable command monitoring for this client
376
412
  * @param {number} [options.minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
413
+ * @param {boolean} [options.useNewUrlParser=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.
414
+ * @param {boolean} [options.useUnifiedTopology] Enables the new unified topology layer
415
+ * @param {Number} [options.localThresholdMS=15] **Only applies to the unified topology** The size of the latency window for selecting among multiple suitable servers
416
+ * @param {Number} [options.serverSelectionTimeoutMS=30000] **Only applies to the unified topology** How long to block for server selection before throwing an error
417
+ * @param {Number} [options.heartbeatFrequencyMS=10000] **Only applies to the unified topology** The frequency with which topology updates are scheduled
418
+ * @param {AutoEncrypter~AutoEncryptionOptions} [options.autoEncryption] Optionally enable client side auto encryption
419
+ * @param {DriverInfoOptions} [options.driverInfo] Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver
377
420
  * @param {MongoClient~connectCallback} [callback] The command result callback
378
421
  * @return {Promise<MongoClient>} returns Promise if no callback passed
379
422
  */
@@ -1,8 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const OperationBase = require('./operation').OperationBase;
4
- const defineAspects = require('./operation').defineAspects;
5
- const Aspect = require('./operation').Aspect;
6
3
  const deprecate = require('util').deprecate;
7
4
  const Logger = require('../core').Logger;
8
5
  const MongoCredentials = require('../core').MongoCredentials;
@@ -191,28 +188,6 @@ const LEGACY_OPTIONS_MAP = validOptionNames.reduce((obj, name) => {
191
188
  return obj;
192
189
  }, {});
193
190
 
194
- class ConnectOperation extends OperationBase {
195
- constructor(mongoClient) {
196
- super();
197
-
198
- this.mongoClient = mongoClient;
199
- }
200
-
201
- execute(callback) {
202
- const mongoClient = this.mongoClient;
203
- const err = validOptions(mongoClient.s.options);
204
-
205
- // Did we have a validation error
206
- if (err) return callback(err);
207
- // Fallback to callback based connect
208
- connect(mongoClient, mongoClient.s.url, mongoClient.s.options, err => {
209
- if (err) return callback(err);
210
- callback(null, mongoClient);
211
- });
212
- }
213
- }
214
- defineAspects(ConnectOperation, [Aspect.SKIP_SESSION]);
215
-
216
191
  function addListeners(mongoClient, topology) {
217
192
  topology.on('authenticated', createListener(mongoClient, 'authenticated'));
218
193
  topology.on('error', createListener(mongoClient, 'error'));
@@ -820,4 +795,4 @@ function translateOptions(options, translationOptions) {
820
795
  });
821
796
  }
822
797
 
823
- module.exports = ConnectOperation;
798
+ module.exports = { validOptions, connect };
@@ -1,8 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const Aspect = require('./operation').Aspect;
4
3
  const buildCountCommand = require('./common_functions').buildCountCommand;
5
- const defineAspects = require('./operation').defineAspects;
6
4
  const OperationBase = require('./operation').OperationBase;
7
5
 
8
6
  class CountOperation extends OperationBase {
@@ -67,6 +65,4 @@ class CountOperation extends OperationBase {
67
65
  }
68
66
  }
69
67
 
70
- defineAspects(CountOperation, Aspect.SKIP_SESSION);
71
-
72
68
  module.exports = CountOperation;
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const buildCountCommand = require('./collection_ops').buildCountCommand;
4
- const formattedOrderClause = require('../utils').formattedOrderClause;
5
4
  const handleCallback = require('../utils').handleCallback;
6
5
  const MongoError = require('../core').MongoError;
7
6
  const push = Array.prototype.push;
@@ -106,34 +105,6 @@ function each(cursor, callback) {
106
105
  }
107
106
  }
108
107
 
109
- /**
110
- * Check if there is any document still available in the cursor.
111
- *
112
- * @method
113
- * @param {Cursor} cursor The Cursor instance on which to run.
114
- * @param {Cursor~resultCallback} [callback] The result callback.
115
- */
116
- function hasNext(cursor, callback) {
117
- if (cursor.s.currentDoc) {
118
- return callback(null, true);
119
- }
120
-
121
- if (cursor.isNotified()) {
122
- return callback(null, false);
123
- }
124
-
125
- nextObject(cursor, (err, doc) => {
126
- if (err) return callback(err, null);
127
- if (cursor.s.state === CursorState.CLOSED || cursor.isDead()) {
128
- return callback(null, false);
129
- }
130
-
131
- if (!doc) return callback(null, false);
132
- cursor.s.currentDoc = doc;
133
- callback(null, true);
134
- });
135
- }
136
-
137
108
  // Trampoline emptying the number of retrieved items
138
109
  // without incurring a nextTick operation
139
110
  function loop(cursor, callback) {
@@ -145,48 +116,6 @@ function loop(cursor, callback) {
145
116
  return loop;
146
117
  }
147
118
 
148
- /**
149
- * Get the next available document from the cursor. Returns null if no more documents are available.
150
- *
151
- * @method
152
- * @param {Cursor} cursor The Cursor instance from which to get the next document.
153
- * @param {Cursor~resultCallback} [callback] The result callback.
154
- */
155
- function next(cursor, callback) {
156
- // Return the currentDoc if someone called hasNext first
157
- if (cursor.s.currentDoc) {
158
- const doc = cursor.s.currentDoc;
159
- cursor.s.currentDoc = null;
160
- return callback(null, doc);
161
- }
162
-
163
- // Return the next object
164
- nextObject(cursor, callback);
165
- }
166
-
167
- // Get the next available document from the cursor, returns null if no more documents are available.
168
- function nextObject(cursor, callback) {
169
- if (cursor.s.state === CursorState.CLOSED || (cursor.isDead && cursor.isDead()))
170
- return handleCallback(
171
- callback,
172
- MongoError.create({ message: 'Cursor is closed', driver: true })
173
- );
174
- if (cursor.s.state === CursorState.INIT && cursor.cmd.sort) {
175
- try {
176
- cursor.cmd.sort = formattedOrderClause(cursor.cmd.sort);
177
- } catch (err) {
178
- return handleCallback(callback, err);
179
- }
180
- }
181
-
182
- // Get the next object
183
- cursor._next((err, doc) => {
184
- cursor.s.state = CursorState.OPEN;
185
- if (err) return handleCallback(callback, err);
186
- handleCallback(callback, null, doc);
187
- });
188
- }
189
-
190
119
  /**
191
120
  * Returns an array of documents. See Cursor.prototype.toArray for more information.
192
121
  *
@@ -236,4 +165,4 @@ function toArray(cursor, callback) {
236
165
  fetchDocs();
237
166
  }
238
167
 
239
- module.exports = { count, each, hasNext, next, toArray };
168
+ module.exports = { count, each, toArray };