mongodb 3.2.5 → 3.3.0-beta2
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 +0 -10
- package/index.js +4 -4
- package/lib/admin.js +56 -56
- package/lib/aggregation_cursor.js +7 -3
- package/lib/bulk/common.js +18 -13
- package/lib/change_stream.js +196 -89
- package/lib/collection.js +217 -169
- package/lib/command_cursor.js +17 -7
- package/lib/core/auth/auth_provider.js +158 -0
- package/lib/core/auth/defaultAuthProviders.js +29 -0
- package/lib/core/auth/gssapi.js +241 -0
- package/lib/core/auth/mongo_credentials.js +81 -0
- package/lib/core/auth/mongocr.js +51 -0
- package/lib/core/auth/plain.js +35 -0
- package/lib/core/auth/scram.js +293 -0
- package/lib/core/auth/sspi.js +131 -0
- package/lib/core/auth/x509.js +26 -0
- package/lib/core/connection/apm.js +236 -0
- package/lib/core/connection/command_result.js +36 -0
- package/lib/core/connection/commands.js +507 -0
- package/lib/core/connection/connect.js +370 -0
- package/lib/core/connection/connection.js +624 -0
- package/lib/core/connection/logger.js +246 -0
- package/lib/core/connection/msg.js +219 -0
- package/lib/core/connection/pool.js +1285 -0
- package/lib/core/connection/utils.js +57 -0
- package/lib/core/cursor.js +752 -0
- package/lib/core/error.js +186 -0
- package/lib/core/index.js +50 -0
- package/lib/core/sdam/monitoring.js +228 -0
- package/lib/core/sdam/server.js +467 -0
- package/lib/core/sdam/server_description.js +163 -0
- package/lib/core/sdam/server_selectors.js +244 -0
- package/lib/core/sdam/srv_polling.js +135 -0
- package/lib/core/sdam/topology.js +1151 -0
- package/lib/core/sdam/topology_description.js +408 -0
- package/lib/core/sessions.js +711 -0
- package/lib/core/tools/smoke_plugin.js +61 -0
- package/lib/core/topologies/mongos.js +1337 -0
- package/lib/core/topologies/read_preference.js +202 -0
- package/lib/core/topologies/replset.js +1507 -0
- package/lib/core/topologies/replset_state.js +1121 -0
- package/lib/core/topologies/server.js +984 -0
- package/lib/core/topologies/shared.js +453 -0
- package/lib/core/transactions.js +167 -0
- package/lib/core/uri_parser.js +631 -0
- package/lib/core/utils.js +165 -0
- package/lib/core/wireprotocol/command.js +170 -0
- package/lib/core/wireprotocol/compression.js +73 -0
- package/lib/core/wireprotocol/constants.js +13 -0
- package/lib/core/wireprotocol/get_more.js +86 -0
- package/lib/core/wireprotocol/index.js +18 -0
- package/lib/core/wireprotocol/kill_cursors.js +70 -0
- package/lib/core/wireprotocol/query.js +224 -0
- package/lib/core/wireprotocol/shared.js +115 -0
- package/lib/core/wireprotocol/write_command.js +50 -0
- package/lib/cursor.js +40 -46
- package/lib/db.js +141 -95
- package/lib/dynamic_loaders.js +32 -0
- package/lib/error.js +12 -10
- package/lib/gridfs/chunk.js +2 -2
- package/lib/gridfs/grid_store.js +31 -25
- package/lib/gridfs-stream/index.js +4 -4
- package/lib/gridfs-stream/upload.js +1 -1
- package/lib/mongo_client.js +37 -15
- package/lib/operations/add_user.js +96 -0
- package/lib/operations/aggregate.js +24 -13
- package/lib/operations/aggregate_operation.js +127 -0
- package/lib/operations/bulk_write.js +104 -0
- package/lib/operations/close.js +47 -0
- package/lib/operations/collection_ops.js +28 -287
- package/lib/operations/collections.js +55 -0
- package/lib/operations/command.js +120 -0
- package/lib/operations/command_v2.js +43 -0
- package/lib/operations/common_functions.js +372 -0
- package/lib/operations/{mongo_client_ops.js → connect.js} +185 -157
- package/lib/operations/count.js +72 -0
- package/lib/operations/count_documents.js +46 -0
- package/lib/operations/create_collection.js +118 -0
- package/lib/operations/create_index.js +92 -0
- package/lib/operations/create_indexes.js +61 -0
- package/lib/operations/cursor_ops.js +3 -4
- package/lib/operations/db_ops.js +15 -12
- package/lib/operations/delete_many.js +25 -0
- package/lib/operations/delete_one.js +25 -0
- package/lib/operations/distinct.js +85 -0
- package/lib/operations/drop.js +53 -0
- package/lib/operations/drop_index.js +42 -0
- package/lib/operations/drop_indexes.js +23 -0
- package/lib/operations/estimated_document_count.js +33 -0
- package/lib/operations/execute_db_admin_command.js +34 -0
- package/lib/operations/execute_operation.js +165 -0
- package/lib/operations/explain.js +23 -0
- package/lib/operations/find_and_modify.js +98 -0
- package/lib/operations/find_one.js +33 -0
- package/lib/operations/find_one_and_delete.js +16 -0
- package/lib/operations/find_one_and_replace.js +18 -0
- package/lib/operations/find_one_and_update.js +19 -0
- package/lib/operations/geo_haystack_search.js +79 -0
- package/lib/operations/has_next.js +40 -0
- package/lib/operations/index_exists.js +39 -0
- package/lib/operations/index_information.js +23 -0
- package/lib/operations/indexes.js +22 -0
- package/lib/operations/insert_many.js +63 -0
- package/lib/operations/insert_one.js +75 -0
- package/lib/operations/is_capped.js +19 -0
- package/lib/operations/list_indexes.js +66 -0
- package/lib/operations/map_reduce.js +189 -0
- package/lib/operations/next.js +32 -0
- package/lib/operations/operation.js +63 -0
- package/lib/operations/options_operation.js +32 -0
- package/lib/operations/profiling_level.js +31 -0
- package/lib/operations/re_index.js +28 -0
- package/lib/operations/remove_user.js +52 -0
- package/lib/operations/rename.js +61 -0
- package/lib/operations/replace_one.js +47 -0
- package/lib/operations/set_profiling_level.js +48 -0
- package/lib/operations/stats.js +45 -0
- package/lib/operations/to_array.js +68 -0
- package/lib/operations/update_many.js +29 -0
- package/lib/operations/update_one.js +44 -0
- package/lib/operations/validate_collection.js +40 -0
- package/lib/read_concern.js +55 -0
- package/lib/topologies/mongos.js +3 -3
- package/lib/topologies/native_topology.js +22 -2
- package/lib/topologies/replset.js +3 -3
- package/lib/topologies/server.js +4 -4
- package/lib/topologies/topology_base.js +6 -6
- package/lib/url_parser.js +4 -3
- package/lib/utils.js +46 -59
- package/lib/write_concern.js +66 -0
- package/package.json +15 -6
- package/lib/.DS_Store +0 -0
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const OperationBase = require('./operation').OperationBase;
|
|
5
|
+
const defineAspects = require('./operation').defineAspects;
|
|
6
|
+
const Aspect = require('./operation').Aspect;
|
|
3
7
|
const deprecate = require('util').deprecate;
|
|
4
|
-
const Logger = require('
|
|
5
|
-
const
|
|
8
|
+
const Logger = require('../core').Logger;
|
|
9
|
+
const MongoCredentials = require('../core').MongoCredentials;
|
|
10
|
+
const MongoError = require('../core').MongoError;
|
|
6
11
|
const Mongos = require('../topologies/mongos');
|
|
7
|
-
const
|
|
8
|
-
const
|
|
12
|
+
const NativeTopology = require('../topologies/native_topology');
|
|
13
|
+
const parse = require('../core').parseConnectionString;
|
|
14
|
+
const ReadConcern = require('../read_concern');
|
|
15
|
+
const ReadPreference = require('../core').ReadPreference;
|
|
9
16
|
const ReplSet = require('../topologies/replset');
|
|
10
17
|
const Server = require('../topologies/server');
|
|
11
|
-
const ServerSessionPool = require('
|
|
12
|
-
const NativeTopology = require('../topologies/native_topology');
|
|
13
|
-
const MongoCredentials = require('mongodb-core').MongoCredentials;
|
|
18
|
+
const ServerSessionPool = require('../core').Sessions.ServerSessionPool;
|
|
14
19
|
|
|
15
20
|
let client;
|
|
16
21
|
function loadClient() {
|
|
@@ -20,6 +25,21 @@ function loadClient() {
|
|
|
20
25
|
return client;
|
|
21
26
|
}
|
|
22
27
|
|
|
28
|
+
const legacyParse = deprecate(
|
|
29
|
+
require('../url_parser'),
|
|
30
|
+
'current URL string parser is deprecated, and will be removed in a future version. ' +
|
|
31
|
+
'To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.'
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const AUTH_MECHANISM_INTERNAL_MAP = {
|
|
35
|
+
DEFAULT: 'default',
|
|
36
|
+
'MONGODB-CR': 'mongocr',
|
|
37
|
+
PLAIN: 'plain',
|
|
38
|
+
'MONGODB-X509': 'x509',
|
|
39
|
+
'SCRAM-SHA-1': 'scram-sha-1',
|
|
40
|
+
'SCRAM-SHA-256': 'scram-sha-256'
|
|
41
|
+
};
|
|
42
|
+
|
|
23
43
|
const monitoringEvents = [
|
|
24
44
|
'timeout',
|
|
25
45
|
'close',
|
|
@@ -43,13 +63,17 @@ const monitoringEvents = [
|
|
|
43
63
|
'fullsetup',
|
|
44
64
|
'open'
|
|
45
65
|
];
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
'
|
|
51
|
-
|
|
52
|
-
|
|
66
|
+
|
|
67
|
+
const VALID_AUTH_MECHANISMS = new Set([
|
|
68
|
+
'DEFAULT',
|
|
69
|
+
'MONGODB-CR',
|
|
70
|
+
'PLAIN',
|
|
71
|
+
'MONGODB-X509',
|
|
72
|
+
'SCRAM-SHA-1',
|
|
73
|
+
'SCRAM-SHA-256',
|
|
74
|
+
'GSSAPI'
|
|
75
|
+
]);
|
|
76
|
+
|
|
53
77
|
const validOptionNames = [
|
|
54
78
|
'poolSize',
|
|
55
79
|
'ssl',
|
|
@@ -109,12 +133,70 @@ const validOptionNames = [
|
|
|
109
133
|
'minSize',
|
|
110
134
|
'monitorCommands',
|
|
111
135
|
'retryWrites',
|
|
136
|
+
'retryReads',
|
|
112
137
|
'useNewUrlParser',
|
|
113
138
|
'useUnifiedTopology',
|
|
114
139
|
'serverSelectionTimeoutMS',
|
|
115
|
-
'useRecoveryToken'
|
|
140
|
+
'useRecoveryToken',
|
|
141
|
+
'autoEncryption'
|
|
116
142
|
];
|
|
117
143
|
|
|
144
|
+
const ignoreOptionNames = ['native_parser'];
|
|
145
|
+
const legacyOptionNames = ['server', 'replset', 'replSet', 'mongos', 'db'];
|
|
146
|
+
|
|
147
|
+
// Validate options object
|
|
148
|
+
function validOptions(options) {
|
|
149
|
+
const _validOptions = validOptionNames.concat(legacyOptionNames);
|
|
150
|
+
|
|
151
|
+
for (const name in options) {
|
|
152
|
+
if (ignoreOptionNames.indexOf(name) !== -1) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (_validOptions.indexOf(name) === -1) {
|
|
157
|
+
if (options.validateOptions) {
|
|
158
|
+
return new MongoError(`option ${name} is not supported`);
|
|
159
|
+
} else {
|
|
160
|
+
console.warn(`the options [${name}] is not supported`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (legacyOptionNames.indexOf(name) !== -1) {
|
|
165
|
+
console.warn(
|
|
166
|
+
`the server/replset/mongos/db options are deprecated, ` +
|
|
167
|
+
`all their options are supported at the top level of the options object [${validOptionNames}]`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const LEGACY_OPTIONS_MAP = validOptionNames.reduce((obj, name) => {
|
|
174
|
+
obj[name.toLowerCase()] = name;
|
|
175
|
+
return obj;
|
|
176
|
+
}, {});
|
|
177
|
+
|
|
178
|
+
class ConnectOperation extends OperationBase {
|
|
179
|
+
constructor(mongoClient) {
|
|
180
|
+
super();
|
|
181
|
+
|
|
182
|
+
this.mongoClient = mongoClient;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
execute(callback) {
|
|
186
|
+
const mongoClient = this.mongoClient;
|
|
187
|
+
const err = validOptions(mongoClient.s.options);
|
|
188
|
+
|
|
189
|
+
// Did we have a validation error
|
|
190
|
+
if (err) return callback(err);
|
|
191
|
+
// Fallback to callback based connect
|
|
192
|
+
connect(mongoClient, mongoClient.s.url, mongoClient.s.options, err => {
|
|
193
|
+
if (err) return callback(err);
|
|
194
|
+
callback(null, mongoClient);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
defineAspects(ConnectOperation, [Aspect.SKIP_SESSION]);
|
|
199
|
+
|
|
118
200
|
function addListeners(mongoClient, topology) {
|
|
119
201
|
topology.on('authenticated', createListener(mongoClient, 'authenticated'));
|
|
120
202
|
topology.on('error', createListener(mongoClient, 'error'));
|
|
@@ -160,19 +242,6 @@ function collectEvents(mongoClient, topology) {
|
|
|
160
242
|
return collectedEvents;
|
|
161
243
|
}
|
|
162
244
|
|
|
163
|
-
/**
|
|
164
|
-
* Connect to MongoDB using a url as documented at
|
|
165
|
-
*
|
|
166
|
-
* docs.mongodb.org/manual/reference/connection-string/
|
|
167
|
-
*
|
|
168
|
-
* Note that for replicasets the replicaSet query parameter is required in the 2.0 driver
|
|
169
|
-
*
|
|
170
|
-
* @method
|
|
171
|
-
* @param {MongoClient} mongoClient The MongoClient instance with which to connect.
|
|
172
|
-
* @param {string} url The connection URI string
|
|
173
|
-
* @param {object} [options] Optional settings. See MongoClient.prototype.connect for a list of options.
|
|
174
|
-
* @param {MongoClient~connectCallback} [callback] The command result callback
|
|
175
|
-
*/
|
|
176
245
|
function connect(mongoClient, url, options, callback) {
|
|
177
246
|
options = Object.assign({}, options);
|
|
178
247
|
|
|
@@ -205,6 +274,8 @@ function connect(mongoClient, url, options, callback) {
|
|
|
205
274
|
// Check if we have connection and socket timeout set
|
|
206
275
|
if (_finalOptions.socketTimeoutMS == null) _finalOptions.socketTimeoutMS = 360000;
|
|
207
276
|
if (_finalOptions.connectTimeoutMS == null) _finalOptions.connectTimeoutMS = 30000;
|
|
277
|
+
if (_finalOptions.retryWrites == null) _finalOptions.retryWrites = true;
|
|
278
|
+
if (_finalOptions.useRecoveryToken == null) _finalOptions.useRecoveryToken = true;
|
|
208
279
|
|
|
209
280
|
if (_finalOptions.db_options && _finalOptions.db_options.auth) {
|
|
210
281
|
delete _finalOptions.db_options.auth;
|
|
@@ -266,27 +337,6 @@ function connect(mongoClient, url, options, callback) {
|
|
|
266
337
|
}
|
|
267
338
|
}
|
|
268
339
|
|
|
269
|
-
/**
|
|
270
|
-
* Connect to MongoDB using a url as documented at
|
|
271
|
-
*
|
|
272
|
-
* docs.mongodb.org/manual/reference/connection-string/
|
|
273
|
-
*
|
|
274
|
-
* Note that for replicasets the replicaSet query parameter is required in the 2.0 driver
|
|
275
|
-
*
|
|
276
|
-
* @method
|
|
277
|
-
* @param {MongoClient} mongoClient The MongoClient instance with which to connect.
|
|
278
|
-
* @param {MongoClient~connectCallback} [callback] The command result callback
|
|
279
|
-
*/
|
|
280
|
-
function connectOp(mongoClient, err, callback) {
|
|
281
|
-
// Did we have a validation error
|
|
282
|
-
if (err) return callback(err);
|
|
283
|
-
// Fallback to callback based connect
|
|
284
|
-
connect(mongoClient, mongoClient.s.url, mongoClient.s.options, err => {
|
|
285
|
-
if (err) return callback(err);
|
|
286
|
-
callback(null, mongoClient);
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
340
|
function connectWithUrl(mongoClient, url, options, connectCallback) {
|
|
291
341
|
// Set the topology
|
|
292
342
|
assignTopology(mongoClient, url);
|
|
@@ -414,7 +464,50 @@ function createTopology(mongoClient, topologyType, options, callback) {
|
|
|
414
464
|
}
|
|
415
465
|
|
|
416
466
|
assignTopology(mongoClient, newTopology);
|
|
417
|
-
|
|
467
|
+
if (options.autoEncryption == null) {
|
|
468
|
+
callback(null, newTopology);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// setup for client side encryption
|
|
473
|
+
let AutoEncrypter;
|
|
474
|
+
try {
|
|
475
|
+
AutoEncrypter = require('mongodb-client-encryption').AutoEncrypter;
|
|
476
|
+
} catch (err) {
|
|
477
|
+
callback(
|
|
478
|
+
new MongoError(
|
|
479
|
+
'Auto-encryption requested, but the module is not installed. Please add `mongodb-client-encryption` as a dependency of your project'
|
|
480
|
+
)
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const MongoClient = loadClient();
|
|
487
|
+
let connectionString;
|
|
488
|
+
if (options.autoEncryption.extraOptions && options.autoEncryption.extraOptions.mongocryptURI) {
|
|
489
|
+
connectionString = options.autoEncryption.extraOptions.mongocryptURI;
|
|
490
|
+
} else if (os.platform() === 'win32') {
|
|
491
|
+
connectionString = 'mongodb://localhost:27020/?serverSelectionTimeoutMS=1000';
|
|
492
|
+
} else {
|
|
493
|
+
connectionString = 'mongodb://%2Ftmp%2Fmongocryptd.sock/?serverSelectionTimeoutMS=1000';
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const mongocryptdClient = new MongoClient(connectionString, {
|
|
497
|
+
useNewUrlParser: true,
|
|
498
|
+
useUnifiedTopology: true
|
|
499
|
+
});
|
|
500
|
+
mongoClient.s.mongocryptdClient = mongocryptdClient;
|
|
501
|
+
mongocryptdClient.connect(err => {
|
|
502
|
+
if (err) return callback(err, null);
|
|
503
|
+
|
|
504
|
+
const mongoCryptOptions = Object.assign({}, options.autoEncryption, {
|
|
505
|
+
mongocryptdClient
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
topology.s.options.autoEncrypter = new AutoEncrypter(mongoClient, mongoCryptOptions);
|
|
509
|
+
callback(null, newTopology);
|
|
510
|
+
});
|
|
418
511
|
});
|
|
419
512
|
}
|
|
420
513
|
|
|
@@ -453,6 +546,42 @@ function createUnifiedOptions(finalOptions, options) {
|
|
|
453
546
|
return finalOptions;
|
|
454
547
|
}
|
|
455
548
|
|
|
549
|
+
function generateCredentials(client, username, password, options) {
|
|
550
|
+
options = Object.assign({}, options);
|
|
551
|
+
|
|
552
|
+
// the default db to authenticate against is 'self'
|
|
553
|
+
// if authententicate is called from a retry context, it may be another one, like admin
|
|
554
|
+
const source = options.authSource || options.authdb || options.dbName;
|
|
555
|
+
|
|
556
|
+
// authMechanism
|
|
557
|
+
const authMechanismRaw = options.authMechanism || 'DEFAULT';
|
|
558
|
+
const authMechanism = authMechanismRaw.toUpperCase();
|
|
559
|
+
|
|
560
|
+
if (!VALID_AUTH_MECHANISMS.has(authMechanism)) {
|
|
561
|
+
throw MongoError.create({
|
|
562
|
+
message: `authentication mechanism ${authMechanismRaw} not supported', options.authMechanism`,
|
|
563
|
+
driver: true
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (authMechanism === 'GSSAPI') {
|
|
568
|
+
return new MongoCredentials({
|
|
569
|
+
mechanism: process.platform === 'win32' ? 'sspi' : 'gssapi',
|
|
570
|
+
mechanismProperties: options,
|
|
571
|
+
source,
|
|
572
|
+
username,
|
|
573
|
+
password
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
return new MongoCredentials({
|
|
578
|
+
mechanism: AUTH_MECHANISM_INTERNAL_MAP[authMechanism],
|
|
579
|
+
source,
|
|
580
|
+
username,
|
|
581
|
+
password
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
|
|
456
585
|
function legacyTransformUrlOptions(object) {
|
|
457
586
|
return mergeOptions(createUnifiedOptions({}, object), object, false);
|
|
458
587
|
}
|
|
@@ -505,11 +634,6 @@ function replayEvents(mongoClient, events) {
|
|
|
505
634
|
}
|
|
506
635
|
}
|
|
507
636
|
|
|
508
|
-
const LEGACY_OPTIONS_MAP = validOptionNames.reduce((obj, name) => {
|
|
509
|
-
obj[name.toLowerCase()] = name;
|
|
510
|
-
return obj;
|
|
511
|
-
}, {});
|
|
512
|
-
|
|
513
637
|
function transformUrlOptions(_object) {
|
|
514
638
|
let object = Object.assign({ servers: _object.hosts }, _object.options);
|
|
515
639
|
for (let name in object) {
|
|
@@ -541,13 +665,17 @@ function transformUrlOptions(_object) {
|
|
|
541
665
|
}
|
|
542
666
|
|
|
543
667
|
if (object.readconcernlevel) {
|
|
544
|
-
object.readConcern =
|
|
668
|
+
object.readConcern = new ReadConcern(object.readconcernlevel);
|
|
545
669
|
}
|
|
546
670
|
|
|
547
671
|
if (object.wtimeoutms) {
|
|
548
672
|
object.wtimeout = object.wtimeoutms;
|
|
549
673
|
}
|
|
550
674
|
|
|
675
|
+
if (_object.srvHost) {
|
|
676
|
+
object.srvHost = _object.srvHost;
|
|
677
|
+
}
|
|
678
|
+
|
|
551
679
|
return object;
|
|
552
680
|
}
|
|
553
681
|
|
|
@@ -585,104 +713,4 @@ function translateOptions(options, translationOptions) {
|
|
|
585
713
|
});
|
|
586
714
|
}
|
|
587
715
|
|
|
588
|
-
|
|
589
|
-
function validOptions(options) {
|
|
590
|
-
const _validOptions = validOptionNames.concat(legacyOptionNames);
|
|
591
|
-
|
|
592
|
-
for (const name in options) {
|
|
593
|
-
if (ignoreOptionNames.indexOf(name) !== -1) {
|
|
594
|
-
continue;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
if (_validOptions.indexOf(name) === -1) {
|
|
598
|
-
if (options.validateOptions) {
|
|
599
|
-
return new MongoError(`option ${name} is not supported`);
|
|
600
|
-
} else {
|
|
601
|
-
console.warn(`the options [${name}] is not supported`);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
if (legacyOptionNames.indexOf(name) !== -1) {
|
|
606
|
-
console.warn(
|
|
607
|
-
`the server/replset/mongos/db options are deprecated, ` +
|
|
608
|
-
`all their options are supported at the top level of the options object [${validOptionNames}]`
|
|
609
|
-
);
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
const VALID_AUTH_MECHANISMS = new Set([
|
|
615
|
-
'DEFAULT',
|
|
616
|
-
'MONGODB-CR',
|
|
617
|
-
'PLAIN',
|
|
618
|
-
'MONGODB-X509',
|
|
619
|
-
'SCRAM-SHA-1',
|
|
620
|
-
'SCRAM-SHA-256',
|
|
621
|
-
'GSSAPI'
|
|
622
|
-
]);
|
|
623
|
-
|
|
624
|
-
const AUTH_MECHANISM_INTERNAL_MAP = {
|
|
625
|
-
DEFAULT: 'default',
|
|
626
|
-
'MONGODB-CR': 'mongocr',
|
|
627
|
-
PLAIN: 'plain',
|
|
628
|
-
'MONGODB-X509': 'x509',
|
|
629
|
-
'SCRAM-SHA-1': 'scram-sha-1',
|
|
630
|
-
'SCRAM-SHA-256': 'scram-sha-256'
|
|
631
|
-
};
|
|
632
|
-
|
|
633
|
-
function generateCredentials(client, username, password, options) {
|
|
634
|
-
options = Object.assign({}, options);
|
|
635
|
-
|
|
636
|
-
// the default db to authenticate against is 'self'
|
|
637
|
-
// if authenticate is called from a retry context, it may be another one, like admin
|
|
638
|
-
const source = options.authSource || options.authdb || options.dbName;
|
|
639
|
-
|
|
640
|
-
// authMechanism
|
|
641
|
-
const authMechanismRaw = options.authMechanism || 'DEFAULT';
|
|
642
|
-
const authMechanism = authMechanismRaw.toUpperCase();
|
|
643
|
-
|
|
644
|
-
if (!VALID_AUTH_MECHANISMS.has(authMechanism)) {
|
|
645
|
-
throw MongoError.create({
|
|
646
|
-
message: `authentication mechanism ${authMechanismRaw} not supported', options.authMechanism`,
|
|
647
|
-
driver: true
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
if (authMechanism === 'GSSAPI') {
|
|
652
|
-
return new MongoCredentials({
|
|
653
|
-
mechanism: process.platform === 'win32' ? 'sspi' : 'gssapi',
|
|
654
|
-
mechanismProperties: options,
|
|
655
|
-
source,
|
|
656
|
-
username,
|
|
657
|
-
password
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
return new MongoCredentials({
|
|
662
|
-
mechanism: AUTH_MECHANISM_INTERNAL_MAP[authMechanism],
|
|
663
|
-
source,
|
|
664
|
-
username,
|
|
665
|
-
password
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
function closeOperation(client, force, callback) {
|
|
670
|
-
const completeClose = err => {
|
|
671
|
-
client.emit('close', client);
|
|
672
|
-
for (const name in client.s.dbCache) {
|
|
673
|
-
client.s.dbCache[name].emit('close', client);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
client.removeAllListeners('close');
|
|
677
|
-
callback(err, null);
|
|
678
|
-
};
|
|
679
|
-
|
|
680
|
-
if (client.topology == null) {
|
|
681
|
-
completeClose();
|
|
682
|
-
return;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
client.topology.close(force, completeClose);
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
module.exports = { connectOp, validOptions, closeOperation };
|
|
716
|
+
module.exports = ConnectOperation;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Aspect = require('./operation').Aspect;
|
|
4
|
+
const buildCountCommand = require('./common_functions').buildCountCommand;
|
|
5
|
+
const defineAspects = require('./operation').defineAspects;
|
|
6
|
+
const OperationBase = require('./operation').OperationBase;
|
|
7
|
+
|
|
8
|
+
class CountOperation extends OperationBase {
|
|
9
|
+
constructor(cursor, applySkipLimit, options) {
|
|
10
|
+
super(options);
|
|
11
|
+
|
|
12
|
+
this.cursor = cursor;
|
|
13
|
+
this.applySkipLimit = applySkipLimit;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
execute(callback) {
|
|
17
|
+
const cursor = this.cursor;
|
|
18
|
+
const applySkipLimit = this.applySkipLimit;
|
|
19
|
+
const options = this.options;
|
|
20
|
+
|
|
21
|
+
if (applySkipLimit) {
|
|
22
|
+
if (typeof cursor.cursorSkip() === 'number') options.skip = cursor.cursorSkip();
|
|
23
|
+
if (typeof cursor.cursorLimit() === 'number') options.limit = cursor.cursorLimit();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Ensure we have the right read preference inheritance
|
|
27
|
+
if (options.readPreference) {
|
|
28
|
+
cursor.setReadPreference(options.readPreference);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
typeof options.maxTimeMS !== 'number' &&
|
|
33
|
+
cursor.s.cmd &&
|
|
34
|
+
typeof cursor.s.cmd.maxTimeMS === 'number'
|
|
35
|
+
) {
|
|
36
|
+
options.maxTimeMS = cursor.s.cmd.maxTimeMS;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let finalOptions = {};
|
|
40
|
+
finalOptions.skip = options.skip;
|
|
41
|
+
finalOptions.limit = options.limit;
|
|
42
|
+
finalOptions.hint = options.hint;
|
|
43
|
+
finalOptions.maxTimeMS = options.maxTimeMS;
|
|
44
|
+
|
|
45
|
+
// Command
|
|
46
|
+
finalOptions.collectionName = cursor.s.namespace.collection;
|
|
47
|
+
|
|
48
|
+
let command;
|
|
49
|
+
try {
|
|
50
|
+
command = buildCountCommand(cursor, cursor.s.cmd.query, finalOptions);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
return callback(err);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Set cursor server to the same as the topology
|
|
56
|
+
cursor.server = cursor.topology.s.coreTopology;
|
|
57
|
+
|
|
58
|
+
// Execute the command
|
|
59
|
+
cursor.s.topology.command(
|
|
60
|
+
cursor.s.namespace.withCollection('$cmd'),
|
|
61
|
+
command,
|
|
62
|
+
cursor.s.options,
|
|
63
|
+
(err, result) => {
|
|
64
|
+
callback(err, result ? result.result.n : null);
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
defineAspects(CountOperation, Aspect.SKIP_SESSION);
|
|
71
|
+
|
|
72
|
+
module.exports = CountOperation;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const OperationBase = require('./operation').OperationBase;
|
|
4
|
+
const handleCallback = require('../utils').handleCallback;
|
|
5
|
+
|
|
6
|
+
class CountDocumentsOperation extends OperationBase {
|
|
7
|
+
constructor(collection, query, options) {
|
|
8
|
+
super(options);
|
|
9
|
+
|
|
10
|
+
this.collection = collection;
|
|
11
|
+
this.query = query;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
execute(callback) {
|
|
15
|
+
const coll = this.collection;
|
|
16
|
+
const query = this.query;
|
|
17
|
+
let options = this.options;
|
|
18
|
+
|
|
19
|
+
const skip = options.skip;
|
|
20
|
+
const limit = options.limit;
|
|
21
|
+
options = Object.assign({}, options);
|
|
22
|
+
|
|
23
|
+
const pipeline = [{ $match: query }];
|
|
24
|
+
|
|
25
|
+
// Add skip and limit if defined
|
|
26
|
+
if (typeof skip === 'number') {
|
|
27
|
+
pipeline.push({ $skip: skip });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (typeof limit === 'number') {
|
|
31
|
+
pipeline.push({ $limit: limit });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
pipeline.push({ $group: { _id: 1, n: { $sum: 1 } } });
|
|
35
|
+
|
|
36
|
+
delete options.limit;
|
|
37
|
+
delete options.skip;
|
|
38
|
+
|
|
39
|
+
coll.aggregate(pipeline, options).toArray((err, docs) => {
|
|
40
|
+
if (err) return handleCallback(callback, err);
|
|
41
|
+
handleCallback(callback, null, docs.length ? docs[0].n : 0);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = CountDocumentsOperation;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Aspect = require('./operation').Aspect;
|
|
4
|
+
const defineAspects = require('./operation').defineAspects;
|
|
5
|
+
const CommandOperation = require('./command');
|
|
6
|
+
const applyWriteConcern = require('../utils').applyWriteConcern;
|
|
7
|
+
const handleCallback = require('../utils').handleCallback;
|
|
8
|
+
const loadCollection = require('../dynamic_loaders').loadCollection;
|
|
9
|
+
const MongoError = require('../core').MongoError;
|
|
10
|
+
const ReadPreference = require('../core').ReadPreference;
|
|
11
|
+
|
|
12
|
+
// Filter out any write concern options
|
|
13
|
+
const illegalCommandFields = [
|
|
14
|
+
'w',
|
|
15
|
+
'wtimeout',
|
|
16
|
+
'j',
|
|
17
|
+
'fsync',
|
|
18
|
+
'autoIndexId',
|
|
19
|
+
'strict',
|
|
20
|
+
'serializeFunctions',
|
|
21
|
+
'pkFactory',
|
|
22
|
+
'raw',
|
|
23
|
+
'readPreference',
|
|
24
|
+
'session',
|
|
25
|
+
'readConcern',
|
|
26
|
+
'writeConcern'
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
class CreateCollectionOperation extends CommandOperation {
|
|
30
|
+
constructor(db, name, options) {
|
|
31
|
+
super(db, options);
|
|
32
|
+
|
|
33
|
+
this.name = name;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
_buildCommand() {
|
|
37
|
+
const name = this.name;
|
|
38
|
+
const options = this.options;
|
|
39
|
+
|
|
40
|
+
// Create collection command
|
|
41
|
+
const cmd = { create: name };
|
|
42
|
+
// Add all optional parameters
|
|
43
|
+
for (let n in options) {
|
|
44
|
+
if (
|
|
45
|
+
options[n] != null &&
|
|
46
|
+
typeof options[n] !== 'function' &&
|
|
47
|
+
illegalCommandFields.indexOf(n) === -1
|
|
48
|
+
) {
|
|
49
|
+
cmd[n] = options[n];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return cmd;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
execute(callback) {
|
|
57
|
+
const db = this.db;
|
|
58
|
+
const name = this.name;
|
|
59
|
+
const options = this.options;
|
|
60
|
+
|
|
61
|
+
let Collection = loadCollection();
|
|
62
|
+
|
|
63
|
+
// Did the user destroy the topology
|
|
64
|
+
if (db.serverConfig && db.serverConfig.isDestroyed()) {
|
|
65
|
+
return callback(new MongoError('topology was destroyed'));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let listCollectionOptions = Object.assign({}, options, { nameOnly: true });
|
|
69
|
+
listCollectionOptions = applyWriteConcern(listCollectionOptions, { db }, listCollectionOptions);
|
|
70
|
+
|
|
71
|
+
// Check if we have the name
|
|
72
|
+
db
|
|
73
|
+
.listCollections({ name }, listCollectionOptions)
|
|
74
|
+
.setReadPreference(ReadPreference.PRIMARY)
|
|
75
|
+
.toArray((err, collections) => {
|
|
76
|
+
if (err != null) return handleCallback(callback, err, null);
|
|
77
|
+
if (collections.length > 0 && listCollectionOptions.strict) {
|
|
78
|
+
return handleCallback(
|
|
79
|
+
callback,
|
|
80
|
+
MongoError.create({
|
|
81
|
+
message: `Collection ${name} already exists. Currently in strict mode.`,
|
|
82
|
+
driver: true
|
|
83
|
+
}),
|
|
84
|
+
null
|
|
85
|
+
);
|
|
86
|
+
} else if (collections.length > 0) {
|
|
87
|
+
try {
|
|
88
|
+
return handleCallback(
|
|
89
|
+
callback,
|
|
90
|
+
null,
|
|
91
|
+
new Collection(db, db.s.topology, db.databaseName, name, db.s.pkFactory, options)
|
|
92
|
+
);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
return handleCallback(callback, err);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Execute command
|
|
99
|
+
super.execute(err => {
|
|
100
|
+
if (err) return handleCallback(callback, err);
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
return handleCallback(
|
|
104
|
+
callback,
|
|
105
|
+
null,
|
|
106
|
+
new Collection(db, db.s.topology, db.databaseName, name, db.s.pkFactory, options)
|
|
107
|
+
);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
return handleCallback(callback, err);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
defineAspects(CreateCollectionOperation, Aspect.WRITE_OPERATION);
|
|
117
|
+
|
|
118
|
+
module.exports = CreateCollectionOperation;
|