mongodb 3.3.0-beta1 → 3.3.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/HISTORY.md +117 -0
- package/index.js +1 -0
- package/lib/admin.js +6 -6
- package/lib/aggregation_cursor.js +180 -226
- package/lib/change_stream.js +233 -121
- package/lib/collection.js +74 -39
- package/lib/command_cursor.js +87 -165
- package/lib/core/connection/connect.js +1 -1
- package/lib/core/connection/msg.js +2 -1
- package/lib/core/connection/pool.js +66 -41
- package/lib/core/cursor.js +605 -461
- package/lib/core/error.js +70 -1
- package/lib/core/index.js +1 -1
- package/lib/core/sdam/server.js +109 -10
- package/lib/core/sdam/server_description.js +14 -0
- package/lib/core/sdam/topology.js +34 -14
- package/lib/core/sdam/topology_description.js +6 -14
- package/lib/core/sessions.js +68 -12
- package/lib/core/topologies/mongos.js +10 -3
- package/lib/core/topologies/replset.js +49 -11
- package/lib/core/topologies/server.js +38 -3
- package/lib/core/topologies/shared.js +22 -0
- package/lib/core/transactions.js +1 -0
- package/lib/core/utils.js +45 -1
- package/lib/core/wireprotocol/command.js +2 -2
- package/lib/core/wireprotocol/get_more.js +4 -0
- package/lib/core/wireprotocol/query.js +8 -1
- package/lib/cursor.js +780 -840
- package/lib/db.js +31 -73
- package/lib/error.js +10 -8
- package/lib/gridfs-stream/download.js +12 -5
- package/lib/mongo_client.js +33 -21
- package/lib/operations/aggregate.js +77 -95
- package/lib/operations/close.js +46 -0
- package/lib/operations/collection_ops.js +7 -916
- package/lib/operations/command.js +2 -1
- package/lib/operations/command_v2.js +109 -0
- package/lib/operations/common_functions.js +48 -14
- package/lib/operations/connect.js +73 -9
- package/lib/operations/count.js +8 -8
- package/lib/operations/count_documents.js +24 -29
- package/lib/operations/create_collection.js +1 -0
- package/lib/operations/cursor_ops.js +22 -32
- package/lib/operations/db_ops.js +0 -178
- package/lib/operations/distinct.js +20 -21
- package/lib/operations/drop.js +1 -0
- package/lib/operations/estimated_document_count.js +43 -18
- package/lib/operations/execute_operation.js +115 -3
- package/lib/operations/explain.js +2 -6
- package/lib/operations/find.js +35 -0
- package/lib/operations/insert_one.js +1 -37
- package/lib/operations/list_collections.js +106 -0
- package/lib/operations/list_databases.js +38 -0
- package/lib/operations/list_indexes.js +28 -52
- package/lib/operations/operation.js +7 -1
- package/lib/operations/rename.js +1 -1
- package/lib/operations/to_array.js +3 -5
- package/lib/read_concern.js +7 -1
- package/lib/topologies/mongos.js +1 -1
- package/lib/topologies/replset.js +1 -1
- package/lib/topologies/server.js +2 -2
- package/lib/topologies/topology_base.js +4 -5
- package/lib/utils.js +4 -4
- package/package.json +1 -1
- package/lib/operations/aggregate_operation.js +0 -127
- package/lib/operations/mongo_client_ops.js +0 -731
package/lib/operations/db_ops.js
CHANGED
|
@@ -55,21 +55,6 @@ const debugFields = [
|
|
|
55
55
|
'noListener'
|
|
56
56
|
];
|
|
57
57
|
|
|
58
|
-
// Filter out any write concern options
|
|
59
|
-
const illegalCommandFields = [
|
|
60
|
-
'w',
|
|
61
|
-
'wtimeout',
|
|
62
|
-
'j',
|
|
63
|
-
'fsync',
|
|
64
|
-
'autoIndexId',
|
|
65
|
-
'strict',
|
|
66
|
-
'serializeFunctions',
|
|
67
|
-
'pkFactory',
|
|
68
|
-
'raw',
|
|
69
|
-
'readPreference',
|
|
70
|
-
'session'
|
|
71
|
-
];
|
|
72
|
-
|
|
73
58
|
/**
|
|
74
59
|
* Add a user to the database.
|
|
75
60
|
* @method
|
|
@@ -177,92 +162,6 @@ function collections(db, options, callback) {
|
|
|
177
162
|
});
|
|
178
163
|
}
|
|
179
164
|
|
|
180
|
-
/**
|
|
181
|
-
* Create a new collection on a server with the specified options. Use this to create capped collections.
|
|
182
|
-
* More information about command options available at https://docs.mongodb.com/manual/reference/command/create/
|
|
183
|
-
*
|
|
184
|
-
* @method
|
|
185
|
-
* @param {Db} db The Db instance on which to create the collection.
|
|
186
|
-
* @param {string} name The collection name to create.
|
|
187
|
-
* @param {object} [options] Optional settings. See Db.prototype.createCollection for a list of options.
|
|
188
|
-
* @param {Db~collectionResultCallback} [callback] The results callback
|
|
189
|
-
*/
|
|
190
|
-
function createCollection(db, name, options, callback) {
|
|
191
|
-
let Collection = loadCollection();
|
|
192
|
-
|
|
193
|
-
// Get the write concern options
|
|
194
|
-
const finalOptions = applyWriteConcern(Object.assign({}, options), { db }, options);
|
|
195
|
-
|
|
196
|
-
// Did the user destroy the topology
|
|
197
|
-
if (db.serverConfig && db.serverConfig.isDestroyed()) {
|
|
198
|
-
return callback(new MongoError('topology was destroyed'));
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const listCollectionOptions = Object.assign({}, finalOptions, { nameOnly: true });
|
|
202
|
-
|
|
203
|
-
// Check if we have the name
|
|
204
|
-
db
|
|
205
|
-
.listCollections({ name }, listCollectionOptions)
|
|
206
|
-
.setReadPreference(ReadPreference.PRIMARY)
|
|
207
|
-
.toArray((err, collections) => {
|
|
208
|
-
if (err != null) return handleCallback(callback, err, null);
|
|
209
|
-
if (collections.length > 0 && finalOptions.strict) {
|
|
210
|
-
return handleCallback(
|
|
211
|
-
callback,
|
|
212
|
-
MongoError.create({
|
|
213
|
-
message: `Collection ${name} already exists. Currently in strict mode.`,
|
|
214
|
-
driver: true
|
|
215
|
-
}),
|
|
216
|
-
null
|
|
217
|
-
);
|
|
218
|
-
} else if (collections.length > 0) {
|
|
219
|
-
try {
|
|
220
|
-
return handleCallback(
|
|
221
|
-
callback,
|
|
222
|
-
null,
|
|
223
|
-
new Collection(db, db.s.topology, db.databaseName, name, db.s.pkFactory, options)
|
|
224
|
-
);
|
|
225
|
-
} catch (err) {
|
|
226
|
-
return handleCallback(callback, err);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Create collection command
|
|
231
|
-
const cmd = { create: name };
|
|
232
|
-
|
|
233
|
-
// Decorate command with writeConcern if supported
|
|
234
|
-
applyWriteConcern(cmd, { db }, options);
|
|
235
|
-
|
|
236
|
-
// Add all optional parameters
|
|
237
|
-
for (let n in options) {
|
|
238
|
-
if (
|
|
239
|
-
options[n] != null &&
|
|
240
|
-
typeof options[n] !== 'function' &&
|
|
241
|
-
illegalCommandFields.indexOf(n) === -1
|
|
242
|
-
) {
|
|
243
|
-
cmd[n] = options[n];
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Force a primary read Preference
|
|
248
|
-
finalOptions.readPreference = ReadPreference.PRIMARY;
|
|
249
|
-
// Execute command
|
|
250
|
-
executeCommand(db, cmd, finalOptions, err => {
|
|
251
|
-
if (err) return handleCallback(callback, err);
|
|
252
|
-
|
|
253
|
-
try {
|
|
254
|
-
return handleCallback(
|
|
255
|
-
callback,
|
|
256
|
-
null,
|
|
257
|
-
new Collection(db, db.s.topology, db.databaseName, name, db.s.pkFactory, options)
|
|
258
|
-
);
|
|
259
|
-
} catch (err) {
|
|
260
|
-
return handleCallback(callback, err);
|
|
261
|
-
}
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
|
|
266
165
|
/**
|
|
267
166
|
* Creates an index on the db and collection.
|
|
268
167
|
* @method
|
|
@@ -586,23 +485,6 @@ function indexInformation(db, name, options, callback) {
|
|
|
586
485
|
});
|
|
587
486
|
}
|
|
588
487
|
|
|
589
|
-
// Transformation methods for cursor results
|
|
590
|
-
function listCollectionsTransforms(databaseName) {
|
|
591
|
-
const matching = `${databaseName}.`;
|
|
592
|
-
|
|
593
|
-
return {
|
|
594
|
-
doc: doc => {
|
|
595
|
-
const index = doc.name.indexOf(matching);
|
|
596
|
-
// Remove database name if available
|
|
597
|
-
if (doc.name && index === 0) {
|
|
598
|
-
doc.name = doc.name.substr(index + matching.length);
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
return doc;
|
|
602
|
-
}
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
|
|
606
488
|
/**
|
|
607
489
|
* Retrieve the current profiling information for MongoDB
|
|
608
490
|
*
|
|
@@ -623,28 +505,6 @@ function profilingInfo(db, options, callback) {
|
|
|
623
505
|
}
|
|
624
506
|
}
|
|
625
507
|
|
|
626
|
-
/**
|
|
627
|
-
* Retrieve the current profiling level for MongoDB
|
|
628
|
-
*
|
|
629
|
-
* @method
|
|
630
|
-
* @param {Db} db The Db instance on which to retrieve the profiling level.
|
|
631
|
-
* @param {Object} [options] Optional settings. See Db.prototype.profilingLevel for a list of options.
|
|
632
|
-
* @param {Db~resultCallback} [callback] The command result callback
|
|
633
|
-
*/
|
|
634
|
-
function profilingLevel(db, options, callback) {
|
|
635
|
-
executeCommand(db, { profile: -1 }, options, (err, doc) => {
|
|
636
|
-
if (err == null && doc.ok === 1) {
|
|
637
|
-
const was = doc.was;
|
|
638
|
-
if (was === 0) return callback(null, 'off');
|
|
639
|
-
if (was === 1) return callback(null, 'slow_only');
|
|
640
|
-
if (was === 2) return callback(null, 'all');
|
|
641
|
-
return callback(new Error('Error: illegal profiling level value ' + was), null);
|
|
642
|
-
} else {
|
|
643
|
-
err != null ? callback(err, null) : callback(new Error('Error with profile command'), null);
|
|
644
|
-
}
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
|
|
648
508
|
/**
|
|
649
509
|
* Remove a user from a database
|
|
650
510
|
*
|
|
@@ -683,40 +543,6 @@ function removeUser(db, username, options, callback) {
|
|
|
683
543
|
});
|
|
684
544
|
}
|
|
685
545
|
|
|
686
|
-
/**
|
|
687
|
-
* Set the current profiling level of MongoDB
|
|
688
|
-
*
|
|
689
|
-
* @method
|
|
690
|
-
* @param {Db} db The Db instance on which to execute the command.
|
|
691
|
-
* @param {string} level The new profiling level (off, slow_only, all).
|
|
692
|
-
* @param {Object} [options] Optional settings. See Db.prototype.setProfilingLevel for a list of options.
|
|
693
|
-
* @param {Db~resultCallback} [callback] The command result callback.
|
|
694
|
-
*/
|
|
695
|
-
function setProfilingLevel(db, level, options, callback) {
|
|
696
|
-
const command = {};
|
|
697
|
-
let profile = 0;
|
|
698
|
-
|
|
699
|
-
if (level === 'off') {
|
|
700
|
-
profile = 0;
|
|
701
|
-
} else if (level === 'slow_only') {
|
|
702
|
-
profile = 1;
|
|
703
|
-
} else if (level === 'all') {
|
|
704
|
-
profile = 2;
|
|
705
|
-
} else {
|
|
706
|
-
return callback(new Error('Error: illegal profiling level value ' + level));
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
// Set up the profile number
|
|
710
|
-
command['profile'] = profile;
|
|
711
|
-
|
|
712
|
-
executeCommand(db, command, options, (err, doc) => {
|
|
713
|
-
if (err == null && doc.ok === 1) return callback(null, level);
|
|
714
|
-
return err != null
|
|
715
|
-
? callback(err, null)
|
|
716
|
-
: callback(new Error('Error with profile command'), null);
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
|
|
720
546
|
// Validate the database name
|
|
721
547
|
function validateDatabaseName(databaseName) {
|
|
722
548
|
if (typeof databaseName !== 'string')
|
|
@@ -990,7 +816,6 @@ function executeAuthRemoveUserCommand(db, username, options, callback) {
|
|
|
990
816
|
module.exports = {
|
|
991
817
|
addUser,
|
|
992
818
|
collections,
|
|
993
|
-
createCollection,
|
|
994
819
|
createListener,
|
|
995
820
|
createIndex,
|
|
996
821
|
dropCollection,
|
|
@@ -999,11 +824,8 @@ module.exports = {
|
|
|
999
824
|
evaluate,
|
|
1000
825
|
executeCommand,
|
|
1001
826
|
executeDbAdminCommand,
|
|
1002
|
-
listCollectionsTransforms,
|
|
1003
827
|
indexInformation,
|
|
1004
828
|
profilingInfo,
|
|
1005
|
-
profilingLevel,
|
|
1006
829
|
removeUser,
|
|
1007
|
-
setProfilingLevel,
|
|
1008
830
|
validateDatabaseName
|
|
1009
831
|
};
|
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const Aspect = require('./operation').Aspect;
|
|
4
4
|
const defineAspects = require('./operation').defineAspects;
|
|
5
|
-
const
|
|
5
|
+
const CommandOperationV2 = require('./command_v2');
|
|
6
6
|
const decorateWithCollation = require('../utils').decorateWithCollation;
|
|
7
7
|
const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
|
|
8
|
-
const executeCommand = require('./db_ops').executeCommand;
|
|
9
|
-
const handleCallback = require('../utils').handleCallback;
|
|
10
|
-
const resolveReadPreference = require('../utils').resolveReadPreference;
|
|
11
8
|
|
|
12
9
|
/**
|
|
13
10
|
* Return a list of distinct values for the given key across a collection.
|
|
@@ -18,7 +15,7 @@ const resolveReadPreference = require('../utils').resolveReadPreference;
|
|
|
18
15
|
* @property {object} query The query for filtering the set of documents to which we apply the distinct filter.
|
|
19
16
|
* @property {object} [options] Optional settings. See Collection.prototype.distinct for a list of options.
|
|
20
17
|
*/
|
|
21
|
-
class DistinctOperation extends
|
|
18
|
+
class DistinctOperation extends CommandOperationV2 {
|
|
22
19
|
/**
|
|
23
20
|
* Construct a Distinct operation.
|
|
24
21
|
*
|
|
@@ -28,7 +25,7 @@ class DistinctOperation extends OperationBase {
|
|
|
28
25
|
* @param {object} [options] Optional settings. See Collection.prototype.distinct for a list of options.
|
|
29
26
|
*/
|
|
30
27
|
constructor(collection, key, query, options) {
|
|
31
|
-
super(options);
|
|
28
|
+
super(collection, options);
|
|
32
29
|
|
|
33
30
|
this.collection = collection;
|
|
34
31
|
this.key = key;
|
|
@@ -40,14 +37,11 @@ class DistinctOperation extends OperationBase {
|
|
|
40
37
|
*
|
|
41
38
|
* @param {Collection~resultCallback} [callback] The command result callback
|
|
42
39
|
*/
|
|
43
|
-
execute(callback) {
|
|
40
|
+
execute(server, callback) {
|
|
44
41
|
const coll = this.collection;
|
|
45
42
|
const key = this.key;
|
|
46
43
|
const query = this.query;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// maxTimeMS option
|
|
50
|
-
const maxTimeMS = options.maxTimeMS;
|
|
44
|
+
const options = this.options;
|
|
51
45
|
|
|
52
46
|
// Distinct command
|
|
53
47
|
const cmd = {
|
|
@@ -56,12 +50,10 @@ class DistinctOperation extends OperationBase {
|
|
|
56
50
|
query: query
|
|
57
51
|
};
|
|
58
52
|
|
|
59
|
-
options = Object.assign({}, options);
|
|
60
|
-
// Ensure we have the right read preference inheritance
|
|
61
|
-
options.readPreference = resolveReadPreference(coll, options);
|
|
62
|
-
|
|
63
53
|
// Add maxTimeMS if defined
|
|
64
|
-
if (typeof maxTimeMS === 'number')
|
|
54
|
+
if (typeof options.maxTimeMS === 'number') {
|
|
55
|
+
cmd.maxTimeMS = options.maxTimeMS;
|
|
56
|
+
}
|
|
65
57
|
|
|
66
58
|
// Do we have a readConcern specified
|
|
67
59
|
decorateWithReadConcern(cmd, coll, options);
|
|
@@ -73,14 +65,21 @@ class DistinctOperation extends OperationBase {
|
|
|
73
65
|
return callback(err, null);
|
|
74
66
|
}
|
|
75
67
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
68
|
+
super.executeCommand(server, cmd, (err, result) => {
|
|
69
|
+
if (err) {
|
|
70
|
+
callback(err);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
callback(null, this.options.full ? result : result.values);
|
|
80
75
|
});
|
|
81
76
|
}
|
|
82
77
|
}
|
|
83
78
|
|
|
84
|
-
defineAspects(DistinctOperation,
|
|
79
|
+
defineAspects(DistinctOperation, [
|
|
80
|
+
Aspect.READ_OPERATION,
|
|
81
|
+
Aspect.RETRYABLE,
|
|
82
|
+
Aspect.EXECUTE_WITH_SELECTION
|
|
83
|
+
]);
|
|
85
84
|
|
|
86
85
|
module.exports = DistinctOperation;
|
package/lib/operations/drop.js
CHANGED
|
@@ -2,32 +2,57 @@
|
|
|
2
2
|
|
|
3
3
|
const Aspect = require('./operation').Aspect;
|
|
4
4
|
const defineAspects = require('./operation').defineAspects;
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
const CommandOperationV2 = require('./command_v2');
|
|
6
|
+
|
|
7
|
+
class EstimatedDocumentCountOperation extends CommandOperationV2 {
|
|
8
|
+
constructor(collection, query, options) {
|
|
9
|
+
if (typeof options === 'undefined') {
|
|
10
|
+
options = query;
|
|
11
|
+
query = undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
super(collection, options);
|
|
15
|
+
this.collectionName = collection.s.namespace.collection;
|
|
16
|
+
if (query) {
|
|
17
|
+
this.query = query;
|
|
18
|
+
}
|
|
12
19
|
}
|
|
13
20
|
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
21
|
+
execute(server, callback) {
|
|
22
|
+
const options = this.options;
|
|
23
|
+
const cmd = { count: this.collectionName };
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
if (this.query) {
|
|
26
|
+
cmd.query = this.query;
|
|
27
|
+
}
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
|
|
29
|
+
if (typeof options.skip === 'number') {
|
|
30
|
+
cmd.skip = options.skip;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (typeof options.limit === 'number') {
|
|
34
|
+
cmd.limit = options.limit;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (options.hint) {
|
|
38
|
+
cmd.hint = options.hint;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
super.executeCommand(server, cmd, (err, response) => {
|
|
42
|
+
if (err) {
|
|
43
|
+
callback(err);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
22
46
|
|
|
23
|
-
|
|
24
|
-
super.execute((err, result) => {
|
|
25
|
-
if (err) return handleCallback(callback, err);
|
|
26
|
-
handleCallback(callback, null, result.n);
|
|
47
|
+
callback(null, response.n);
|
|
27
48
|
});
|
|
28
49
|
}
|
|
29
50
|
}
|
|
30
51
|
|
|
31
|
-
defineAspects(EstimatedDocumentCountOperation,
|
|
52
|
+
defineAspects(EstimatedDocumentCountOperation, [
|
|
53
|
+
Aspect.READ_OPERATION,
|
|
54
|
+
Aspect.RETRYABLE,
|
|
55
|
+
Aspect.EXECUTE_WITH_SELECTION
|
|
56
|
+
]);
|
|
32
57
|
|
|
33
58
|
module.exports = EstimatedDocumentCountOperation;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const MongoError = require('../core').MongoError;
|
|
3
|
+
const MongoError = require('../core/error').MongoError;
|
|
4
4
|
const Aspect = require('./operation').Aspect;
|
|
5
5
|
const OperationBase = require('./operation').OperationBase;
|
|
6
|
+
const ReadPreference = require('../core/topologies/read_preference');
|
|
7
|
+
const isRetryableError = require('../core/error').isRetryableError;
|
|
8
|
+
const maxWireVersion = require('../core/utils').maxWireVersion;
|
|
9
|
+
const isUnifiedTopology = require('../core/utils').isUnifiedTopology;
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* Executes the given operation with provided arguments.
|
|
@@ -26,6 +30,14 @@ function executeOperation(topology, operation, callback) {
|
|
|
26
30
|
throw new TypeError('This method requires a valid operation instance');
|
|
27
31
|
}
|
|
28
32
|
|
|
33
|
+
if (
|
|
34
|
+
isUnifiedTopology(topology) &&
|
|
35
|
+
!operation.hasAspect(Aspect.SKIP_SESSION) &&
|
|
36
|
+
topology.shouldCheckForSessionSupport()
|
|
37
|
+
) {
|
|
38
|
+
return selectServerForSessionSupport(topology, operation, callback);
|
|
39
|
+
}
|
|
40
|
+
|
|
29
41
|
const Promise = topology.s.promiseLibrary;
|
|
30
42
|
|
|
31
43
|
// The driver sessions spec mandates that we implicitly create sessions for operations
|
|
@@ -65,7 +77,11 @@ function executeOperation(topology, operation, callback) {
|
|
|
65
77
|
);
|
|
66
78
|
|
|
67
79
|
try {
|
|
68
|
-
|
|
80
|
+
if (operation.hasAspect(Aspect.EXECUTE_WITH_SELECTION)) {
|
|
81
|
+
return executeWithServerSelection(topology, operation, handler);
|
|
82
|
+
} else {
|
|
83
|
+
return operation.execute(handler);
|
|
84
|
+
}
|
|
69
85
|
} catch (e) {
|
|
70
86
|
handler(e);
|
|
71
87
|
throw e;
|
|
@@ -76,11 +92,107 @@ function executeOperation(topology, operation, callback) {
|
|
|
76
92
|
const handler = makeExecuteCallback(resolve, reject);
|
|
77
93
|
|
|
78
94
|
try {
|
|
79
|
-
|
|
95
|
+
if (operation.hasAspect(Aspect.EXECUTE_WITH_SELECTION)) {
|
|
96
|
+
return executeWithServerSelection(topology, operation, handler);
|
|
97
|
+
} else {
|
|
98
|
+
return operation.execute(handler);
|
|
99
|
+
}
|
|
80
100
|
} catch (e) {
|
|
81
101
|
handler(e);
|
|
82
102
|
}
|
|
83
103
|
});
|
|
84
104
|
}
|
|
85
105
|
|
|
106
|
+
function supportsRetryableReads(server) {
|
|
107
|
+
return maxWireVersion(server) >= 6;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function executeWithServerSelection(topology, operation, callback) {
|
|
111
|
+
const readPreference = operation.readPreference || ReadPreference.primary;
|
|
112
|
+
const inTransaction = operation.session && operation.session.inTransaction();
|
|
113
|
+
|
|
114
|
+
if (inTransaction && !readPreference.equals(ReadPreference.primary)) {
|
|
115
|
+
callback(
|
|
116
|
+
new MongoError(
|
|
117
|
+
`Read preference in a transaction must be primary, not: ${readPreference.mode}`
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const serverSelectionOptions = {
|
|
125
|
+
readPreference,
|
|
126
|
+
session: operation.session
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
function callbackWithRetry(err, result) {
|
|
130
|
+
if (err == null) {
|
|
131
|
+
return callback(null, result);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!isRetryableError(err)) {
|
|
135
|
+
return callback(err);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// select a new server, and attempt to retry the operation
|
|
139
|
+
topology.selectServer(serverSelectionOptions, (err, server) => {
|
|
140
|
+
if (err || !supportsRetryableReads(server)) {
|
|
141
|
+
callback(err, null);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
operation.execute(server, callback);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// select a server, and execute the operation against it
|
|
150
|
+
topology.selectServer(serverSelectionOptions, (err, server) => {
|
|
151
|
+
if (err) {
|
|
152
|
+
callback(err, null);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const shouldRetryReads =
|
|
157
|
+
topology.s.options.retryReads !== false &&
|
|
158
|
+
(operation.session && !inTransaction) &&
|
|
159
|
+
supportsRetryableReads(server) &&
|
|
160
|
+
operation.canRetryRead;
|
|
161
|
+
|
|
162
|
+
if (operation.hasAspect(Aspect.RETRYABLE) && shouldRetryReads) {
|
|
163
|
+
operation.execute(server, callbackWithRetry);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
operation.execute(server, callback);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// TODO: This is only supported for unified topology, it should go away once
|
|
172
|
+
// we remove support for legacy topology types.
|
|
173
|
+
function selectServerForSessionSupport(topology, operation, callback) {
|
|
174
|
+
const Promise = topology.s.promiseLibrary;
|
|
175
|
+
|
|
176
|
+
let result;
|
|
177
|
+
if (typeof callback !== 'function') {
|
|
178
|
+
result = new Promise((resolve, reject) => {
|
|
179
|
+
callback = (err, result) => {
|
|
180
|
+
if (err) return reject(err);
|
|
181
|
+
resolve(result);
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
topology.selectServer(ReadPreference.primaryPreferred, err => {
|
|
187
|
+
if (err) {
|
|
188
|
+
callback(err);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
executeOperation(topology, operation, callback);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
197
|
+
|
|
86
198
|
module.exports = executeOperation;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const Aspect = require('./operation').Aspect;
|
|
4
|
-
const CoreCursor = require('../core').
|
|
4
|
+
const CoreCursor = require('../core/cursor').CoreCursor;
|
|
5
5
|
const defineAspects = require('./operation').defineAspects;
|
|
6
6
|
const OperationBase = require('./operation').OperationBase;
|
|
7
7
|
|
|
@@ -14,11 +14,7 @@ class ExplainOperation extends OperationBase {
|
|
|
14
14
|
|
|
15
15
|
execute() {
|
|
16
16
|
const cursor = this.cursor;
|
|
17
|
-
|
|
18
|
-
if (cursor._initImplicitSession) {
|
|
19
|
-
cursor._initImplicitSession();
|
|
20
|
-
}
|
|
21
|
-
return CoreCursor.prototype.next.apply(cursor, arguments);
|
|
17
|
+
return CoreCursor.prototype._next.apply(cursor, arguments);
|
|
22
18
|
}
|
|
23
19
|
}
|
|
24
20
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const OperationBase = require('./operation').OperationBase;
|
|
4
|
+
const Aspect = require('./operation').Aspect;
|
|
5
|
+
const defineAspects = require('./operation').defineAspects;
|
|
6
|
+
const resolveReadPreference = require('../utils').resolveReadPreference;
|
|
7
|
+
|
|
8
|
+
class FindOperation extends OperationBase {
|
|
9
|
+
constructor(collection, ns, command, options) {
|
|
10
|
+
super(options);
|
|
11
|
+
|
|
12
|
+
this.ns = ns;
|
|
13
|
+
this.cmd = command;
|
|
14
|
+
this.readPreference = resolveReadPreference(collection, this.options);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
execute(server, callback) {
|
|
18
|
+
// copied from `CommandOperationV2`, to be subclassed in the future
|
|
19
|
+
this.server = server;
|
|
20
|
+
|
|
21
|
+
const cursorState = this.cursorState || {};
|
|
22
|
+
|
|
23
|
+
// TOOD: use `MongoDBNamespace` through and through
|
|
24
|
+
server.query(this.ns.toString(), this.cmd, cursorState, this.options, callback);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
defineAspects(FindOperation, [
|
|
29
|
+
Aspect.READ_OPERATION,
|
|
30
|
+
Aspect.RETRYABLE,
|
|
31
|
+
Aspect.EXECUTE_WITH_SELECTION,
|
|
32
|
+
Aspect.SKIP_SESSION
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
module.exports = FindOperation;
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const applyRetryableWrites = require('../utils').applyRetryableWrites;
|
|
4
|
-
const applyWriteConcern = require('../utils').applyWriteConcern;
|
|
5
|
-
const handleCallback = require('../utils').handleCallback;
|
|
6
3
|
const MongoError = require('../core').MongoError;
|
|
7
4
|
const OperationBase = require('./operation').OperationBase;
|
|
8
|
-
const
|
|
9
|
-
const toError = require('../utils').toError;
|
|
5
|
+
const insertDocuments = require('./common_functions').insertDocuments;
|
|
10
6
|
|
|
11
7
|
class InsertOneOperation extends OperationBase {
|
|
12
8
|
constructor(collection, doc, options) {
|
|
@@ -40,36 +36,4 @@ class InsertOneOperation extends OperationBase {
|
|
|
40
36
|
}
|
|
41
37
|
}
|
|
42
38
|
|
|
43
|
-
function insertDocuments(coll, docs, options, callback) {
|
|
44
|
-
if (typeof options === 'function') (callback = options), (options = {});
|
|
45
|
-
options = options || {};
|
|
46
|
-
// Ensure we are operating on an array op docs
|
|
47
|
-
docs = Array.isArray(docs) ? docs : [docs];
|
|
48
|
-
|
|
49
|
-
// Final options for retryable writes and write concern
|
|
50
|
-
let finalOptions = Object.assign({}, options);
|
|
51
|
-
finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
|
|
52
|
-
finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
|
|
53
|
-
|
|
54
|
-
// If keep going set unordered
|
|
55
|
-
if (finalOptions.keepGoing === true) finalOptions.ordered = false;
|
|
56
|
-
finalOptions.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions;
|
|
57
|
-
|
|
58
|
-
docs = prepareDocs(coll, docs, options);
|
|
59
|
-
|
|
60
|
-
// File inserts
|
|
61
|
-
coll.s.topology.insert(coll.s.namespace, docs, finalOptions, (err, result) => {
|
|
62
|
-
if (callback == null) return;
|
|
63
|
-
if (err) return handleCallback(callback, err);
|
|
64
|
-
if (result == null) return handleCallback(callback, null, null);
|
|
65
|
-
if (result.result.code) return handleCallback(callback, toError(result.result));
|
|
66
|
-
if (result.result.writeErrors)
|
|
67
|
-
return handleCallback(callback, toError(result.result.writeErrors[0]));
|
|
68
|
-
// Add docs to the list
|
|
69
|
-
result.ops = docs;
|
|
70
|
-
// Return the results
|
|
71
|
-
handleCallback(callback, null, result);
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
39
|
module.exports = InsertOneOperation;
|