mongodb 3.1.13 → 3.2.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 +63 -0
- package/README.md +7 -0
- package/lib/aggregation_cursor.js +9 -2
- package/lib/async/.eslintrc +5 -0
- package/lib/async/async_iterator.js +15 -0
- package/lib/bulk/ordered.js +5 -1
- package/lib/bulk/unordered.js +5 -1
- package/lib/collection.js +7 -139
- package/lib/command_cursor.js +5 -0
- package/lib/cursor.js +5 -0
- package/lib/db.js +46 -0
- package/lib/mongo_client.js +8 -45
- package/lib/operations/aggregate.js +121 -0
- package/lib/operations/collection_ops.js +53 -1
- package/lib/operations/db_ops.js +2 -2
- package/lib/operations/mongo_client_ops.js +142 -108
- package/lib/topologies/native_topology.js +51 -0
- package/lib/topologies/replset.js +2 -3
- package/lib/topologies/topology_base.js +8 -15
- package/lib/utils.js +13 -7
- package/package.json +4 -3
- package/lib/authenticate.js +0 -136
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const AggregationCursor = require('../aggregation_cursor');
|
|
4
|
+
const applyWriteConcern = require('../utils').applyWriteConcern;
|
|
5
|
+
const decorateWithCollation = require('../utils').decorateWithCollation;
|
|
6
|
+
const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
|
|
7
|
+
const handleCallback = require('../utils').handleCallback;
|
|
8
|
+
const MongoError = require('mongodb-core').MongoError;
|
|
9
|
+
const resolveReadPreference = require('../utils').resolveReadPreference;
|
|
10
|
+
const toError = require('../utils').toError;
|
|
11
|
+
|
|
12
|
+
const DB_AGGREGATE_COLLECTION = 1;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Perform an aggregate operation. See Collection.prototype.aggregate or Db.prototype.aggregate for more information.
|
|
16
|
+
*
|
|
17
|
+
* @method
|
|
18
|
+
* @param {Db} db A Db instance.
|
|
19
|
+
* @param {Collection|string} coll A collection instance or the string '1', used for db.aggregate.
|
|
20
|
+
* @param {object} [pipeline=[]] Array containing all the aggregation framework commands for the execution.
|
|
21
|
+
* @param {object} [options] Optional settings. See Collection.prototype.aggregate or Db.prototype.aggregate for a list of options.
|
|
22
|
+
* @param {Db~aggregationCallback|Collection~aggregationCallback} callback The command result callback
|
|
23
|
+
*/
|
|
24
|
+
function aggregate(db, coll, pipeline, options, callback) {
|
|
25
|
+
const isDbAggregate = typeof coll === 'string';
|
|
26
|
+
const target = isDbAggregate ? db : coll;
|
|
27
|
+
const topology = target.s.topology;
|
|
28
|
+
let hasOutStage = false;
|
|
29
|
+
|
|
30
|
+
if (typeof options.out === 'string') {
|
|
31
|
+
pipeline = pipeline.concat({ $out: options.out });
|
|
32
|
+
hasOutStage = true;
|
|
33
|
+
} else if (pipeline.length > 0 && pipeline[pipeline.length - 1]['$out']) {
|
|
34
|
+
hasOutStage = true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let command;
|
|
38
|
+
let namespace;
|
|
39
|
+
let optionSources;
|
|
40
|
+
|
|
41
|
+
if (isDbAggregate) {
|
|
42
|
+
command = { aggregate: DB_AGGREGATE_COLLECTION, pipeline: pipeline };
|
|
43
|
+
namespace = `${db.s.databaseName}.${DB_AGGREGATE_COLLECTION}`;
|
|
44
|
+
|
|
45
|
+
optionSources = { db };
|
|
46
|
+
} else {
|
|
47
|
+
command = { aggregate: coll.s.name, pipeline: pipeline };
|
|
48
|
+
namespace = coll.s.namespace;
|
|
49
|
+
|
|
50
|
+
optionSources = { db: coll.s.db, collection: coll };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const takesWriteConcern = topology.capabilities().commandsTakeWriteConcern;
|
|
54
|
+
|
|
55
|
+
if (!hasOutStage) {
|
|
56
|
+
decorateWithReadConcern(command, target, options);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (pipeline.length > 0 && pipeline[pipeline.length - 1]['$out'] && takesWriteConcern) {
|
|
60
|
+
applyWriteConcern(command, optionSources, options);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
decorateWithCollation(command, target, options);
|
|
65
|
+
} catch (err) {
|
|
66
|
+
if (typeof callback === 'function') return callback(err, null);
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (options.bypassDocumentValidation === true) {
|
|
71
|
+
command.bypassDocumentValidation = options.bypassDocumentValidation;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (typeof options.allowDiskUse === 'boolean') command.allowDiskUse = options.allowDiskUse;
|
|
75
|
+
if (typeof options.maxTimeMS === 'number') command.maxTimeMS = options.maxTimeMS;
|
|
76
|
+
|
|
77
|
+
if (options.hint) command.hint = options.hint;
|
|
78
|
+
|
|
79
|
+
options = Object.assign({}, options);
|
|
80
|
+
|
|
81
|
+
// Ensure we have the right read preference inheritance
|
|
82
|
+
options.readPreference = resolveReadPreference(options, optionSources);
|
|
83
|
+
|
|
84
|
+
if (options.explain) {
|
|
85
|
+
if (command.readConcern || command.writeConcern) {
|
|
86
|
+
throw toError('"explain" cannot be used on an aggregate call with readConcern/writeConcern');
|
|
87
|
+
}
|
|
88
|
+
command.explain = options.explain;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (typeof options.comment === 'string') command.comment = options.comment;
|
|
92
|
+
|
|
93
|
+
// Validate that cursor options is valid
|
|
94
|
+
if (options.cursor != null && typeof options.cursor !== 'object') {
|
|
95
|
+
throw toError('cursor options must be an object');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
options.cursor = options.cursor || {};
|
|
99
|
+
if (options.batchSize && !hasOutStage) options.cursor.batchSize = options.batchSize;
|
|
100
|
+
command.cursor = options.cursor;
|
|
101
|
+
|
|
102
|
+
// promiseLibrary
|
|
103
|
+
options.promiseLibrary = target.s.promiseLibrary;
|
|
104
|
+
|
|
105
|
+
// Set the AggregationCursor constructor
|
|
106
|
+
options.cursorFactory = AggregationCursor;
|
|
107
|
+
|
|
108
|
+
if (typeof callback !== 'function') {
|
|
109
|
+
if (!topology.capabilities()) {
|
|
110
|
+
throw new MongoError('cannot connect to server');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return topology.cursor(namespace, command, options);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return handleCallback(callback, null, topology.cursor(namespace, command, options));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = {
|
|
120
|
+
aggregate
|
|
121
|
+
};
|
|
@@ -225,7 +225,7 @@ function countDocuments(coll, query, options, callback) {
|
|
|
225
225
|
pipeline.push({ $limit: limit });
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
pipeline.push({ $group: { _id:
|
|
228
|
+
pipeline.push({ $group: { _id: 1, n: { $sum: 1 } } });
|
|
229
229
|
|
|
230
230
|
delete options.limit;
|
|
231
231
|
delete options.skip;
|
|
@@ -892,6 +892,57 @@ function insertOne(coll, doc, options, callback) {
|
|
|
892
892
|
});
|
|
893
893
|
}
|
|
894
894
|
|
|
895
|
+
/**
|
|
896
|
+
* Inserts an array of documents into MongoDB. If documents passed in do not contain the **_id** field,
|
|
897
|
+
* one will be added to each of the documents missing it by the driver, mutating the document. This behavior
|
|
898
|
+
* can be overridden by setting the **forceServerObjectId** flag.
|
|
899
|
+
*
|
|
900
|
+
* @method
|
|
901
|
+
* @param {Collection} a Collection instance.
|
|
902
|
+
* @param {object[]} docs Documents to insert.
|
|
903
|
+
* @param {number} [options] Optional settings. See Collection.prototype.insertMany for a list of options.
|
|
904
|
+
* @param {Collection~insertWriteOpCallback} [callback] The command result callback
|
|
905
|
+
*/
|
|
906
|
+
function insertMany(coll, docs, options, callback) {
|
|
907
|
+
if (!Array.isArray(docs)) {
|
|
908
|
+
return callback(
|
|
909
|
+
MongoError.create({ message: 'docs parameter must be an array of documents', driver: true })
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// If keep going set unordered
|
|
914
|
+
options['serializeFunctions'] = options['serializeFunctions'] || coll.s.serializeFunctions;
|
|
915
|
+
|
|
916
|
+
docs = prepareDocs(coll, docs, options);
|
|
917
|
+
|
|
918
|
+
// Generate the bulk write operations
|
|
919
|
+
const operations = [
|
|
920
|
+
{
|
|
921
|
+
insertMany: docs
|
|
922
|
+
}
|
|
923
|
+
];
|
|
924
|
+
|
|
925
|
+
bulkWrite(coll, operations, options, (err, result) => {
|
|
926
|
+
if (err) return callback(err, null);
|
|
927
|
+
callback(null, mapInsertManyResults(docs, result));
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
function mapInsertManyResults(docs, r) {
|
|
932
|
+
const finalResult = {
|
|
933
|
+
result: { ok: 1, n: r.insertedCount },
|
|
934
|
+
ops: docs,
|
|
935
|
+
insertedCount: r.insertedCount,
|
|
936
|
+
insertedIds: r.insertedIds
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
if (r.getLastOp()) {
|
|
940
|
+
finalResult.result.opTime = r.getLastOp();
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
return finalResult;
|
|
944
|
+
}
|
|
945
|
+
|
|
895
946
|
/**
|
|
896
947
|
* Determine whether the collection is a capped collection.
|
|
897
948
|
*
|
|
@@ -1476,6 +1527,7 @@ module.exports = {
|
|
|
1476
1527
|
indexes,
|
|
1477
1528
|
indexExists,
|
|
1478
1529
|
indexInformation,
|
|
1530
|
+
insertMany,
|
|
1479
1531
|
insertOne,
|
|
1480
1532
|
isCapped,
|
|
1481
1533
|
mapReduce,
|
package/lib/operations/db_ops.js
CHANGED
|
@@ -97,10 +97,10 @@ function addUser(db, username, password, options, callback) {
|
|
|
97
97
|
const userPassword = md5.digest('hex');
|
|
98
98
|
|
|
99
99
|
// If we have another db set
|
|
100
|
-
const
|
|
100
|
+
const dbToUse = options.dbName ? new Db(options.dbName, db.s.topology, db.s.options) : db;
|
|
101
101
|
|
|
102
102
|
// Fetch a user collection
|
|
103
|
-
const collection =
|
|
103
|
+
const collection = dbToUse.collection(CONSTANTS.SYSTEM_USER_COLLECTION);
|
|
104
104
|
|
|
105
105
|
// Check if we are inserting the first user
|
|
106
106
|
count(collection, {}, finalOptions, (err, count) => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const authenticate = require('../authenticate');
|
|
4
3
|
const deprecate = require('util').deprecate;
|
|
5
4
|
const Logger = require('mongodb-core').Logger;
|
|
6
5
|
const MongoError = require('mongodb-core').MongoError;
|
|
@@ -10,6 +9,8 @@ const ReadPreference = require('mongodb-core').ReadPreference;
|
|
|
10
9
|
const ReplSet = require('../topologies/replset');
|
|
11
10
|
const Server = require('../topologies/server');
|
|
12
11
|
const ServerSessionPool = require('mongodb-core').Sessions.ServerSessionPool;
|
|
12
|
+
const NativeTopology = require('../topologies/native_topology');
|
|
13
|
+
const MongoCredentials = require('mongodb-core').MongoCredentials;
|
|
13
14
|
|
|
14
15
|
let client;
|
|
15
16
|
function loadClient() {
|
|
@@ -108,7 +109,10 @@ const validOptionNames = [
|
|
|
108
109
|
'minSize',
|
|
109
110
|
'monitorCommands',
|
|
110
111
|
'retryWrites',
|
|
111
|
-
'useNewUrlParser'
|
|
112
|
+
'useNewUrlParser',
|
|
113
|
+
'useUnifiedTopology',
|
|
114
|
+
'serverSelectionTimeoutMS',
|
|
115
|
+
'useRecoveryToken'
|
|
112
116
|
];
|
|
113
117
|
|
|
114
118
|
function addListeners(mongoClient, topology) {
|
|
@@ -125,7 +129,10 @@ function addListeners(mongoClient, topology) {
|
|
|
125
129
|
|
|
126
130
|
function assignTopology(client, topology) {
|
|
127
131
|
client.topology = topology;
|
|
128
|
-
topology.s.sessionPool =
|
|
132
|
+
topology.s.sessionPool =
|
|
133
|
+
topology instanceof NativeTopology
|
|
134
|
+
? new ServerSessionPool(topology)
|
|
135
|
+
: new ServerSessionPool(topology.s.coreTopology);
|
|
129
136
|
}
|
|
130
137
|
|
|
131
138
|
// Clear out all events
|
|
@@ -174,7 +181,7 @@ function connect(mongoClient, url, options, callback) {
|
|
|
174
181
|
throw new Error('no callback function provided');
|
|
175
182
|
}
|
|
176
183
|
|
|
177
|
-
|
|
184
|
+
let didRequestAuthentication = false;
|
|
178
185
|
const logger = Logger('MongoClient', options);
|
|
179
186
|
|
|
180
187
|
// Did we pass in a Server/ReplSet/Mongos
|
|
@@ -211,29 +218,34 @@ function connect(mongoClient, url, options, callback) {
|
|
|
211
218
|
return callback(new Error('connection string must contain at least one seed host'));
|
|
212
219
|
}
|
|
213
220
|
|
|
221
|
+
if (_finalOptions.auth && !_finalOptions.credentials) {
|
|
222
|
+
try {
|
|
223
|
+
didRequestAuthentication = true;
|
|
224
|
+
_finalOptions.credentials = generateCredentials(
|
|
225
|
+
mongoClient,
|
|
226
|
+
_finalOptions.auth.user,
|
|
227
|
+
_finalOptions.auth.password,
|
|
228
|
+
_finalOptions
|
|
229
|
+
);
|
|
230
|
+
} catch (err) {
|
|
231
|
+
return callback(err);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (_finalOptions.useUnifiedTopology) {
|
|
236
|
+
return createTopology(mongoClient, 'unified', _finalOptions, connectCallback);
|
|
237
|
+
}
|
|
238
|
+
|
|
214
239
|
// Do we have a replicaset then skip discovery and go straight to connectivity
|
|
215
240
|
if (_finalOptions.replicaSet || _finalOptions.rs_name) {
|
|
216
|
-
return createTopology(
|
|
217
|
-
mongoClient,
|
|
218
|
-
'replicaset',
|
|
219
|
-
_finalOptions,
|
|
220
|
-
connectHandler(mongoClient, _finalOptions, connectCallback)
|
|
221
|
-
);
|
|
241
|
+
return createTopology(mongoClient, 'replicaset', _finalOptions, connectCallback);
|
|
222
242
|
} else if (object.servers.length > 1) {
|
|
223
|
-
return createTopology(
|
|
224
|
-
mongoClient,
|
|
225
|
-
'mongos',
|
|
226
|
-
_finalOptions,
|
|
227
|
-
connectHandler(mongoClient, _finalOptions, connectCallback)
|
|
228
|
-
);
|
|
243
|
+
return createTopology(mongoClient, 'mongos', _finalOptions, connectCallback);
|
|
229
244
|
} else {
|
|
230
|
-
return createServer(
|
|
231
|
-
mongoClient,
|
|
232
|
-
_finalOptions,
|
|
233
|
-
connectHandler(mongoClient, _finalOptions, connectCallback)
|
|
234
|
-
);
|
|
245
|
+
return createServer(mongoClient, _finalOptions, connectCallback);
|
|
235
246
|
}
|
|
236
247
|
});
|
|
248
|
+
|
|
237
249
|
function connectCallback(err, topology) {
|
|
238
250
|
const warningMessage = `seed list contains no mongos proxies, replicaset connections requires the parameter replicaSet to be supplied in the URI or options object, mongodb://server:port/db?replicaSet=name`;
|
|
239
251
|
if (err && err.message === 'no mongos proxies found in seed list') {
|
|
@@ -245,35 +257,15 @@ function connect(mongoClient, url, options, callback) {
|
|
|
245
257
|
return callback(new MongoError(warningMessage));
|
|
246
258
|
}
|
|
247
259
|
|
|
260
|
+
if (didRequestAuthentication) {
|
|
261
|
+
mongoClient.emit('authenticated', null, true);
|
|
262
|
+
}
|
|
263
|
+
|
|
248
264
|
// Return the error and db instance
|
|
249
265
|
callback(err, topology);
|
|
250
266
|
}
|
|
251
267
|
}
|
|
252
268
|
|
|
253
|
-
function connectHandler(client, options, callback) {
|
|
254
|
-
return (err, topology) => {
|
|
255
|
-
if (err) {
|
|
256
|
-
return handleConnectCallback(err, topology, callback);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// No authentication just reconnect
|
|
260
|
-
if (!options.auth) {
|
|
261
|
-
return handleConnectCallback(err, topology, callback);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Authenticate
|
|
265
|
-
authenticate(client, options.user, options.password, options, (err, success) => {
|
|
266
|
-
if (success) {
|
|
267
|
-
handleConnectCallback(null, topology, callback);
|
|
268
|
-
} else {
|
|
269
|
-
if (topology) topology.close();
|
|
270
|
-
const authError = err ? err : new Error('Could not authenticate user ' + options.auth[0]);
|
|
271
|
-
handleConnectCallback(authError, topology, callback);
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
|
|
277
269
|
/**
|
|
278
270
|
* Connect to MongoDB using a url as documented at
|
|
279
271
|
*
|
|
@@ -314,27 +306,21 @@ function connectWithUrl(mongoClient, url, options, connectCallback) {
|
|
|
314
306
|
);
|
|
315
307
|
}
|
|
316
308
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
connectCallback(err, topology);
|
|
331
|
-
}
|
|
332
|
-
);
|
|
333
|
-
}
|
|
309
|
+
const isDoingAuth = finalOptions.user || finalOptions.password || finalOptions.authMechanism;
|
|
310
|
+
if (isDoingAuth && !finalOptions.credentials) {
|
|
311
|
+
try {
|
|
312
|
+
finalOptions.credentials = generateCredentials(
|
|
313
|
+
mongoClient,
|
|
314
|
+
finalOptions.user,
|
|
315
|
+
finalOptions.password,
|
|
316
|
+
finalOptions
|
|
317
|
+
);
|
|
318
|
+
} catch (err) {
|
|
319
|
+
return connectCallback(err, url);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
334
322
|
|
|
335
|
-
|
|
336
|
-
})
|
|
337
|
-
);
|
|
323
|
+
return url.connect(finalOptions, connectCallback);
|
|
338
324
|
}
|
|
339
325
|
|
|
340
326
|
function createListener(mongoClient, event) {
|
|
@@ -410,6 +396,8 @@ function createTopology(mongoClient, topologyType, options, callback) {
|
|
|
410
396
|
topology = new Mongos(servers, options);
|
|
411
397
|
} else if (topologyType === 'replicaset') {
|
|
412
398
|
topology = new ReplSet(servers, options);
|
|
399
|
+
} else if (topologyType === 'unified') {
|
|
400
|
+
topology = new NativeTopology(options.servers, options);
|
|
413
401
|
}
|
|
414
402
|
|
|
415
403
|
// Add listeners
|
|
@@ -465,36 +453,10 @@ function createUnifiedOptions(finalOptions, options) {
|
|
|
465
453
|
return finalOptions;
|
|
466
454
|
}
|
|
467
455
|
|
|
468
|
-
function handleConnectCallback(err, topology, callback) {
|
|
469
|
-
return process.nextTick(() => {
|
|
470
|
-
try {
|
|
471
|
-
callback(err, topology);
|
|
472
|
-
} catch (err) {
|
|
473
|
-
if (topology) topology.close();
|
|
474
|
-
throw err;
|
|
475
|
-
}
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
|
|
479
456
|
function legacyTransformUrlOptions(object) {
|
|
480
457
|
return mergeOptions(createUnifiedOptions({}, object), object, false);
|
|
481
458
|
}
|
|
482
459
|
|
|
483
|
-
/**
|
|
484
|
-
* Logout user from server, fire off on all connections and remove all auth info.
|
|
485
|
-
*
|
|
486
|
-
* @method
|
|
487
|
-
* @param {MongoClient} mongoClient The MongoClient instance on which to logout.
|
|
488
|
-
* @param {object} [options] Optional settings. See MongoClient.prototype.logout for a list of options.
|
|
489
|
-
* @param {Db~resultCallback} [callback] The command result callback
|
|
490
|
-
*/
|
|
491
|
-
function logout(mongoClient, dbName, callback) {
|
|
492
|
-
mongoClient.topology.logout(dbName, err => {
|
|
493
|
-
if (err) return callback(err);
|
|
494
|
-
callback(null, true);
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
|
|
498
460
|
function mergeOptions(target, source, flatten) {
|
|
499
461
|
for (const name in source) {
|
|
500
462
|
if (source[name] && typeof source[name] === 'object' && flatten) {
|
|
@@ -556,21 +518,17 @@ function transformUrlOptions(_object) {
|
|
|
556
518
|
object[camelCaseName] = object[name];
|
|
557
519
|
}
|
|
558
520
|
}
|
|
559
|
-
if (_object.auth) {
|
|
560
|
-
const auth = _object.auth;
|
|
561
|
-
for (let i in auth) {
|
|
562
|
-
if (auth[i]) {
|
|
563
|
-
object[i] = auth[i];
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
521
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
522
|
+
const hasUsername = _object.auth && _object.auth.username;
|
|
523
|
+
const hasAuthMechanism = _object.options && _object.options.authMechanism;
|
|
524
|
+
if (hasUsername || hasAuthMechanism) {
|
|
525
|
+
object.auth = Object.assign({}, _object.auth);
|
|
526
|
+
if (object.auth.db) {
|
|
527
|
+
object.authSource = object.authSource || object.auth.db;
|
|
570
528
|
}
|
|
571
529
|
|
|
572
|
-
if (auth.
|
|
573
|
-
object.
|
|
530
|
+
if (object.auth.username) {
|
|
531
|
+
object.auth.user = object.auth.username;
|
|
574
532
|
}
|
|
575
533
|
}
|
|
576
534
|
|
|
@@ -636,10 +594,12 @@ function validOptions(options) {
|
|
|
636
594
|
continue;
|
|
637
595
|
}
|
|
638
596
|
|
|
639
|
-
if (_validOptions.indexOf(name) === -1
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
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
|
+
}
|
|
643
603
|
}
|
|
644
604
|
|
|
645
605
|
if (legacyOptionNames.indexOf(name) !== -1) {
|
|
@@ -651,4 +611,78 @@ function validOptions(options) {
|
|
|
651
611
|
}
|
|
652
612
|
}
|
|
653
613
|
|
|
654
|
-
|
|
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 authententicate 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 };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Topology = require('mongodb-core').Topology;
|
|
4
|
+
const ServerCapabilities = require('./topology_base').ServerCapabilities;
|
|
5
|
+
const Cursor = require('../cursor');
|
|
6
|
+
const translateOptions = require('../utils').translateOptions;
|
|
7
|
+
|
|
8
|
+
class NativeTopology extends Topology {
|
|
9
|
+
constructor(servers, options) {
|
|
10
|
+
options = options || {};
|
|
11
|
+
|
|
12
|
+
let clonedOptions = Object.assign(
|
|
13
|
+
{},
|
|
14
|
+
{
|
|
15
|
+
cursorFactory: Cursor,
|
|
16
|
+
reconnect: false,
|
|
17
|
+
emitError: options.emitError,
|
|
18
|
+
size: options.poolSize,
|
|
19
|
+
monitorCommands: options.monitorCommands
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// Translate any SSL options and other connectivity options
|
|
24
|
+
clonedOptions = translateOptions(clonedOptions, options);
|
|
25
|
+
|
|
26
|
+
// Socket options
|
|
27
|
+
var socketOptions =
|
|
28
|
+
options.socketOptions && Object.keys(options.socketOptions).length > 0
|
|
29
|
+
? options.socketOptions
|
|
30
|
+
: options;
|
|
31
|
+
|
|
32
|
+
// Translate all the options to the mongodb-core ones
|
|
33
|
+
clonedOptions = translateOptions(clonedOptions, socketOptions);
|
|
34
|
+
|
|
35
|
+
super(servers, clonedOptions);
|
|
36
|
+
|
|
37
|
+
// Do we have an application specific string
|
|
38
|
+
if (options.appname) {
|
|
39
|
+
this.s.clientInfo.application = { name: options.appname };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
capabilities() {
|
|
44
|
+
if (this.s.sCapabilities) return this.s.sCapabilities;
|
|
45
|
+
if (this.lastIsMaster() == null) return null;
|
|
46
|
+
this.s.sCapabilities = new ServerCapabilities(this.lastIsMaster());
|
|
47
|
+
return this.s.sCapabilities;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = NativeTopology;
|
|
@@ -381,10 +381,9 @@ class ReplSet extends TopologyBase {
|
|
|
381
381
|
self.s.coreTopology.connect(_options);
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
-
close(forceClosed) {
|
|
385
|
-
super.close(forceClosed);
|
|
386
|
-
|
|
384
|
+
close(forceClosed, callback) {
|
|
387
385
|
['timeout', 'error', 'close', 'joined', 'left'].forEach(e => this.removeAllListeners(e));
|
|
386
|
+
super.close(forceClosed, callback);
|
|
388
387
|
}
|
|
389
388
|
}
|
|
390
389
|
|
|
@@ -370,16 +370,6 @@ class TopologyBase extends EventEmitter {
|
|
|
370
370
|
return this.s.coreTopology.unref();
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
-
auth() {
|
|
374
|
-
var args = Array.prototype.slice.call(arguments, 0);
|
|
375
|
-
this.s.coreTopology.auth.apply(this.s.coreTopology, args);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
logout() {
|
|
379
|
-
var args = Array.prototype.slice.call(arguments, 0);
|
|
380
|
-
this.s.coreTopology.logout.apply(this.s.coreTopology, args);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
373
|
/**
|
|
384
374
|
* All raw connections
|
|
385
375
|
* @method
|
|
@@ -389,7 +379,7 @@ class TopologyBase extends EventEmitter {
|
|
|
389
379
|
return this.s.coreTopology.connections();
|
|
390
380
|
}
|
|
391
381
|
|
|
392
|
-
close(forceClosed) {
|
|
382
|
+
close(forceClosed, callback) {
|
|
393
383
|
// If we have sessions, we want to individually move them to the session pool,
|
|
394
384
|
// and then send a single endSessions call.
|
|
395
385
|
if (this.s.sessions.length) {
|
|
@@ -400,15 +390,18 @@ class TopologyBase extends EventEmitter {
|
|
|
400
390
|
this.s.sessionPool.endAllPooledSessions();
|
|
401
391
|
}
|
|
402
392
|
|
|
403
|
-
this.s.coreTopology.destroy({
|
|
404
|
-
force: typeof forceClosed === 'boolean' ? forceClosed : false
|
|
405
|
-
});
|
|
406
|
-
|
|
407
393
|
// We need to wash out all stored processes
|
|
408
394
|
if (forceClosed === true) {
|
|
409
395
|
this.s.storeOptions.force = forceClosed;
|
|
410
396
|
this.s.store.flush();
|
|
411
397
|
}
|
|
398
|
+
|
|
399
|
+
this.s.coreTopology.destroy(
|
|
400
|
+
{
|
|
401
|
+
force: typeof forceClosed === 'boolean' ? forceClosed : false
|
|
402
|
+
},
|
|
403
|
+
callback
|
|
404
|
+
);
|
|
412
405
|
}
|
|
413
406
|
}
|
|
414
407
|
|