Cleanup
This commit is contained in:
2757
node_modules/mongodb/HISTORY.md
generated
vendored
2757
node_modules/mongodb/HISTORY.md
generated
vendored
File diff suppressed because it is too large
Load Diff
132
node_modules/mongodb/README.md
generated
vendored
132
node_modules/mongodb/README.md
generated
vendored
@@ -1,23 +1,24 @@
|
||||
[](https://nodei.co/npm/mongodb/) [](https://nodei.co/npm/mongodb/)
|
||||
# MongoDB NodeJS Driver
|
||||
|
||||
[](http://travis-ci.org/mongodb/node-mongodb-native)
|
||||
[](https://coveralls.io/github/mongodb/node-mongodb-native?branch=2.1)
|
||||
[](https://gitter.im/mongodb/node-mongodb-native?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[](https://nodei.co/npm/mongodb/)
|
||||
|
||||
# Description
|
||||
The official [MongoDB](https://www.mongodb.com/) driver for Node.js.
|
||||
|
||||
The official [MongoDB](https://www.mongodb.com/) driver for Node.js. Provides a high-level API on top of [mongodb-core](https://www.npmjs.com/package/mongodb-core) that is meant for end users.
|
||||
**NOTE: v3.x released with breaking API changes. You can find a list of changes [here](CHANGES_3.0.0.md).**
|
||||
|
||||
**NOTE: v3.x was recently released with breaking API changes. You can find a list of changes [here](CHANGES_3.0.0.md).**
|
||||
## Version 4.0
|
||||
|
||||
## MongoDB Node.JS Driver
|
||||
**Looking for the latest?** We're working on the next major version of the driver, now in beta.
|
||||
Check out our [beta version 4.0 here](https://github.com/mongodb/node-mongodb-native/tree/4.0), which includes a full migration of the driver to TypeScript.
|
||||
|
||||
| what | where |
|
||||
|---------------|------------------------------------------------|
|
||||
| documentation | http://mongodb.github.io/node-mongodb-native |
|
||||
| api-doc | http://mongodb.github.io/node-mongodb-native/3.1/api |
|
||||
| source | https://github.com/mongodb/node-mongodb-native |
|
||||
| mongodb | http://www.mongodb.org |
|
||||
## Quick Links
|
||||
|
||||
| what | where |
|
||||
| ------------- | ---------------------------------------------------- |
|
||||
| documentation | https://mongodb.github.io/node-mongodb-native |
|
||||
| api-doc | https://mongodb.github.io/node-mongodb-native/3.6/api |
|
||||
| source | https://github.com/mongodb/node-mongodb-native |
|
||||
| mongodb | https://www.mongodb.org |
|
||||
|
||||
### Bugs / Feature Requests
|
||||
|
||||
@@ -43,12 +44,12 @@ Change history can be found in [`HISTORY.md`](HISTORY.md).
|
||||
|
||||
For version compatibility matrices, please refer to the following links:
|
||||
|
||||
* [MongoDB](https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/#reference-compatibility-mongodb-node)
|
||||
* [NodeJS](https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/#reference-compatibility-language-node)
|
||||
- [MongoDB](https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/#reference-compatibility-mongodb-node)
|
||||
- [NodeJS](https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/#reference-compatibility-language-node)
|
||||
|
||||
# Installation
|
||||
## Installation
|
||||
|
||||
The recommended way to get started using the Node.js 3.0 driver is by using the `npm` (Node Package Manager) to install the dependency in your project.
|
||||
The recommended way to get started using the Node.js driver is by using `npm` (Node Package Manager) to install the dependency in your project.
|
||||
|
||||
## MongoDB Driver
|
||||
|
||||
@@ -66,10 +67,10 @@ You can also use the [Yarn](https://yarnpkg.com/en) package manager.
|
||||
|
||||
The MongoDB driver depends on several other packages. These are:
|
||||
|
||||
* [mongodb-core](https://github.com/mongodb-js/mongodb-core)
|
||||
* [bson](https://github.com/mongodb/js-bson)
|
||||
* [kerberos](https://github.com/mongodb-js/kerberos)
|
||||
* [node-gyp](https://github.com/nodejs/node-gyp)
|
||||
- [bson](https://github.com/mongodb/js-bson)
|
||||
- [bson-ext](https://github.com/mongodb-js/bson-ext)
|
||||
- [kerberos](https://github.com/mongodb-js/kerberos)
|
||||
- [mongodb-client-encryption](https://github.com/mongodb/libmongocrypt#readme)
|
||||
|
||||
The `kerberos` package is a C++ extension that requires a build environment to be installed on your system. You must be able to build Node.js itself in order to compile and install the `kerberos` module. Furthermore, the `kerberos` module requires the MIT Kerberos package to correctly compile on UNIX operating systems. Consult your UNIX operation system package manager for what libraries to install.
|
||||
|
||||
@@ -110,9 +111,9 @@ This will print out all the steps npm is performing while trying to install the
|
||||
|
||||
A compiler tool chain known to work for compiling `kerberos` on Windows is the following.
|
||||
|
||||
* Visual Studio C++ 2010 (do not use higher versions)
|
||||
* Windows 7 64bit SDK
|
||||
* Python 2.7 or higher
|
||||
- Visual Studio C++ 2010 (do not use higher versions)
|
||||
- Windows 7 64bit SDK
|
||||
- Python 2.7 or higher
|
||||
|
||||
Open the Visual Studio command prompt. Ensure `node.exe` is in your path and install `node-gyp`.
|
||||
|
||||
@@ -170,7 +171,7 @@ For complete MongoDB installation instructions, see [the manual](https://docs.mo
|
||||
|
||||
1. Download the right MongoDB version from [MongoDB](https://www.mongodb.org/downloads)
|
||||
2. Create a database directory (in this case under **/data**).
|
||||
3. Install and start a ``mongod`` process.
|
||||
3. Install and start a `mongod` process.
|
||||
|
||||
```bash
|
||||
mongod --dbpath=/data
|
||||
@@ -194,11 +195,11 @@ const url = 'mongodb://localhost:27017';
|
||||
|
||||
// Database Name
|
||||
const dbName = 'myproject';
|
||||
|
||||
const client = new MongoClient(url);
|
||||
// Use connect method to connect to the server
|
||||
MongoClient.connect(url, function(err, client) {
|
||||
client.connect(function(err) {
|
||||
assert.equal(null, err);
|
||||
console.log("Connected successfully to server");
|
||||
console.log('Connected successfully to server');
|
||||
|
||||
const db = client.db(dbName);
|
||||
|
||||
@@ -224,23 +225,21 @@ const insertDocuments = function(db, callback) {
|
||||
// Get the documents collection
|
||||
const collection = db.collection('documents');
|
||||
// Insert some documents
|
||||
collection.insertMany([
|
||||
{a : 1}, {a : 2}, {a : 3}
|
||||
], function(err, result) {
|
||||
collection.insertMany([{ a: 1 }, { a: 2 }, { a: 3 }], function(err, result) {
|
||||
assert.equal(err, null);
|
||||
assert.equal(3, result.result.n);
|
||||
assert.equal(3, result.ops.length);
|
||||
console.log("Inserted 3 documents into the collection");
|
||||
console.log('Inserted 3 documents into the collection');
|
||||
callback(result);
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
The **insert** command returns an object with the following fields:
|
||||
|
||||
* **result** Contains the result document from MongoDB
|
||||
* **ops** Contains the documents inserted with added **_id** fields
|
||||
* **connection** Contains the connection used to perform the insert
|
||||
- **result** Contains the result document from MongoDB
|
||||
- **ops** Contains the documents inserted with added **\_id** fields
|
||||
- **connection** Contains the connection used to perform the insert
|
||||
|
||||
Add the following code to call the **insertDocuments** function:
|
||||
|
||||
@@ -257,7 +256,7 @@ const dbName = 'myproject';
|
||||
// Use connect method to connect to the server
|
||||
MongoClient.connect(url, function(err, client) {
|
||||
assert.equal(null, err);
|
||||
console.log("Connected successfully to server");
|
||||
console.log('Connected successfully to server');
|
||||
|
||||
const db = client.db(dbName);
|
||||
|
||||
@@ -291,11 +290,11 @@ const findDocuments = function(db, callback) {
|
||||
// Find some documents
|
||||
collection.find({}).toArray(function(err, docs) {
|
||||
assert.equal(err, null);
|
||||
console.log("Found the following records");
|
||||
console.log(docs)
|
||||
console.log('Found the following records');
|
||||
console.log(docs);
|
||||
callback(docs);
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
This query returns all the documents in the **documents** collection. Add the **findDocument** method to the **MongoClient.connect** callback:
|
||||
@@ -313,7 +312,7 @@ const dbName = 'myproject';
|
||||
// Use connect method to connect to the server
|
||||
MongoClient.connect(url, function(err, client) {
|
||||
assert.equal(null, err);
|
||||
console.log("Connected correctly to server");
|
||||
console.log('Connected correctly to server');
|
||||
|
||||
const db = client.db(dbName);
|
||||
|
||||
@@ -334,16 +333,16 @@ const findDocuments = function(db, callback) {
|
||||
// Get the documents collection
|
||||
const collection = db.collection('documents');
|
||||
// Find some documents
|
||||
collection.find({'a': 3}).toArray(function(err, docs) {
|
||||
collection.find({ a: 3 }).toArray(function(err, docs) {
|
||||
assert.equal(err, null);
|
||||
console.log("Found the following records");
|
||||
console.log('Found the following records');
|
||||
console.log(docs);
|
||||
callback(docs);
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Only the documents which match ``'a' : 3`` should be returned.
|
||||
Only the documents which match `'a' : 3` should be returned.
|
||||
|
||||
### Update a document
|
||||
|
||||
@@ -354,14 +353,13 @@ const updateDocument = function(db, callback) {
|
||||
// Get the documents collection
|
||||
const collection = db.collection('documents');
|
||||
// Update document where a is 2, set b equal to 1
|
||||
collection.updateOne({ a : 2 }
|
||||
, { $set: { b : 1 } }, function(err, result) {
|
||||
collection.updateOne({ a: 2 }, { $set: { b: 1 } }, function(err, result) {
|
||||
assert.equal(err, null);
|
||||
assert.equal(1, result.result.n);
|
||||
console.log("Updated the document with the field a equal to 2");
|
||||
console.log('Updated the document with the field a equal to 2');
|
||||
callback(result);
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
The method updates the first document where the field **a** is equal to **2** by adding a new field **b** to the document set to **1**. Next, update the callback function from **MongoClient.connect** to include the update method.
|
||||
@@ -379,7 +377,7 @@ const dbName = 'myproject';
|
||||
// Use connect method to connect to the server
|
||||
MongoClient.connect(url, function(err, client) {
|
||||
assert.equal(null, err);
|
||||
console.log("Connected successfully to server");
|
||||
console.log('Connected successfully to server');
|
||||
|
||||
const db = client.db(dbName);
|
||||
|
||||
@@ -400,13 +398,13 @@ const removeDocument = function(db, callback) {
|
||||
// Get the documents collection
|
||||
const collection = db.collection('documents');
|
||||
// Delete document where a is 3
|
||||
collection.deleteOne({ a : 3 }, function(err, result) {
|
||||
collection.deleteOne({ a: 3 }, function(err, result) {
|
||||
assert.equal(err, null);
|
||||
assert.equal(1, result.result.n);
|
||||
console.log("Removed the document with the field a equal to 3");
|
||||
console.log('Removed the document with the field a equal to 3');
|
||||
callback(result);
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Add the new method to the **MongoClient.connect** callback function.
|
||||
@@ -424,7 +422,7 @@ const dbName = 'myproject';
|
||||
// Use connect method to connect to the server
|
||||
MongoClient.connect(url, function(err, client) {
|
||||
assert.equal(null, err);
|
||||
console.log("Connected successfully to server");
|
||||
console.log('Connected successfully to server');
|
||||
|
||||
const db = client.db(dbName);
|
||||
|
||||
@@ -446,18 +444,14 @@ performance. The following function creates an index on the **a** field in the
|
||||
|
||||
```js
|
||||
const indexCollection = function(db, callback) {
|
||||
db.collection('documents').createIndex(
|
||||
{ "a": 1 },
|
||||
null,
|
||||
function(err, results) {
|
||||
console.log(results);
|
||||
callback();
|
||||
}
|
||||
);
|
||||
db.collection('documents').createIndex({ a: 1 }, null, function(err, results) {
|
||||
console.log(results);
|
||||
callback();
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
Add the ``indexCollection`` method to your app:
|
||||
Add the `indexCollection` method to your app:
|
||||
|
||||
```js
|
||||
const MongoClient = require('mongodb').MongoClient;
|
||||
@@ -471,7 +465,7 @@ const dbName = 'myproject';
|
||||
// Use connect method to connect to the server
|
||||
MongoClient.connect(url, function(err, client) {
|
||||
assert.equal(null, err);
|
||||
console.log("Connected successfully to server");
|
||||
console.log('Connected successfully to server');
|
||||
|
||||
const db = client.db(dbName);
|
||||
|
||||
@@ -487,13 +481,13 @@ For more detailed information, see the [tutorials](docs/reference/content/tutori
|
||||
|
||||
## Next Steps
|
||||
|
||||
* [MongoDB Documentation](http://mongodb.org)
|
||||
* [Read about Schemas](http://learnmongodbthehardway.com)
|
||||
* [Star us on GitHub](https://github.com/mongodb/node-mongodb-native)
|
||||
- [MongoDB Documentation](https://mongodb.org)
|
||||
- [Read about Schemas](http://learnmongodbthehardway.com)
|
||||
- [Star us on GitHub](https://github.com/mongodb/node-mongodb-native)
|
||||
|
||||
## License
|
||||
|
||||
[Apache 2.0](LICENSE.md)
|
||||
|
||||
© 2009-2012 Christian Amor Kvalheim
|
||||
© 2009-2012 Christian Amor Kvalheim
|
||||
© 2012-present MongoDB [Contributors](CONTRIBUTORS.md)
|
||||
|
||||
4
node_modules/mongodb/index.js
generated
vendored
4
node_modules/mongodb/index.js
generated
vendored
@@ -17,6 +17,9 @@ connect.MongoWriteConcernError = core.MongoWriteConcernError;
|
||||
connect.MongoBulkWriteError = require('./lib/bulk/common').BulkWriteError;
|
||||
connect.BulkWriteError = connect.MongoBulkWriteError;
|
||||
|
||||
// Expose server versions
|
||||
connect.ServerApiVersion = core.ServerApiVersion;
|
||||
|
||||
// Actual driver classes exported
|
||||
connect.Admin = require('./lib/admin');
|
||||
connect.MongoClient = require('./lib/mongo_client');
|
||||
@@ -47,6 +50,7 @@ connect.Int32 = core.BSON.Int32;
|
||||
connect.Long = core.BSON.Long;
|
||||
connect.MinKey = core.BSON.MinKey;
|
||||
connect.MaxKey = core.BSON.MaxKey;
|
||||
/** @deprecated Please use `ObjectId` */
|
||||
connect.ObjectID = core.BSON.ObjectID;
|
||||
connect.ObjectId = core.BSON.ObjectID;
|
||||
connect.Symbol = core.BSON.Symbol;
|
||||
|
||||
19
node_modules/mongodb/lib/admin.js
generated
vendored
19
node_modules/mongodb/lib/admin.js
generated
vendored
@@ -166,10 +166,11 @@ Admin.prototype.ping = function(options, callback) {
|
||||
* @param {string} username The username.
|
||||
* @param {string} password The password.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {boolean} [options.fsync=false] Specify a file sync write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {boolean} [options.fsync=false] **Deprecated** Specify a file sync write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {object} [options.customData] Custom data associated with the user (only Mongodb 2.6 or higher)
|
||||
* @param {object[]} [options.roles] Roles associated with the created user (only Mongodb 2.6 or higher)
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
@@ -203,10 +204,11 @@ Admin.prototype.addUser = function(username, password, options, callback) {
|
||||
* @method
|
||||
* @param {string} username The username.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {boolean} [options.fsync=false] Specify a file sync write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {boolean} [options.fsync=false] **Deprecated** Specify a file sync write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Admin~resultCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
@@ -232,6 +234,7 @@ Admin.prototype.removeUser = function(username, options, callback) {
|
||||
*
|
||||
* @param {string} collectionName The name of the collection to validate.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {boolean} [options.background] Validates a collection in the background, without interrupting read or write traffic (only in MongoDB 4.4+)
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Admin~resultCallback} [callback] The command result callback.
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
|
||||
15
node_modules/mongodb/lib/aggregation_cursor.js
generated
vendored
15
node_modules/mongodb/lib/aggregation_cursor.js
generated
vendored
@@ -3,7 +3,6 @@
|
||||
const MongoError = require('./core').MongoError;
|
||||
const Cursor = require('./cursor');
|
||||
const CursorState = require('./core/cursor').CursorState;
|
||||
const deprecate = require('util').deprecate;
|
||||
|
||||
/**
|
||||
* @fileOverview The **AggregationCursor** class is an internal class that embodies an aggregation cursor on MongoDB
|
||||
@@ -203,7 +202,7 @@ class AggregationCursor extends Cursor {
|
||||
/**
|
||||
* Add a unwind stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {number} field The unwind field name.
|
||||
* @param {(string|object)} field The unwind field name or stage document.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
unwind(field) {
|
||||
@@ -225,12 +224,6 @@ class AggregationCursor extends Cursor {
|
||||
// aliases
|
||||
AggregationCursor.prototype.get = AggregationCursor.prototype.toArray;
|
||||
|
||||
// deprecated methods
|
||||
deprecate(
|
||||
AggregationCursor.prototype.geoNear,
|
||||
'The `$geoNear` stage is deprecated in MongoDB 4.0, and removed in version 4.2.'
|
||||
);
|
||||
|
||||
/**
|
||||
* AggregationCursor stream data event, fired for each document in the cursor.
|
||||
*
|
||||
@@ -329,7 +322,13 @@ deprecate(
|
||||
|
||||
/**
|
||||
* Execute the explain for the cursor
|
||||
*
|
||||
* For backwards compatibility, a verbosity of true is interpreted as "allPlansExecution"
|
||||
* and false as "queryPlanner". Prior to server version 3.6, aggregate()
|
||||
* ignores the verbosity parameter and executes in "queryPlanner".
|
||||
*
|
||||
* @method AggregationCursor.prototype.explain
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [verbosity=true] - An optional mode in which to run the explain.
|
||||
* @param {AggregationCursor~resultCallback} [callback] The result callback.
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
|
||||
234
node_modules/mongodb/lib/bulk/common.js
generated
vendored
234
node_modules/mongodb/lib/bulk/common.js
generated
vendored
@@ -5,12 +5,15 @@ const MongoError = require('../core').MongoError;
|
||||
const ObjectID = require('../core').BSON.ObjectID;
|
||||
const BSON = require('../core').BSON;
|
||||
const MongoWriteConcernError = require('../core').MongoWriteConcernError;
|
||||
const emitWarningOnce = require('../utils').emitWarningOnce;
|
||||
const toError = require('../utils').toError;
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const applyRetryableWrites = require('../utils').applyRetryableWrites;
|
||||
const applyWriteConcern = require('../utils').applyWriteConcern;
|
||||
const executeLegacyOperation = require('../utils').executeLegacyOperation;
|
||||
const isPromiseLike = require('../utils').isPromiseLike;
|
||||
const hasAtomicOperators = require('../utils').hasAtomicOperators;
|
||||
const maxWireVersion = require('../core/utils').maxWireVersion;
|
||||
|
||||
// Error codes
|
||||
const WRITE_CONCERN_ERROR = 64;
|
||||
@@ -54,6 +57,9 @@ class Batch {
|
||||
}
|
||||
}
|
||||
|
||||
const kUpsertedIds = Symbol('upsertedIds');
|
||||
const kInsertedIds = Symbol('insertedIds');
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* The result of a bulk write.
|
||||
@@ -66,6 +72,60 @@ class BulkWriteResult {
|
||||
*/
|
||||
constructor(bulkResult) {
|
||||
this.result = bulkResult;
|
||||
this[kUpsertedIds] = undefined;
|
||||
this[kInsertedIds] = undefined;
|
||||
}
|
||||
|
||||
/** Number of documents inserted. */
|
||||
get insertedCount() {
|
||||
return typeof this.result.nInserted !== 'number' ? 0 : this.result.nInserted;
|
||||
}
|
||||
/** Number of documents matched for update. */
|
||||
get matchedCount() {
|
||||
return typeof this.result.nMatched !== 'number' ? 0 : this.result.nMatched;
|
||||
}
|
||||
/** Number of documents modified. */
|
||||
get modifiedCount() {
|
||||
return typeof this.result.nModified !== 'number' ? 0 : this.result.nModified;
|
||||
}
|
||||
/** Number of documents deleted. */
|
||||
get deletedCount() {
|
||||
return typeof this.result.nRemoved !== 'number' ? 0 : this.result.nRemoved;
|
||||
}
|
||||
/** Number of documents upserted. */
|
||||
get upsertedCount() {
|
||||
return !this.result.upserted ? 0 : this.result.upserted.length;
|
||||
}
|
||||
|
||||
/** Upserted document generated Id's, hash key is the index of the originating operation */
|
||||
get upsertedIds() {
|
||||
if (this[kUpsertedIds]) {
|
||||
return this[kUpsertedIds];
|
||||
}
|
||||
|
||||
this[kUpsertedIds] = {};
|
||||
for (const doc of this.result.upserted || []) {
|
||||
this[kUpsertedIds][doc.index] = doc._id;
|
||||
}
|
||||
return this[kUpsertedIds];
|
||||
}
|
||||
|
||||
/** Inserted document generated Id's, hash key is the index of the originating operation */
|
||||
get insertedIds() {
|
||||
if (this[kInsertedIds]) {
|
||||
return this[kInsertedIds];
|
||||
}
|
||||
|
||||
this[kInsertedIds] = {};
|
||||
for (const doc of this.result.insertedIds || []) {
|
||||
this[kInsertedIds][doc.index] = doc._id;
|
||||
}
|
||||
return this[kInsertedIds];
|
||||
}
|
||||
|
||||
/** The number of inserted documents @type {number} */
|
||||
get n() {
|
||||
return this.result.insertedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,6 +414,15 @@ class WriteError {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the number to a Long or returns it.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
function longOrConvert(value) {
|
||||
return typeof value === 'number' ? Long.fromNumber(value) : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges results into shared data structure
|
||||
* @ignore
|
||||
@@ -385,42 +454,37 @@ function mergeBatchResults(batch, bulkResult, err, result) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Deal with opTime if available
|
||||
// The server write command specification states that lastOp is an optional
|
||||
// mongod only field that has a type of timestamp. Across various scarce specs
|
||||
// where opTime is mentioned, it is an "opaque" object that can have a "ts" and
|
||||
// "t" field with Timestamp and Long as their types respectively.
|
||||
// The "lastOp" field of the bulk write result is never mentioned in the driver
|
||||
// specifications or the bulk write spec, so we should probably just keep its
|
||||
// value consistent since it seems to vary.
|
||||
// See: https://github.com/mongodb/specifications/blob/master/source/driver-bulk-update.rst#results-object
|
||||
if (result.opTime || result.lastOp) {
|
||||
const opTime = result.lastOp || result.opTime;
|
||||
let lastOpTS = null;
|
||||
let lastOpT = null;
|
||||
let opTime = result.lastOp || result.opTime;
|
||||
|
||||
// We have a time stamp
|
||||
if (opTime && opTime._bsontype === 'Timestamp') {
|
||||
if (bulkResult.lastOp == null) {
|
||||
bulkResult.lastOp = opTime;
|
||||
} else if (opTime.greaterThan(bulkResult.lastOp)) {
|
||||
bulkResult.lastOp = opTime;
|
||||
}
|
||||
// If the opTime is a Timestamp, convert it to a consistent format to be
|
||||
// able to compare easily. Converting to the object from a timestamp is
|
||||
// much more straightforward than the other direction.
|
||||
if (opTime._bsontype === 'Timestamp') {
|
||||
opTime = { ts: opTime, t: Long.ZERO };
|
||||
}
|
||||
|
||||
// If there's no lastOp, just set it.
|
||||
if (!bulkResult.lastOp) {
|
||||
bulkResult.lastOp = opTime;
|
||||
} else {
|
||||
// Existing TS
|
||||
if (bulkResult.lastOp) {
|
||||
lastOpTS =
|
||||
typeof bulkResult.lastOp.ts === 'number'
|
||||
? Long.fromNumber(bulkResult.lastOp.ts)
|
||||
: bulkResult.lastOp.ts;
|
||||
lastOpT =
|
||||
typeof bulkResult.lastOp.t === 'number'
|
||||
? Long.fromNumber(bulkResult.lastOp.t)
|
||||
: bulkResult.lastOp.t;
|
||||
}
|
||||
|
||||
// Current OpTime TS
|
||||
const opTimeTS = typeof opTime.ts === 'number' ? Long.fromNumber(opTime.ts) : opTime.ts;
|
||||
const opTimeT = typeof opTime.t === 'number' ? Long.fromNumber(opTime.t) : opTime.t;
|
||||
|
||||
// Compare the opTime's
|
||||
if (bulkResult.lastOp == null) {
|
||||
bulkResult.lastOp = opTime;
|
||||
} else if (opTimeTS.greaterThan(lastOpTS)) {
|
||||
// First compare the ts values and set if the opTimeTS value is greater.
|
||||
const lastOpTS = longOrConvert(bulkResult.lastOp.ts);
|
||||
const opTimeTS = longOrConvert(opTime.ts);
|
||||
if (opTimeTS.greaterThan(lastOpTS)) {
|
||||
bulkResult.lastOp = opTime;
|
||||
} else if (opTimeTS.equals(lastOpTS)) {
|
||||
// If the ts values are equal, then compare using the t values.
|
||||
const lastOpT = longOrConvert(bulkResult.lastOp.t);
|
||||
const opTimeT = longOrConvert(opTime.t);
|
||||
if (opTimeT.greaterThan(lastOpT)) {
|
||||
bulkResult.lastOp = opTime;
|
||||
}
|
||||
@@ -569,6 +633,35 @@ class BulkWriteError extends MongoError {
|
||||
this.name = 'BulkWriteError';
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
/** Number of documents inserted. */
|
||||
get insertedCount() {
|
||||
return this.result.insertedCount;
|
||||
}
|
||||
/** Number of documents matched for update. */
|
||||
get matchedCount() {
|
||||
return this.result.matchedCount;
|
||||
}
|
||||
/** Number of documents modified. */
|
||||
get modifiedCount() {
|
||||
return this.result.modifiedCount;
|
||||
}
|
||||
/** Number of documents deleted. */
|
||||
get deletedCount() {
|
||||
return this.result.deletedCount;
|
||||
}
|
||||
/** Number of documents upserted. */
|
||||
get upsertedCount() {
|
||||
return this.result.upsertedCount;
|
||||
}
|
||||
/** Inserted document generated Id's, hash key is the index of the originating operation */
|
||||
get insertedIds() {
|
||||
return this.result.insertedIds;
|
||||
}
|
||||
/** Upserted document generated Id's, hash key is the index of the originating operation */
|
||||
get upsertedIds() {
|
||||
return this.result.upsertedIds;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -641,6 +734,10 @@ class FindOperators {
|
||||
document.hint = updateDocument.hint;
|
||||
}
|
||||
|
||||
if (!hasAtomicOperators(updateDocument)) {
|
||||
throw new TypeError('Update document requires atomic operators');
|
||||
}
|
||||
|
||||
// Clear out current Op
|
||||
this.s.currentOp = null;
|
||||
return this.s.options.addToOperationsList(this, UPDATE, document);
|
||||
@@ -650,12 +747,33 @@ class FindOperators {
|
||||
* Add a replace one operation to the bulk operation
|
||||
*
|
||||
* @method
|
||||
* @param {object} updateDocument the new document to replace the existing one with
|
||||
* @param {object} replacement the new document to replace the existing one with
|
||||
* @throws {MongoError} If operation cannot be added to bulk write
|
||||
* @return {OrderedBulkOperation|UnorderedBulkOperation} A reference to the parent BulkOperation
|
||||
*/
|
||||
replaceOne(updateDocument) {
|
||||
this.updateOne(updateDocument);
|
||||
replaceOne(replacement) {
|
||||
// Perform upsert
|
||||
const upsert = typeof this.s.currentOp.upsert === 'boolean' ? this.s.currentOp.upsert : false;
|
||||
|
||||
// Establish the update command
|
||||
const document = {
|
||||
q: this.s.currentOp.selector,
|
||||
u: replacement,
|
||||
multi: false,
|
||||
upsert: upsert
|
||||
};
|
||||
|
||||
if (replacement.hint) {
|
||||
document.hint = replacement.hint;
|
||||
}
|
||||
|
||||
if (hasAtomicOperators(replacement)) {
|
||||
throw new TypeError('Replacement document must not use atomic operators');
|
||||
}
|
||||
|
||||
// Clear out current Op
|
||||
this.s.currentOp = null;
|
||||
return this.s.options.addToOperationsList(this, UPDATE, document);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -710,15 +828,19 @@ class FindOperators {
|
||||
|
||||
/**
|
||||
* backwards compatability for deleteOne
|
||||
* @deprecated
|
||||
*/
|
||||
removeOne() {
|
||||
emitWarningOnce('bulk operation `removeOne` has been deprecated, please use `deleteOne`');
|
||||
return this.deleteOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* backwards compatability for delete
|
||||
* @deprecated
|
||||
*/
|
||||
remove() {
|
||||
emitWarningOnce('bulk operation `remove` has been deprecated, please use `delete`');
|
||||
return this.delete();
|
||||
}
|
||||
}
|
||||
@@ -943,6 +1065,12 @@ class BulkOperationBase {
|
||||
|
||||
// Crud spec update format
|
||||
if (op.updateOne || op.updateMany || op.replaceOne) {
|
||||
if (op.replaceOne && hasAtomicOperators(op[key].replacement)) {
|
||||
throw new TypeError('Replacement document must not use atomic operators');
|
||||
} else if ((op.updateOne || op.updateMany) && !hasAtomicOperators(op[key].update)) {
|
||||
throw new TypeError('Update document requires atomic operators');
|
||||
}
|
||||
|
||||
const multi = op.updateOne || op.replaceOne ? false : true;
|
||||
const operation = {
|
||||
q: op[key].filter,
|
||||
@@ -960,7 +1088,15 @@ class BulkOperationBase {
|
||||
} else {
|
||||
if (op[key].upsert) operation.upsert = true;
|
||||
}
|
||||
if (op[key].arrayFilters) operation.arrayFilters = op[key].arrayFilters;
|
||||
if (op[key].arrayFilters) {
|
||||
// TODO: this check should be done at command construction against a connection, not a topology
|
||||
if (maxWireVersion(this.s.topology) < 6) {
|
||||
throw new TypeError('arrayFilters are only supported on MongoDB 3.6+');
|
||||
}
|
||||
|
||||
operation.arrayFilters = op[key].arrayFilters;
|
||||
}
|
||||
|
||||
return this.s.options.addToOperationsList(this, UPDATE, operation);
|
||||
}
|
||||
|
||||
@@ -979,6 +1115,9 @@ class BulkOperationBase {
|
||||
if (op.deleteOne || op.deleteMany) {
|
||||
const limit = op.deleteOne ? 1 : 0;
|
||||
const operation = { q: op[key].filter, limit: limit };
|
||||
if (op[key].hint) {
|
||||
operation.hint = op[key].hint;
|
||||
}
|
||||
if (this.isOrdered) {
|
||||
if (op.collation) operation.collation = op.collation;
|
||||
}
|
||||
@@ -997,6 +1136,9 @@ class BulkOperationBase {
|
||||
}
|
||||
|
||||
if (op.insertMany) {
|
||||
emitWarningOnce(
|
||||
'bulk operation `insertMany` has been deprecated; use multiple `insertOne` ops instead'
|
||||
);
|
||||
for (let i = 0; i < op.insertMany.length; i++) {
|
||||
if (forceServerObjectId !== true && op.insertMany[i]._id == null)
|
||||
op.insertMany[i]._id = new ObjectID();
|
||||
@@ -1038,8 +1180,11 @@ class BulkOperationBase {
|
||||
* @param {function} callback
|
||||
*/
|
||||
bulkExecute(_writeConcern, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
}
|
||||
|
||||
const finalOptions = Object.assign({}, this.s.options, options);
|
||||
|
||||
if (typeof _writeConcern === 'function') {
|
||||
callback = _writeConcern;
|
||||
@@ -1065,7 +1210,7 @@ class BulkOperationBase {
|
||||
const emptyBatchError = toError('Invalid Operation, no operations specified');
|
||||
return this._handleEarlyError(emptyBatchError, callback);
|
||||
}
|
||||
return { options, callback };
|
||||
return { options: finalOptions, callback };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1081,10 +1226,11 @@ class BulkOperationBase {
|
||||
* @method
|
||||
* @param {WriteConcern} [_writeConcern] Optional write concern. Can also be specified through options.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {boolean} [options.fsync=false] Specify a file sync write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {boolean} [options.fsync=false] **Deprecated** Specify a file sync write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {BulkOperationBase~resultCallback} [callback] A callback that will be invoked when bulkWrite finishes/errors
|
||||
* @throws {MongoError} Throws error if the bulk object has already been executed
|
||||
* @throws {MongoError} Throws error if the bulk object does not have any operations
|
||||
@@ -1245,9 +1391,11 @@ Object.defineProperty(BulkOperationBase.prototype, 'length', {
|
||||
module.exports = {
|
||||
Batch,
|
||||
BulkOperationBase,
|
||||
mergeBatchResults,
|
||||
bson,
|
||||
INSERT: INSERT,
|
||||
UPDATE: UPDATE,
|
||||
REMOVE: REMOVE,
|
||||
BulkWriteError
|
||||
BulkWriteError,
|
||||
BulkWriteResult
|
||||
};
|
||||
|
||||
12
node_modules/mongodb/lib/change_stream.js
generated
vendored
12
node_modules/mongodb/lib/change_stream.js
generated
vendored
@@ -169,7 +169,6 @@ class ChangeStream extends EventEmitter {
|
||||
/**
|
||||
* Is the change stream closed
|
||||
* @method ChangeStream.prototype.isClosed
|
||||
* @param {boolean} [checkCursor=true] also check if the underlying cursor is closed
|
||||
* @return {boolean}
|
||||
*/
|
||||
isClosed() {
|
||||
@@ -326,8 +325,8 @@ class ChangeStreamCursor extends Cursor {
|
||||
|
||||
_initializeCursor(callback) {
|
||||
super._initializeCursor((err, result) => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
if (err || result == null) {
|
||||
callback(err, result);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -438,7 +437,7 @@ function createChangeStreamCursor(self, options) {
|
||||
|
||||
if (self.pipeDestinations) {
|
||||
const cursorStream = changeStreamCursor.stream(self.streamOptions);
|
||||
for (let pipeDestination in self.pipeDestinations) {
|
||||
for (let pipeDestination of self.pipeDestinations) {
|
||||
cursorStream.pipe(pipeDestination);
|
||||
}
|
||||
}
|
||||
@@ -483,6 +482,11 @@ function waitForTopologyConnected(topology, options, callback) {
|
||||
function processNewChange(changeStream, change, callback) {
|
||||
const cursor = changeStream.cursor;
|
||||
|
||||
// a null change means the cursor has been notified, implicitly closing the change stream
|
||||
if (change == null) {
|
||||
changeStream.closed = true;
|
||||
}
|
||||
|
||||
if (changeStream.closed) {
|
||||
if (callback) callback(new MongoError('ChangeStream is closed'));
|
||||
return;
|
||||
|
||||
117
node_modules/mongodb/lib/cmap/connection.js
generated
vendored
117
node_modules/mongodb/lib/cmap/connection.js
generated
vendored
@@ -4,6 +4,7 @@ const EventEmitter = require('events');
|
||||
const MessageStream = require('./message_stream');
|
||||
const MongoError = require('../core/error').MongoError;
|
||||
const MongoNetworkError = require('../core/error').MongoNetworkError;
|
||||
const MongoNetworkTimeoutError = require('../core/error').MongoNetworkTimeoutError;
|
||||
const MongoWriteConcernError = require('../core/error').MongoWriteConcernError;
|
||||
const CommandResult = require('../core/connection/command_result');
|
||||
const StreamDescription = require('./stream_description').StreamDescription;
|
||||
@@ -31,9 +32,13 @@ class Connection extends EventEmitter {
|
||||
this.id = options.id;
|
||||
this.address = streamIdentifier(stream);
|
||||
this.bson = options.bson;
|
||||
this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
|
||||
this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 0;
|
||||
this.host = options.host || 'localhost';
|
||||
this.port = options.port || 27017;
|
||||
this.monitorCommands =
|
||||
typeof options.monitorCommands === 'boolean' ? options.monitorCommands : false;
|
||||
this.serverApi = options.serverApi;
|
||||
|
||||
this.closed = false;
|
||||
this.destroyed = false;
|
||||
|
||||
@@ -55,34 +60,9 @@ class Connection extends EventEmitter {
|
||||
/* ignore errors, listen to `close` instead */
|
||||
});
|
||||
|
||||
stream.on('close', () => {
|
||||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.closed = true;
|
||||
this[kQueue].forEach(op =>
|
||||
op.cb(new MongoNetworkError(`connection ${this.id} to ${this.address} closed`))
|
||||
);
|
||||
this[kQueue].clear();
|
||||
|
||||
this.emit('close');
|
||||
});
|
||||
|
||||
stream.on('timeout', () => {
|
||||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
stream.destroy();
|
||||
this.closed = true;
|
||||
this[kQueue].forEach(op =>
|
||||
op.cb(new MongoNetworkError(`connection ${this.id} to ${this.address} timed out`))
|
||||
);
|
||||
this[kQueue].clear();
|
||||
|
||||
this.emit('close');
|
||||
});
|
||||
this[kMessageStream].on('error', error => this.handleIssue({ destroy: error }));
|
||||
stream.on('close', () => this.handleIssue({ isClose: true }));
|
||||
stream.on('timeout', () => this.handleIssue({ isTimeout: true, destroy: true }));
|
||||
|
||||
// hook the message stream up to the passed in stream
|
||||
stream.pipe(this[kMessageStream]);
|
||||
@@ -125,6 +105,39 @@ class Connection extends EventEmitter {
|
||||
this[kLastUseTime] = now();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ isTimeout?: boolean; isClose?: boolean; destroy?: boolean | Error }} issue
|
||||
*/
|
||||
handleIssue(issue) {
|
||||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (issue.destroy) {
|
||||
this[kStream].destroy(typeof issue.destroy === 'boolean' ? undefined : issue.destroy);
|
||||
}
|
||||
|
||||
this.closed = true;
|
||||
|
||||
for (const idAndOp of this[kQueue]) {
|
||||
const op = idAndOp[1];
|
||||
if (issue.isTimeout) {
|
||||
op.cb(
|
||||
new MongoNetworkTimeoutError(`connection ${this.id} to ${this.address} timed out`, {
|
||||
beforeHandshake: this.ismaster == null
|
||||
})
|
||||
);
|
||||
} else if (issue.isClose) {
|
||||
op.cb(new MongoNetworkError(`connection ${this.id} to ${this.address} closed`));
|
||||
} else {
|
||||
op.cb(typeof issue.destroy === 'boolean' ? undefined : issue.destroy);
|
||||
}
|
||||
}
|
||||
|
||||
this[kQueue].clear();
|
||||
this.emit('close');
|
||||
}
|
||||
|
||||
destroy(options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
@@ -159,33 +172,58 @@ class Connection extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
applyApiVersion(options) {
|
||||
if (this.serverApi) {
|
||||
options.serverApi = this.serverApi;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
// Wire protocol methods
|
||||
command(ns, cmd, options, callback) {
|
||||
wp.command(makeServerTrampoline(this), ns, cmd, options, callback);
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
wp.command(makeServerTrampoline(this), ns, cmd, this.applyApiVersion(options), callback);
|
||||
}
|
||||
|
||||
query(ns, cmd, cursorState, options, callback) {
|
||||
wp.query(makeServerTrampoline(this), ns, cmd, cursorState, options, callback);
|
||||
wp.query(
|
||||
makeServerTrampoline(this),
|
||||
ns,
|
||||
cmd,
|
||||
cursorState,
|
||||
this.applyApiVersion(options),
|
||||
callback
|
||||
);
|
||||
}
|
||||
|
||||
getMore(ns, cursorState, batchSize, options, callback) {
|
||||
wp.getMore(makeServerTrampoline(this), ns, cursorState, batchSize, options, callback);
|
||||
wp.getMore(
|
||||
makeServerTrampoline(this),
|
||||
ns,
|
||||
cursorState,
|
||||
batchSize,
|
||||
this.applyApiVersion(options),
|
||||
callback
|
||||
);
|
||||
}
|
||||
|
||||
killCursors(ns, cursorState, callback) {
|
||||
wp.killCursors(makeServerTrampoline(this), ns, cursorState, callback);
|
||||
wp.killCursors(makeServerTrampoline(this), ns, cursorState, this.applyApiVersion({}), callback);
|
||||
}
|
||||
|
||||
insert(ns, ops, options, callback) {
|
||||
wp.insert(makeServerTrampoline(this), ns, ops, options, callback);
|
||||
wp.insert(makeServerTrampoline(this), ns, ops, this.applyApiVersion(options), callback);
|
||||
}
|
||||
|
||||
update(ns, ops, options, callback) {
|
||||
wp.update(makeServerTrampoline(this), ns, ops, options, callback);
|
||||
wp.update(makeServerTrampoline(this), ns, ops, this.applyApiVersion(options), callback);
|
||||
}
|
||||
|
||||
remove(ns, ops, options, callback) {
|
||||
wp.remove(makeServerTrampoline(this), ns, ops, options, callback);
|
||||
wp.remove(makeServerTrampoline(this), ns, ops, this.applyApiVersion(options), callback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +256,7 @@ function messageHandler(conn) {
|
||||
}
|
||||
|
||||
const operationDescription = conn[kQueue].get(message.responseTo);
|
||||
const callback = operationDescription.cb;
|
||||
|
||||
// SERVER-45775: For exhaust responses we should be able to use the same requestId to
|
||||
// track response, however the server currently synthetically produces remote requests
|
||||
@@ -226,10 +265,7 @@ function messageHandler(conn) {
|
||||
if (message.moreToCome) {
|
||||
// requeue the callback for next synthetic request
|
||||
conn[kQueue].set(message.requestId, operationDescription);
|
||||
}
|
||||
|
||||
const callback = operationDescription.cb;
|
||||
if (operationDescription.socketTimeoutOverride) {
|
||||
} else if (operationDescription.socketTimeoutOverride) {
|
||||
conn[kStream].setTimeout(conn.socketTimeout);
|
||||
}
|
||||
|
||||
@@ -308,6 +344,7 @@ function write(command, options, callback) {
|
||||
promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true,
|
||||
promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true,
|
||||
promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false,
|
||||
bsonRegExp: typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : false,
|
||||
raw: typeof options.raw === 'boolean' ? options.raw : false
|
||||
};
|
||||
|
||||
|
||||
26
node_modules/mongodb/lib/cmap/connection_pool.js
generated
vendored
26
node_modules/mongodb/lib/cmap/connection_pool.js
generated
vendored
@@ -41,6 +41,7 @@ const VALID_POOL_OPTIONS = new Set([
|
||||
'ssl',
|
||||
'bson',
|
||||
'connectionType',
|
||||
'serverApi',
|
||||
'monitorCommands',
|
||||
'socketTimeout',
|
||||
'credentials',
|
||||
@@ -95,7 +96,7 @@ const VALID_POOL_OPTIONS = new Set([
|
||||
|
||||
function resolveOptions(options, defaults) {
|
||||
const newOptions = Array.from(VALID_POOL_OPTIONS).reduce((obj, key) => {
|
||||
if (options.hasOwnProperty(key)) {
|
||||
if (Object.prototype.hasOwnProperty.call(options, key)) {
|
||||
obj[key] = options[key];
|
||||
}
|
||||
|
||||
@@ -157,12 +158,13 @@ class ConnectionPool extends EventEmitter {
|
||||
waitQueueTimeoutMS:
|
||||
typeof options.waitQueueTimeoutMS === 'number' ? options.waitQueueTimeoutMS : 0,
|
||||
autoEncrypter: options.autoEncrypter,
|
||||
metadata: options.metadata
|
||||
metadata: options.metadata,
|
||||
useUnifiedTopology: options.useUnifiedTopology
|
||||
});
|
||||
|
||||
if (options.minSize > options.maxSize) {
|
||||
throw new TypeError(
|
||||
'Connection pool minimum size must not be greater than maxiumum pool size'
|
||||
'Connection pool minimum size must not be greater than maximum pool size'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -218,7 +220,6 @@ class ConnectionPool extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
// add this request to the wait queue
|
||||
const waitQueueMember = { callback };
|
||||
|
||||
const pool = this;
|
||||
@@ -233,11 +234,8 @@ class ConnectionPool extends EventEmitter {
|
||||
}, waitQueueTimeoutMS);
|
||||
}
|
||||
|
||||
// place the member at the end of the wait queue
|
||||
this[kWaitQueue].push(waitQueueMember);
|
||||
|
||||
// process the wait queue
|
||||
processWaitQueue(this);
|
||||
process.nextTick(() => processWaitQueue(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,10 +248,8 @@ class ConnectionPool extends EventEmitter {
|
||||
const stale = connectionIsStale(this, connection);
|
||||
const willDestroy = !!(poolClosed || stale || connection.closed);
|
||||
|
||||
// Properly adjust state of connection
|
||||
if (!willDestroy) {
|
||||
connection.markAvailable();
|
||||
|
||||
this[kConnections].push(connection);
|
||||
}
|
||||
|
||||
@@ -264,7 +260,7 @@ class ConnectionPool extends EventEmitter {
|
||||
destroyConnection(this, connection, reason);
|
||||
}
|
||||
|
||||
processWaitQueue(this);
|
||||
process.nextTick(() => processWaitQueue(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -434,7 +430,7 @@ function createConnection(pool, callback) {
|
||||
|
||||
// otherwise add it to the pool for later acquisition, and try to process the wait queue
|
||||
pool[kConnections].push(connection);
|
||||
processWaitQueue(pool);
|
||||
process.nextTick(() => processWaitQueue(pool));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -483,7 +479,7 @@ function processWaitQueue(pool) {
|
||||
if (pool.waitQueueSize && (maxPoolSize <= 0 || pool.totalConnectionCount < maxPoolSize)) {
|
||||
createConnection(pool, (err, connection) => {
|
||||
const waitQueueMember = pool[kWaitQueue].shift();
|
||||
if (waitQueueMember == null) {
|
||||
if (waitQueueMember == null || waitQueueMember[kCancelled]) {
|
||||
if (err == null) {
|
||||
pool[kConnections].push(connection);
|
||||
}
|
||||
@@ -491,10 +487,6 @@ function processWaitQueue(pool) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (waitQueueMember[kCancelled]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
pool.emit('connectionCheckOutFailed', new ConnectionCheckOutFailedEvent(pool, err));
|
||||
} else {
|
||||
|
||||
368
node_modules/mongodb/lib/collection.js
generated
vendored
368
node_modules/mongodb/lib/collection.js
generated
vendored
@@ -2,10 +2,10 @@
|
||||
|
||||
const deprecate = require('util').deprecate;
|
||||
const deprecateOptions = require('./utils').deprecateOptions;
|
||||
const emitWarningOnce = require('./utils').emitWarningOnce;
|
||||
const checkCollectionName = require('./utils').checkCollectionName;
|
||||
const ObjectID = require('./core').BSON.ObjectID;
|
||||
const MongoError = require('./core').MongoError;
|
||||
const toError = require('./utils').toError;
|
||||
const normalizeHintField = require('./utils').normalizeHintField;
|
||||
const decorateCommand = require('./utils').decorateCommand;
|
||||
const decorateWithCollation = require('./utils').decorateWithCollation;
|
||||
@@ -16,7 +16,6 @@ const unordered = require('./bulk/unordered');
|
||||
const ordered = require('./bulk/ordered');
|
||||
const ChangeStream = require('./change_stream');
|
||||
const executeLegacyOperation = require('./utils').executeLegacyOperation;
|
||||
const resolveReadPreference = require('./utils').resolveReadPreference;
|
||||
const WriteConcern = require('./write_concern');
|
||||
const ReadConcern = require('./read_concern');
|
||||
const MongoDBNamespace = require('./utils').MongoDBNamespace;
|
||||
@@ -24,7 +23,6 @@ const AggregationCursor = require('./aggregation_cursor');
|
||||
const CommandCursor = require('./command_cursor');
|
||||
|
||||
// Operations
|
||||
const checkForAtomicOperators = require('./operations/collection_ops').checkForAtomicOperators;
|
||||
const ensureIndex = require('./operations/collection_ops').ensureIndex;
|
||||
const group = require('./operations/collection_ops').group;
|
||||
const parallelCollectionScan = require('./operations/collection_ops').parallelCollectionScan;
|
||||
@@ -35,7 +33,6 @@ const updateDocuments = require('./operations/common_functions').updateDocuments
|
||||
const AggregateOperation = require('./operations/aggregate');
|
||||
const BulkWriteOperation = require('./operations/bulk_write');
|
||||
const CountDocumentsOperation = require('./operations/count_documents');
|
||||
const CreateIndexOperation = require('./operations/create_index');
|
||||
const CreateIndexesOperation = require('./operations/create_indexes');
|
||||
const DeleteManyOperation = require('./operations/delete_many');
|
||||
const DeleteOneOperation = require('./operations/delete_one');
|
||||
@@ -123,6 +120,8 @@ function Collection(db, topology, dbName, name, pkFactory, options) {
|
||||
options == null || options.promoteBuffers == null
|
||||
? db.s.options.promoteBuffers
|
||||
: options.promoteBuffers;
|
||||
const bsonRegExp =
|
||||
options == null || options.bsonRegExp == null ? db.s.options.bsonRegExp : options.bsonRegExp;
|
||||
const collectionHint = null;
|
||||
|
||||
const namespace = new MongoDBNamespace(dbName, name);
|
||||
@@ -159,6 +158,8 @@ function Collection(db, topology, dbName, name, pkFactory, options) {
|
||||
promoteValues: promoteValues,
|
||||
// promoteBuffers
|
||||
promoteBuffers: promoteBuffers,
|
||||
// bsonRegExp
|
||||
bsonRegExp: bsonRegExp,
|
||||
// internalHint
|
||||
internalHint: internalHint,
|
||||
// collectionHint
|
||||
@@ -278,7 +279,7 @@ Object.defineProperty(Collection.prototype, 'hint', {
|
||||
}
|
||||
});
|
||||
|
||||
const DEPRECATED_FIND_OPTIONS = ['maxScan', 'fields', 'snapshot'];
|
||||
const DEPRECATED_FIND_OPTIONS = ['maxScan', 'fields', 'snapshot', 'oplogReplay'];
|
||||
|
||||
/**
|
||||
* Creates a cursor for a query that can be used to iterate over results from MongoDB
|
||||
@@ -291,7 +292,6 @@ const DEPRECATED_FIND_OPTIONS = ['maxScan', 'fields', 'snapshot'];
|
||||
* @param {object} [options.fields] **Deprecated** Use `options.projection` instead
|
||||
* @param {number} [options.skip=0] Set to skip N documents ahead in your query (useful for pagination).
|
||||
* @param {Object} [options.hint] Tell the query to use specific indexes in the query. Object of indexes to use, {'_id':1}
|
||||
* @param {boolean} [options.explain=false] Explain the query instead of returning the data.
|
||||
* @param {boolean} [options.snapshot=false] DEPRECATED: Snapshot query.
|
||||
* @param {boolean} [options.timeout=false] Specify if the cursor can timeout.
|
||||
* @param {boolean} [options.tailable=false] Specify if the cursor is tailable.
|
||||
@@ -307,12 +307,15 @@ const DEPRECATED_FIND_OPTIONS = ['maxScan', 'fields', 'snapshot'];
|
||||
* @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
|
||||
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
||||
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
||||
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
||||
* @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
|
||||
* @param {boolean} [options.partial=false] Specify if the cursor should return partial results when querying against a sharded system
|
||||
* @param {number} [options.maxTimeMS] Number of milliseconds to wait before aborting the query.
|
||||
* @param {number} [options.maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a tailable cursor query. Requires `tailable` and `awaitData` to be true
|
||||
* @param {boolean} [options.noCursorTimeout] The server normally times out idle cursors after an inactivity period (10 minutes) to prevent excess memory use. Set this option to prevent that.
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {boolean} [options.allowDiskUse] Enables writing to temporary files on the server.
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @throws {MongoError}
|
||||
* @return {Cursor}
|
||||
@@ -326,7 +329,7 @@ Collection.prototype.find = deprecateOptions(
|
||||
function(query, options, callback) {
|
||||
if (typeof callback === 'object') {
|
||||
// TODO(MAJOR): throw in the future
|
||||
console.warn('Third parameter to `find()` must be a callback or undefined');
|
||||
emitWarningOnce('Third parameter to `find()` must be a callback or undefined');
|
||||
}
|
||||
|
||||
let selector = query;
|
||||
@@ -399,7 +402,7 @@ Collection.prototype.find = deprecateOptions(
|
||||
newOptions.slaveOk = options.slaveOk != null ? options.slaveOk : this.s.db.slaveOk;
|
||||
|
||||
// Add read preference if needed
|
||||
newOptions.readPreference = resolveReadPreference(this, newOptions);
|
||||
newOptions.readPreference = ReadPreference.resolve(this, newOptions);
|
||||
|
||||
// Set slave ok to true if read preference different from primary
|
||||
if (
|
||||
@@ -422,13 +425,17 @@ Collection.prototype.find = deprecateOptions(
|
||||
query: selector
|
||||
};
|
||||
|
||||
if (typeof options.allowDiskUse === 'boolean') {
|
||||
findCommand.allowDiskUse = options.allowDiskUse;
|
||||
}
|
||||
|
||||
// Ensure we use the right await data option
|
||||
if (typeof newOptions.awaitdata === 'boolean') {
|
||||
newOptions.awaitData = newOptions.awaitdata;
|
||||
}
|
||||
|
||||
// Translate to new command option noCursorTimeout
|
||||
if (typeof newOptions.timeout === 'boolean') newOptions.noCursorTimeout = newOptions.timeout;
|
||||
if (typeof newOptions.timeout === 'boolean') newOptions.noCursorTimeout = !newOptions.timeout;
|
||||
|
||||
decorateCommand(findCommand, newOptions, ['session', 'collation']);
|
||||
|
||||
@@ -449,6 +456,8 @@ Collection.prototype.find = deprecateOptions(
|
||||
newOptions.promoteValues = this.s.promoteValues;
|
||||
if (newOptions.promoteBuffers == null && typeof this.s.promoteBuffers === 'boolean')
|
||||
newOptions.promoteBuffers = this.s.promoteBuffers;
|
||||
if (newOptions.bsonRegExp == null && typeof this.s.bsonRegExp === 'boolean')
|
||||
newOptions.bsonRegExp = this.s.bsonRegExp;
|
||||
|
||||
// Sort options
|
||||
if (findCommand.sort) {
|
||||
@@ -491,9 +500,10 @@ Collection.prototype.find = deprecateOptions(
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
|
||||
* @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.checkKeys=true] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
@@ -527,9 +537,10 @@ Collection.prototype.insertOne = function(doc, options, callback) {
|
||||
* @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
|
||||
* @param {boolean} [options.ordered=true] If true, when an insert fails, don't execute the remaining writes. If false, continue with remaining inserts when one fails.
|
||||
* @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.checkKeys=true] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
@@ -594,9 +605,10 @@ Collection.prototype.insertMany = function(docs, options, callback) {
|
||||
* @param {boolean} [options.ordered=true] Execute write operation in ordered or unordered fashion.
|
||||
* @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
|
||||
* @param {object[]} [options.arrayFilters] Determines which array elements to modify for update operation in MongoDB 3.6 or higher.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
@@ -675,9 +687,10 @@ Collection.prototype.bulkWrite = function(operations, options, callback) {
|
||||
* @method
|
||||
* @param {(object|object[])} docs Documents to insert.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
|
||||
* @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
|
||||
@@ -732,26 +745,20 @@ Collection.prototype.insert = deprecate(function(docs, options, callback) {
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {object} [options.hint] An optional hint for query optimization. See the {@link https://docs.mongodb.com/manual/reference/command/update/#update-command-hint|update command} reference for more information.
|
||||
* @param {boolean} [options.upsert=false] When true, creates a new document if no document matches the query..
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~updateWriteOpCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
Collection.prototype.updateOne = function(filter, update, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
const err = checkForAtomicOperators(update);
|
||||
if (err) {
|
||||
if (typeof callback === 'function') return callback(err);
|
||||
return this.s.promiseLibrary.reject(err);
|
||||
}
|
||||
|
||||
options = Object.assign({}, options);
|
||||
|
||||
// Add ignoreUndefined
|
||||
@@ -760,9 +767,11 @@ Collection.prototype.updateOne = function(filter, update, options, callback) {
|
||||
options.ignoreUndefined = this.s.options.ignoreUndefined;
|
||||
}
|
||||
|
||||
const updateOneOperation = new UpdateOneOperation(this, filter, update, options);
|
||||
|
||||
return executeOperation(this.s.topology, updateOneOperation, callback);
|
||||
return executeOperation(
|
||||
this.s.topology,
|
||||
new UpdateOneOperation(this, filter, update, options),
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -775,9 +784,10 @@ Collection.prototype.updateOne = function(filter, update, options, callback) {
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {object} [options.hint] An optional hint for query optimization. See the {@link https://docs.mongodb.com/manual/reference/command/update/#update-command-hint|update command} reference for more information.
|
||||
* @param {boolean} [options.upsert=false] When true, creates a new document if no document matches the query.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
@@ -795,9 +805,11 @@ Collection.prototype.replaceOne = function(filter, doc, options, callback) {
|
||||
options.ignoreUndefined = this.s.options.ignoreUndefined;
|
||||
}
|
||||
|
||||
const replaceOneOperation = new ReplaceOneOperation(this, filter, doc, options);
|
||||
|
||||
return executeOperation(this.s.topology, replaceOneOperation, callback);
|
||||
return executeOperation(
|
||||
this.s.topology,
|
||||
new ReplaceOneOperation(this, filter, doc, options),
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -811,26 +823,20 @@ Collection.prototype.replaceOne = function(filter, doc, options, callback) {
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {object} [options.hint] An optional hint for query optimization. See the {@link https://docs.mongodb.com/manual/reference/command/update/#update-command-hint|update command} reference for more information.
|
||||
* @param {boolean} [options.upsert=false] When true, creates a new document if no document matches the query..
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~updateWriteOpCallback} [callback] The command result callback
|
||||
* @return {Promise<Collection~updateWriteOpResult>} returns Promise if no callback passed
|
||||
*/
|
||||
Collection.prototype.updateMany = function(filter, update, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
const err = checkForAtomicOperators(update);
|
||||
if (err) {
|
||||
if (typeof callback === 'function') return callback(err);
|
||||
return this.s.promiseLibrary.reject(err);
|
||||
}
|
||||
|
||||
options = Object.assign({}, options);
|
||||
|
||||
// Add ignoreUndefined
|
||||
@@ -839,9 +845,11 @@ Collection.prototype.updateMany = function(filter, update, options, callback) {
|
||||
options.ignoreUndefined = this.s.options.ignoreUndefined;
|
||||
}
|
||||
|
||||
const updateManyOperation = new UpdateManyOperation(this, filter, update, options);
|
||||
|
||||
return executeOperation(this.s.topology, updateManyOperation, callback);
|
||||
return executeOperation(
|
||||
this.s.topology,
|
||||
new UpdateManyOperation(this, filter, update, options),
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -850,9 +858,10 @@ Collection.prototype.updateMany = function(filter, update, options, callback) {
|
||||
* @param {object} selector The selector for the update operation.
|
||||
* @param {object} update The update operations to be applied to the documents
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.upsert=false] Update operation is an upsert.
|
||||
* @param {boolean} [options.multi=false] Update one/all documents with operation.
|
||||
* @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
|
||||
@@ -906,13 +915,16 @@ Collection.prototype.update = deprecate(function(selector, update, options, call
|
||||
* @param {object} filter The Filter used to select the document to remove
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {string|object} [options.hint] optional index hint for optimizing the filter query
|
||||
* @param {Collection~deleteWriteOpCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
@@ -939,13 +951,16 @@ Collection.prototype.removeOne = Collection.prototype.deleteOne;
|
||||
* @param {object} filter The Filter used to select the documents to remove
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {string|object} [options.hint] optional index hint for optimizing the filter query
|
||||
* @param {Collection~deleteWriteOpCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
@@ -972,9 +987,10 @@ Collection.prototype.removeMany = Collection.prototype.deleteMany;
|
||||
* @param {object} selector The selector for the update operation.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.single=false] Removes the first document found.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~writeOpCallback} [callback] The command result callback
|
||||
@@ -1005,9 +1021,10 @@ Collection.prototype.remove = deprecate(function(selector, options, callback) {
|
||||
* @method
|
||||
* @param {object} doc Document to save
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~writeOpCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
@@ -1051,7 +1068,6 @@ Collection.prototype.save = deprecate(function(doc, options, callback) {
|
||||
* @param {object} [options.fields] **Deprecated** Use `options.projection` instead
|
||||
* @param {number} [options.skip=0] Set to skip N documents ahead in your query (useful for pagination).
|
||||
* @param {Object} [options.hint] Tell the query to use specific indexes in the query. Object of indexes to use, {'_id':1}
|
||||
* @param {boolean} [options.explain=false] Explain the query instead of returning the data.
|
||||
* @param {boolean} [options.snapshot=false] DEPRECATED: Snapshot query.
|
||||
* @param {boolean} [options.timeout=false] Specify if the cursor can timeout.
|
||||
* @param {boolean} [options.tailable=false] Specify if the cursor is tailable.
|
||||
@@ -1066,10 +1082,12 @@ Collection.prototype.save = deprecate(function(doc, options, callback) {
|
||||
* @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
|
||||
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
||||
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
||||
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
||||
* @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
|
||||
* @param {boolean} [options.partial=false] Specify if the cursor should return partial results when querying against a sharded system
|
||||
* @param {number} [options.maxTimeMS] Number of milliseconds to wait before aborting the query.
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~resultCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
@@ -1083,7 +1101,7 @@ Collection.prototype.findOne = deprecateOptions(
|
||||
function(query, options, callback) {
|
||||
if (typeof callback === 'object') {
|
||||
// TODO(MAJOR): throw in the future
|
||||
console.warn('Third parameter to `findOne()` must be a callback or undefined');
|
||||
emitWarningOnce('Third parameter to `findOne()` must be a callback or undefined');
|
||||
}
|
||||
|
||||
if (typeof query === 'function') (callback = query), (query = {}), (options = {});
|
||||
@@ -1129,10 +1147,10 @@ Collection.prototype.rename = function(newName, options, callback) {
|
||||
*
|
||||
* @method
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {WriteConcern} [options.writeConcern] A full WriteConcern object
|
||||
* @param {(number|string)} [options.w] The write concern
|
||||
* @param {number} [options.wtimeout] The write concern timeout
|
||||
* @param {boolean} [options.j] The journal write concern
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~resultCallback} [callback] The results callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
@@ -1191,9 +1209,10 @@ Collection.prototype.isCapped = function(options, callback) {
|
||||
* @method
|
||||
* @param {(string|array|object)} fieldOrSpec Defines the index.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.unique=false] Creates an unique index.
|
||||
* @param {boolean} [options.sparse=false] Creates a sparse index.
|
||||
* @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
|
||||
@@ -1206,6 +1225,7 @@ Collection.prototype.isCapped = function(options, callback) {
|
||||
* @param {object} [options.partialFilterExpression] Creates a partial index based on the given filter object (MongoDB 3.2 or higher)
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {(number|string)} [options.commitQuorum] (MongoDB 4.4. or higher) Specifies how many data-bearing members of a replica set, including the primary, must complete the index builds successfully before the primary marks the indexes as ready. This option accepts the same values for the "w" field in a write concern plus "votingMembers", which indicates all voting data-bearing nodes.
|
||||
* @param {Collection~resultCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
* @example
|
||||
@@ -1232,14 +1252,14 @@ Collection.prototype.createIndex = function(fieldOrSpec, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
const createIndexOperation = new CreateIndexOperation(
|
||||
this.s.db,
|
||||
const createIndexesOperation = new CreateIndexesOperation(
|
||||
this,
|
||||
this.collectionName,
|
||||
fieldOrSpec,
|
||||
options
|
||||
);
|
||||
|
||||
return executeOperation(this.s.topology, createIndexOperation, callback);
|
||||
return executeOperation(this.s.topology, createIndexesOperation, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1260,6 +1280,7 @@ Collection.prototype.createIndex = function(fieldOrSpec, options, callback) {
|
||||
* @param {Collection~IndexDefinition[]} indexSpecs An array of index specifications to be created
|
||||
* @param {Object} [options] Optional settings
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {(number|string)} [options.commitQuorum] (MongoDB 4.4. or higher) Specifies how many data-bearing members of a replica set, including the primary, must complete the index builds successfully before the primary marks the indexes as ready. This option accepts the same values for the "w" field in a write concern plus "votingMembers", which indicates all voting data-bearing nodes.
|
||||
* @param {Collection~resultCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
* @example
|
||||
@@ -1284,9 +1305,15 @@ Collection.prototype.createIndexes = function(indexSpecs, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
|
||||
options = options ? Object.assign({}, options) : {};
|
||||
|
||||
if (typeof options.maxTimeMS !== 'number') delete options.maxTimeMS;
|
||||
|
||||
const createIndexesOperation = new CreateIndexesOperation(this, indexSpecs, options);
|
||||
const createIndexesOperation = new CreateIndexesOperation(
|
||||
this,
|
||||
this.collectionName,
|
||||
indexSpecs,
|
||||
options
|
||||
);
|
||||
|
||||
return executeOperation(this.s.topology, createIndexesOperation, callback);
|
||||
};
|
||||
@@ -1296,9 +1323,10 @@ Collection.prototype.createIndexes = function(indexSpecs, options, callback) {
|
||||
* @method
|
||||
* @param {string} indexName Name of the index to drop.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {number} [options.maxTimeMS] Number of milliseconds to wait before aborting the query.
|
||||
* @param {Collection~resultCallback} [callback] The command result callback
|
||||
@@ -1353,19 +1381,20 @@ Collection.prototype.dropAllIndexes = deprecate(
|
||||
* Reindex all indexes on the collection
|
||||
* Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections.
|
||||
* @method
|
||||
* @deprecated use db.command instead
|
||||
* @param {Object} [options] Optional settings
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~resultCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
Collection.prototype.reIndex = function(options, callback) {
|
||||
Collection.prototype.reIndex = deprecate(function(options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
const reIndexOperation = new ReIndexOperation(this, options);
|
||||
|
||||
return executeOperation(this.s.topology, reIndexOperation, callback);
|
||||
};
|
||||
}, 'collection.reIndex is deprecated. Use db.command instead.');
|
||||
|
||||
/**
|
||||
* Get the list of all indexes information for the collection.
|
||||
@@ -1393,9 +1422,10 @@ Collection.prototype.listIndexes = function(options) {
|
||||
* @deprecated use createIndexes instead
|
||||
* @param {(string|object)} fieldOrSpec Defines the index.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.unique=false] Creates an unique index.
|
||||
* @param {boolean} [options.sparse=false] Creates a sparse index.
|
||||
* @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
|
||||
@@ -1502,7 +1532,7 @@ Collection.prototype.count = deprecate(function(query, options, callback) {
|
||||
|
||||
return executeOperation(
|
||||
this.s.topology,
|
||||
new EstimatedDocumentCountOperation(this, query, options),
|
||||
new EstimatedDocumentCountOperation(this, Object.assign({ query }, options)),
|
||||
callback
|
||||
);
|
||||
}, 'collection.count is deprecated, and will be removed in a future version.' +
|
||||
@@ -1578,6 +1608,7 @@ Collection.prototype.countDocuments = function(query, options, callback) {
|
||||
* @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
|
||||
* @param {number} [options.maxTimeMS] Number of milliseconds to wait before aborting the query.
|
||||
* @param {object} [options.collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~resultCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
@@ -1632,7 +1663,7 @@ Collection.prototype.stats = function(options, callback) {
|
||||
|
||||
/**
|
||||
* @typedef {Object} Collection~findAndModifyWriteOpResult
|
||||
* @property {object} value Document returned from the `findAndModify` command. If no documents were found, `value` will be `null` by default (`returnOriginal: true`), even if a document was upserted; if `returnOriginal` was false, the upserted document will be returned in that case.
|
||||
* @property {object} value Document returned from the `findAndModify` command. If no documents were found, `value` will be `null` by default even if a document was upserted unless `returnDocument` is specified as `'after'`, in which case the upserted document will be returned.
|
||||
* @property {object} lastErrorObject The raw lastErrorObject returned from the command. See {@link https://docs.mongodb.com/manual/reference/command/findAndModify/index.html#lasterrorobject|findAndModify command documentation}.
|
||||
* @property {Number} ok Is 1 if the command executed correctly.
|
||||
*/
|
||||
@@ -1657,6 +1688,7 @@ Collection.prototype.stats = function(options, callback) {
|
||||
* @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~findAndModifyCallback} [callback] The collection result callback
|
||||
* @return {Promise<Collection~findAndModifyWriteOpResultObject>} returns Promise if no callback passed
|
||||
@@ -1665,13 +1697,17 @@ Collection.prototype.findOneAndDelete = function(filter, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
// Basic validation
|
||||
if (filter == null || typeof filter !== 'object')
|
||||
throw toError('filter parameter must be an object');
|
||||
// Add ignoreUndefined
|
||||
if (this.s.options.ignoreUndefined) {
|
||||
options = Object.assign({}, options);
|
||||
options.ignoreUndefined = this.s.options.ignoreUndefined;
|
||||
}
|
||||
|
||||
const findOneAndDeleteOperation = new FindOneAndDeleteOperation(this, filter, options);
|
||||
|
||||
return executeOperation(this.s.topology, findOneAndDeleteOperation, callback);
|
||||
return executeOperation(
|
||||
this.s.topology,
|
||||
new FindOneAndDeleteOperation(this, filter, options),
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1683,44 +1719,44 @@ Collection.prototype.findOneAndDelete = function(filter, options, callback) {
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {string|object} [options.hint] An optional index to use for this operation
|
||||
* @param {number} [options.maxTimeMS] The maximum amount of time to allow the query to run.
|
||||
* @param {object} [options.projection] Limits the fields to return for all matching documents.
|
||||
* @param {object} [options.sort] Determines which document the operation modifies if the query selects multiple documents.
|
||||
* @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
|
||||
* @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
|
||||
* @param {'before'|'after'} [options.returnDocument='before'] When set to `'after'`, returns the updated document rather than the original. The default is `'before'`.
|
||||
* @param {boolean} [options.returnOriginal=true] **Deprecated** Use `options.returnDocument` instead.
|
||||
* @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~findAndModifyCallback} [callback] The collection result callback
|
||||
* @return {Promise<Collection~findAndModifyWriteOpResultObject>} returns Promise if no callback passed
|
||||
*/
|
||||
Collection.prototype.findOneAndReplace = function(filter, replacement, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
Collection.prototype.findOneAndReplace = deprecateOptions(
|
||||
{
|
||||
name: 'collection.findOneAndReplace',
|
||||
deprecatedOptions: ['returnOriginal'],
|
||||
optionsIndex: 2
|
||||
},
|
||||
function(filter, replacement, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
// Basic validation
|
||||
if (filter == null || typeof filter !== 'object')
|
||||
throw toError('filter parameter must be an object');
|
||||
if (replacement == null || typeof replacement !== 'object')
|
||||
throw toError('replacement parameter must be an object');
|
||||
// Add ignoreUndefined
|
||||
if (this.s.options.ignoreUndefined) {
|
||||
options = Object.assign({}, options);
|
||||
options.ignoreUndefined = this.s.options.ignoreUndefined;
|
||||
}
|
||||
|
||||
// Check that there are no atomic operators
|
||||
const keys = Object.keys(replacement);
|
||||
|
||||
if (keys[0] && keys[0][0] === '$') {
|
||||
throw toError('The replacement document must not contain atomic operators.');
|
||||
return executeOperation(
|
||||
this.s.topology,
|
||||
new FindOneAndReplaceOperation(this, filter, replacement, options),
|
||||
callback
|
||||
);
|
||||
}
|
||||
|
||||
const findOneAndReplaceOperation = new FindOneAndReplaceOperation(
|
||||
this,
|
||||
filter,
|
||||
replacement,
|
||||
options
|
||||
);
|
||||
|
||||
return executeOperation(this.s.topology, findOneAndReplaceOperation, callback);
|
||||
};
|
||||
);
|
||||
|
||||
/**
|
||||
* Find a document and update it in one atomic operation. Requires a write lock for the duration of the operation.
|
||||
@@ -1732,38 +1768,44 @@ Collection.prototype.findOneAndReplace = function(filter, replacement, options,
|
||||
* @param {Array} [options.arrayFilters] optional list of array filters referenced in filtered positional operators
|
||||
* @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {string|object} [options.hint] An optional index to use for this operation
|
||||
* @param {number} [options.maxTimeMS] The maximum amount of time to allow the query to run.
|
||||
* @param {object} [options.projection] Limits the fields to return for all matching documents.
|
||||
* @param {object} [options.sort] Determines which document the operation modifies if the query selects multiple documents.
|
||||
* @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
|
||||
* @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
|
||||
* @param {'before'|'after'} [options.returnDocument='before'] When set to `'after'`, returns the updated document rather than the original. The default is `'before'`.
|
||||
* @param {boolean} [options.returnOriginal=true] **Deprecated** Use `options.returnDocument` instead.
|
||||
* @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] An ptional session to use for this operation
|
||||
* @param {Collection~findAndModifyCallback} [callback] The collection result callback
|
||||
* @return {Promise<Collection~findAndModifyWriteOpResultObject>} returns Promise if no callback passed
|
||||
*/
|
||||
Collection.prototype.findOneAndUpdate = function(filter, update, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
Collection.prototype.findOneAndUpdate = deprecateOptions(
|
||||
{
|
||||
name: 'collection.findOneAndUpdate',
|
||||
deprecatedOptions: ['returnOriginal'],
|
||||
optionsIndex: 2
|
||||
},
|
||||
function(filter, update, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
// Basic validation
|
||||
if (filter == null || typeof filter !== 'object')
|
||||
throw toError('filter parameter must be an object');
|
||||
if (update == null || typeof update !== 'object')
|
||||
throw toError('update parameter must be an object');
|
||||
// Add ignoreUndefined
|
||||
if (this.s.options.ignoreUndefined) {
|
||||
options = Object.assign({}, options);
|
||||
options.ignoreUndefined = this.s.options.ignoreUndefined;
|
||||
}
|
||||
|
||||
const err = checkForAtomicOperators(update);
|
||||
if (err) {
|
||||
if (typeof callback === 'function') return callback(err);
|
||||
return this.s.promiseLibrary.reject(err);
|
||||
return executeOperation(
|
||||
this.s.topology,
|
||||
new FindOneAndUpdateOperation(this, filter, update, options),
|
||||
callback
|
||||
);
|
||||
}
|
||||
|
||||
const findOneAndUpdateOperation = new FindOneAndUpdateOperation(this, filter, update, options);
|
||||
|
||||
return executeOperation(this.s.topology, findOneAndUpdateOperation, callback);
|
||||
};
|
||||
);
|
||||
|
||||
/**
|
||||
* Find and update a document.
|
||||
@@ -1772,9 +1814,10 @@ Collection.prototype.findOneAndUpdate = function(filter, update, options, callba
|
||||
* @param {array} sort If multiple docs match, choose the first one in the specified sort order as the object to manipulate.
|
||||
* @param {object} doc The fields/vals to be updated.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.remove=false] Set to true to remove the object before returning.
|
||||
* @param {boolean} [options.upsert=false] Perform an upsert operation.
|
||||
* @param {boolean} [options.new=false] Set to true if you want to return the modified object rather than the original. Ignored for remove.
|
||||
@@ -1822,9 +1865,10 @@ function _findAndModify(query, sort, doc, options, callback) {
|
||||
* @param {object} query Query object to locate the object to modify.
|
||||
* @param {array} sort If multiple docs match, choose the first one in the specified sort order as the object to manipulate.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~resultCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
@@ -1855,7 +1899,6 @@ Collection.prototype.findAndRemove = deprecate(function(query, sort, options, ca
|
||||
* @param {number} [options.batchSize=1000] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
||||
* @param {object} [options.cursor] Return the query as cursor, on 2.6 > it returns as a real cursor on pre 2.6 it returns as an emulated cursor.
|
||||
* @param {number} [options.cursor.batchSize=1000] Deprecated. Use `options.batchSize`
|
||||
* @param {boolean} [options.explain=false] Explain returns the aggregation execution plan (requires mongodb 2.6 >).
|
||||
* @param {boolean} [options.allowDiskUse=false] allowDiskUse lets the server know if it can use disk to store temporary results for the aggregation (requires mongodb 2.6 >).
|
||||
* @param {number} [options.maxTimeMS] maxTimeMS specifies a cumulative time limit in milliseconds for processing operations on the cursor. MongoDB interrupts the operation at the earliest following interrupt point.
|
||||
* @param {number} [options.maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a tailable cursor query.
|
||||
@@ -1864,9 +1907,11 @@ Collection.prototype.findAndRemove = deprecate(function(query, sort, options, ca
|
||||
* @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
|
||||
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
||||
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
||||
* @param {object} [options.collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
||||
* @param {string} [options.comment] Add a comment to an aggregation command
|
||||
* @param {string|object} [options.hint] Add an index selection hint to an aggregation command
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~aggregationCallback} callback The command result callback
|
||||
* @return {(null|AggregationCursor)}
|
||||
@@ -1978,7 +2023,7 @@ Collection.prototype.parallelCollectionScan = deprecate(function(options, callba
|
||||
|
||||
options = Object.assign({}, options);
|
||||
// Ensure we have the right read preference inheritance
|
||||
options.readPreference = resolveReadPreference(this, options);
|
||||
options.readPreference = ReadPreference.resolve(this, options);
|
||||
|
||||
// Add a promiseLibrary
|
||||
options.promiseLibrary = this.s.promiseLibrary;
|
||||
@@ -2009,8 +2054,9 @@ Collection.prototype.parallelCollectionScan = deprecate(function(options, callba
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~resultCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
* @deprecated See {@link https://docs.mongodb.com/manual/geospatial-queries/|geospatial queries docs} for current geospatial support
|
||||
*/
|
||||
Collection.prototype.geoHaystackSearch = function(x, y, options, callback) {
|
||||
Collection.prototype.geoHaystackSearch = deprecate(function(x, y, options, callback) {
|
||||
const args = Array.prototype.slice.call(arguments, 2);
|
||||
callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
|
||||
options = args.length ? args.shift() || {} : {};
|
||||
@@ -2018,7 +2064,7 @@ Collection.prototype.geoHaystackSearch = function(x, y, options, callback) {
|
||||
const geoHaystackSearchOperation = new GeoHaystackSearchOperation(this, x, y, options);
|
||||
|
||||
return executeOperation(this.s.topology, geoHaystackSearchOperation, callback);
|
||||
};
|
||||
}, 'geoHaystackSearch is deprecated, and will be removed in a future version.');
|
||||
|
||||
/**
|
||||
* Run a group command across a collection
|
||||
@@ -2112,6 +2158,7 @@ Collection.prototype.group = deprecate(function(
|
||||
* @param {boolean} [options.jsMode=false] It is possible to make the execution stay in JS. Provided in MongoDB > 2.0.X.
|
||||
* @param {boolean} [options.verbose=false] Provide statistics on job execution time.
|
||||
* @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Collection~resultCallback} [callback] The command result callback
|
||||
* @throws {MongoError}
|
||||
@@ -2147,9 +2194,10 @@ Collection.prototype.mapReduce = function(map, reduce, options, callback) {
|
||||
*
|
||||
* @method
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @return {UnorderedBulkOperation}
|
||||
@@ -2170,12 +2218,12 @@ Collection.prototype.initializeUnorderedBulkOp = function(options) {
|
||||
*
|
||||
* @method
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
* @param {OrderedBulkOperation} callback The command result callback
|
||||
* @return {null}
|
||||
*/
|
||||
Collection.prototype.initializeOrderedBulkOp = function(options) {
|
||||
|
||||
167
node_modules/mongodb/lib/core/auth/auth_provider.js
generated
vendored
167
node_modules/mongodb/lib/core/auth/auth_provider.js
generated
vendored
@@ -1,158 +1,55 @@
|
||||
'use strict';
|
||||
|
||||
const MongoError = require('../error').MongoError;
|
||||
|
||||
/**
|
||||
* Creates a new AuthProvider, which dictates how to authenticate for a given
|
||||
* mechanism.
|
||||
* @class
|
||||
* Context used during authentication
|
||||
*
|
||||
* @property {Connection} connection The connection to authenticate
|
||||
* @property {MongoCredentials} credentials The credentials to use for authentication
|
||||
* @property {object} options The options passed to the `connect` method
|
||||
* @property {object?} response The response of the initial handshake
|
||||
* @property {Buffer?} nonce A random nonce generated for use in an authentication conversation
|
||||
*/
|
||||
class AuthContext {
|
||||
constructor(connection, credentials, options) {
|
||||
this.connection = connection;
|
||||
this.credentials = credentials;
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
|
||||
class AuthProvider {
|
||||
constructor(bson) {
|
||||
this.bson = bson;
|
||||
this.authStore = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the handshake document before the initial handshake.
|
||||
*
|
||||
* @param {object} handshakeDoc The document used for the initial handshake on a connection
|
||||
* @param {AuthContext} authContext Context for authentication flow
|
||||
* @param {function} callback
|
||||
*/
|
||||
prepare(handshakeDoc, context, callback) {
|
||||
callback(undefined, handshakeDoc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate
|
||||
* @method
|
||||
* @param {SendAuthCommand} sendAuthCommand Writes an auth command directly to a specific connection
|
||||
* @param {Connection[]} connections Connections to authenticate using this authenticator
|
||||
* @param {MongoCredentials} credentials Authentication credentials
|
||||
*
|
||||
* @param {AuthContext} context A shared context for authentication flow
|
||||
* @param {authResultCallback} callback The callback to return the result from the authentication
|
||||
*/
|
||||
auth(sendAuthCommand, connections, credentials, callback) {
|
||||
// Total connections
|
||||
let count = connections.length;
|
||||
|
||||
if (count === 0) {
|
||||
callback(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Valid connections
|
||||
let numberOfValidConnections = 0;
|
||||
let errorObject = null;
|
||||
|
||||
const execute = connection => {
|
||||
this._authenticateSingleConnection(sendAuthCommand, connection, credentials, (err, r) => {
|
||||
// Adjust count
|
||||
count = count - 1;
|
||||
|
||||
// If we have an error
|
||||
if (err) {
|
||||
errorObject = new MongoError(err);
|
||||
} else if (r && (r.$err || r.errmsg)) {
|
||||
errorObject = new MongoError(r);
|
||||
} else {
|
||||
numberOfValidConnections = numberOfValidConnections + 1;
|
||||
}
|
||||
|
||||
// Still authenticating against other connections.
|
||||
if (count !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We have authenticated all connections
|
||||
if (numberOfValidConnections > 0) {
|
||||
// Store the auth details
|
||||
this.addCredentials(credentials);
|
||||
// Return correct authentication
|
||||
callback(null, true);
|
||||
} else {
|
||||
if (errorObject == null) {
|
||||
errorObject = new MongoError(`failed to authenticate using ${credentials.mechanism}`);
|
||||
}
|
||||
callback(errorObject, false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const executeInNextTick = _connection => process.nextTick(() => execute(_connection));
|
||||
|
||||
// For each connection we need to authenticate
|
||||
while (connections.length > 0) {
|
||||
executeInNextTick(connections.shift());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of a single connection authenticating. Is meant to be overridden.
|
||||
* Will error if called directly
|
||||
* @ignore
|
||||
*/
|
||||
_authenticateSingleConnection(/*sendAuthCommand, connection, credentials, callback*/) {
|
||||
throw new Error('_authenticateSingleConnection must be overridden');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds credentials to store only if it does not exist
|
||||
* @param {MongoCredentials} credentials credentials to add to store
|
||||
*/
|
||||
addCredentials(credentials) {
|
||||
const found = this.authStore.some(cred => cred.equals(credentials));
|
||||
|
||||
if (!found) {
|
||||
this.authStore.push(credentials);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re authenticate pool
|
||||
* @method
|
||||
* @param {SendAuthCommand} sendAuthCommand Writes an auth command directly to a specific connection
|
||||
* @param {Connection[]} connections Connections to authenticate using this authenticator
|
||||
* @param {authResultCallback} callback The callback to return the result from the authentication
|
||||
*/
|
||||
reauthenticate(sendAuthCommand, connections, callback) {
|
||||
const authStore = this.authStore.slice(0);
|
||||
let count = authStore.length;
|
||||
if (count === 0) {
|
||||
return callback(null, null);
|
||||
}
|
||||
|
||||
for (let i = 0; i < authStore.length; i++) {
|
||||
this.auth(sendAuthCommand, connections, authStore[i], function(err) {
|
||||
count = count - 1;
|
||||
if (count === 0) {
|
||||
callback(err, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove credentials that have been previously stored in the auth provider
|
||||
* @method
|
||||
* @param {string} source Name of database we are removing authStore details about
|
||||
* @return {object}
|
||||
*/
|
||||
logout(source) {
|
||||
this.authStore = this.authStore.filter(credentials => credentials.source !== source);
|
||||
auth(context, callback) {
|
||||
callback(new TypeError('`auth` method must be overridden by subclass'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that writes authentication commands to a specific connection
|
||||
* @callback SendAuthCommand
|
||||
* @param {Connection} connection The connection to write to
|
||||
* @param {Command} command A command with a toBin method that can be written to a connection
|
||||
* @param {AuthWriteCallback} callback Callback called when command response is received
|
||||
*/
|
||||
|
||||
/**
|
||||
* A callback for a specific auth command
|
||||
* @callback AuthWriteCallback
|
||||
* @param {Error} err If command failed, an error from the server
|
||||
* @param {object} r The response from the server
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a result from an authentication strategy
|
||||
* This is a result from an authentication provider
|
||||
*
|
||||
* @callback authResultCallback
|
||||
* @param {error} error An error object. Set to null if no error present
|
||||
* @param {boolean} result The result of the authentication process
|
||||
*/
|
||||
|
||||
module.exports = { AuthProvider };
|
||||
module.exports = { AuthContext, AuthProvider };
|
||||
|
||||
4
node_modules/mongodb/lib/core/auth/defaultAuthProviders.js
generated
vendored
4
node_modules/mongodb/lib/core/auth/defaultAuthProviders.js
generated
vendored
@@ -4,9 +4,9 @@ const MongoCR = require('./mongocr');
|
||||
const X509 = require('./x509');
|
||||
const Plain = require('./plain');
|
||||
const GSSAPI = require('./gssapi');
|
||||
const SSPI = require('./sspi');
|
||||
const ScramSHA1 = require('./scram').ScramSHA1;
|
||||
const ScramSHA256 = require('./scram').ScramSHA256;
|
||||
const MongoDBAWS = require('./mongodb_aws');
|
||||
|
||||
/**
|
||||
* Returns the default authentication providers.
|
||||
@@ -16,11 +16,11 @@ const ScramSHA256 = require('./scram').ScramSHA256;
|
||||
*/
|
||||
function defaultAuthProviders(bson) {
|
||||
return {
|
||||
'mongodb-aws': new MongoDBAWS(bson),
|
||||
mongocr: new MongoCR(bson),
|
||||
x509: new X509(bson),
|
||||
plain: new Plain(bson),
|
||||
gssapi: new GSSAPI(bson),
|
||||
sspi: new SSPI(bson),
|
||||
'scram-sha-1': new ScramSHA1(bson),
|
||||
'scram-sha-256': new ScramSHA256(bson)
|
||||
};
|
||||
|
||||
346
node_modules/mongodb/lib/core/auth/gssapi.js
generated
vendored
346
node_modules/mongodb/lib/core/auth/gssapi.js
generated
vendored
@@ -1,241 +1,151 @@
|
||||
'use strict';
|
||||
const dns = require('dns');
|
||||
|
||||
const AuthProvider = require('./auth_provider').AuthProvider;
|
||||
const retrieveKerberos = require('../utils').retrieveKerberos;
|
||||
const MongoError = require('../error').MongoError;
|
||||
|
||||
let kerberos;
|
||||
|
||||
/**
|
||||
* Creates a new GSSAPI authentication mechanism
|
||||
* @class
|
||||
* @extends AuthProvider
|
||||
*/
|
||||
class GSSAPI extends AuthProvider {
|
||||
/**
|
||||
* Implementation of authentication for a single connection
|
||||
* @override
|
||||
*/
|
||||
_authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) {
|
||||
const source = credentials.source;
|
||||
auth(authContext, callback) {
|
||||
const connection = authContext.connection;
|
||||
const credentials = authContext.credentials;
|
||||
if (credentials == null) return callback(new MongoError('credentials required'));
|
||||
const username = credentials.username;
|
||||
const password = credentials.password;
|
||||
const mechanismProperties = credentials.mechanismProperties;
|
||||
const gssapiServiceName =
|
||||
mechanismProperties['gssapiservicename'] ||
|
||||
mechanismProperties['gssapiServiceName'] ||
|
||||
'mongodb';
|
||||
|
||||
GSSAPIInitialize(
|
||||
this,
|
||||
kerberos.processes.MongoAuthProcess,
|
||||
source,
|
||||
username,
|
||||
password,
|
||||
source,
|
||||
gssapiServiceName,
|
||||
sendAuthCommand,
|
||||
connection,
|
||||
mechanismProperties,
|
||||
callback
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate
|
||||
* @override
|
||||
* @method
|
||||
*/
|
||||
auth(sendAuthCommand, connections, credentials, callback) {
|
||||
if (kerberos == null) {
|
||||
try {
|
||||
kerberos = retrieveKerberos();
|
||||
} catch (e) {
|
||||
return callback(e, null);
|
||||
}
|
||||
function externalCommand(command, cb) {
|
||||
return connection.command('$external.$cmd', command, cb);
|
||||
}
|
||||
|
||||
super.auth(sendAuthCommand, connections, credentials, callback);
|
||||
makeKerberosClient(authContext, (err, client) => {
|
||||
if (err) return callback(err);
|
||||
if (client == null) return callback(new MongoError('gssapi client missing'));
|
||||
client.step('', (err, payload) => {
|
||||
if (err) return callback(err);
|
||||
externalCommand(saslStart(payload), (err, response) => {
|
||||
if (err) return callback(err);
|
||||
const result = response.result;
|
||||
negotiate(client, 10, result.payload, (err, payload) => {
|
||||
if (err) return callback(err);
|
||||
externalCommand(saslContinue(payload, result.conversationId), (err, response) => {
|
||||
if (err) return callback(err);
|
||||
const result = response.result;
|
||||
finalize(client, username, result.payload, (err, payload) => {
|
||||
if (err) return callback(err);
|
||||
externalCommand(
|
||||
{
|
||||
saslContinue: 1,
|
||||
conversationId: result.conversationId,
|
||||
payload
|
||||
},
|
||||
(err, result) => {
|
||||
if (err) return callback(err);
|
||||
callback(undefined, result);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
module.exports = GSSAPI;
|
||||
|
||||
//
|
||||
// Initialize step
|
||||
var GSSAPIInitialize = function(
|
||||
self,
|
||||
MongoAuthProcess,
|
||||
db,
|
||||
username,
|
||||
password,
|
||||
authdb,
|
||||
gssapiServiceName,
|
||||
sendAuthCommand,
|
||||
connection,
|
||||
options,
|
||||
callback
|
||||
) {
|
||||
// Create authenticator
|
||||
var mongo_auth_process = new MongoAuthProcess(
|
||||
connection.host,
|
||||
connection.port,
|
||||
gssapiServiceName,
|
||||
options
|
||||
);
|
||||
|
||||
// Perform initialization
|
||||
mongo_auth_process.init(username, password, function(err) {
|
||||
if (err) return callback(err, false);
|
||||
|
||||
// Perform the first step
|
||||
mongo_auth_process.transition('', function(err, payload) {
|
||||
if (err) return callback(err, false);
|
||||
|
||||
// Call the next db step
|
||||
MongoDBGSSAPIFirstStep(
|
||||
self,
|
||||
mongo_auth_process,
|
||||
payload,
|
||||
db,
|
||||
username,
|
||||
password,
|
||||
authdb,
|
||||
sendAuthCommand,
|
||||
connection,
|
||||
callback
|
||||
);
|
||||
});
|
||||
function makeKerberosClient(authContext, callback) {
|
||||
const host = authContext.options.host;
|
||||
const port = authContext.options.port;
|
||||
const credentials = authContext.credentials;
|
||||
if (!host || !port || !credentials) {
|
||||
return callback(
|
||||
new MongoError(
|
||||
`Connection must specify: ${host ? 'host' : ''}, ${port ? 'port' : ''}, ${
|
||||
credentials ? 'host' : 'credentials'
|
||||
}.`
|
||||
)
|
||||
);
|
||||
}
|
||||
if (kerberos == null) {
|
||||
try {
|
||||
kerberos = retrieveKerberos();
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
}
|
||||
const username = credentials.username;
|
||||
const password = credentials.password;
|
||||
const mechanismProperties = credentials.mechanismProperties;
|
||||
const serviceName =
|
||||
mechanismProperties['gssapiservicename'] ||
|
||||
mechanismProperties['gssapiServiceName'] ||
|
||||
'mongodb';
|
||||
performGssapiCanonicalizeHostName(host, mechanismProperties, (err, host) => {
|
||||
if (err) return callback(err);
|
||||
const initOptions = {};
|
||||
if (password != null) {
|
||||
Object.assign(initOptions, { user: username, password: password });
|
||||
}
|
||||
kerberos.initializeClient(
|
||||
`${serviceName}${process.platform === 'win32' ? '/' : '@'}${host}`,
|
||||
initOptions,
|
||||
(err, client) => {
|
||||
if (err) return callback(new MongoError(err));
|
||||
callback(null, client);
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Perform first step against mongodb
|
||||
var MongoDBGSSAPIFirstStep = function(
|
||||
self,
|
||||
mongo_auth_process,
|
||||
payload,
|
||||
db,
|
||||
username,
|
||||
password,
|
||||
authdb,
|
||||
sendAuthCommand,
|
||||
connection,
|
||||
callback
|
||||
) {
|
||||
// Build the sasl start command
|
||||
var command = {
|
||||
function saslStart(payload) {
|
||||
return {
|
||||
saslStart: 1,
|
||||
mechanism: 'GSSAPI',
|
||||
payload: payload,
|
||||
payload,
|
||||
autoAuthorize: 1
|
||||
};
|
||||
|
||||
// Write the commmand on the connection
|
||||
sendAuthCommand(connection, '$external.$cmd', command, (err, doc) => {
|
||||
if (err) return callback(err, false);
|
||||
// Execute mongodb transition
|
||||
mongo_auth_process.transition(doc.payload, function(err, payload) {
|
||||
if (err) return callback(err, false);
|
||||
|
||||
// MongoDB API Second Step
|
||||
MongoDBGSSAPISecondStep(
|
||||
self,
|
||||
mongo_auth_process,
|
||||
payload,
|
||||
doc,
|
||||
db,
|
||||
username,
|
||||
password,
|
||||
authdb,
|
||||
sendAuthCommand,
|
||||
connection,
|
||||
callback
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
// Perform first step against mongodb
|
||||
var MongoDBGSSAPISecondStep = function(
|
||||
self,
|
||||
mongo_auth_process,
|
||||
payload,
|
||||
doc,
|
||||
db,
|
||||
username,
|
||||
password,
|
||||
authdb,
|
||||
sendAuthCommand,
|
||||
connection,
|
||||
callback
|
||||
) {
|
||||
// Build Authentication command to send to MongoDB
|
||||
var command = {
|
||||
}
|
||||
function saslContinue(payload, conversationId) {
|
||||
return {
|
||||
saslContinue: 1,
|
||||
conversationId: doc.conversationId,
|
||||
payload: payload
|
||||
conversationId,
|
||||
payload
|
||||
};
|
||||
|
||||
// Execute the command
|
||||
// Write the commmand on the connection
|
||||
sendAuthCommand(connection, '$external.$cmd', command, (err, doc) => {
|
||||
if (err) return callback(err, false);
|
||||
// Call next transition for kerberos
|
||||
mongo_auth_process.transition(doc.payload, function(err, payload) {
|
||||
if (err) return callback(err, false);
|
||||
|
||||
// Call the last and third step
|
||||
MongoDBGSSAPIThirdStep(
|
||||
self,
|
||||
mongo_auth_process,
|
||||
payload,
|
||||
doc,
|
||||
db,
|
||||
username,
|
||||
password,
|
||||
authdb,
|
||||
sendAuthCommand,
|
||||
connection,
|
||||
callback
|
||||
);
|
||||
}
|
||||
function negotiate(client, retries, payload, callback) {
|
||||
client.step(payload, (err, response) => {
|
||||
// Retries exhausted, raise error
|
||||
if (err && retries === 0) return callback(err);
|
||||
// Adjust number of retries and call step again
|
||||
if (err) return negotiate(client, retries - 1, payload, callback);
|
||||
// Return the payload
|
||||
callback(undefined, response || '');
|
||||
});
|
||||
}
|
||||
function finalize(client, user, payload, callback) {
|
||||
// GSS Client Unwrap
|
||||
client.unwrap(payload, (err, response) => {
|
||||
if (err) return callback(err);
|
||||
// Wrap the response
|
||||
client.wrap(response || '', { user }, (err, wrapped) => {
|
||||
if (err) return callback(err);
|
||||
// Return the payload
|
||||
callback(undefined, wrapped);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var MongoDBGSSAPIThirdStep = function(
|
||||
self,
|
||||
mongo_auth_process,
|
||||
payload,
|
||||
doc,
|
||||
db,
|
||||
username,
|
||||
password,
|
||||
authdb,
|
||||
sendAuthCommand,
|
||||
connection,
|
||||
callback
|
||||
) {
|
||||
// Build final command
|
||||
var command = {
|
||||
saslContinue: 1,
|
||||
conversationId: doc.conversationId,
|
||||
payload: payload
|
||||
};
|
||||
|
||||
// Execute the command
|
||||
sendAuthCommand(connection, '$external.$cmd', command, (err, r) => {
|
||||
if (err) return callback(err, false);
|
||||
mongo_auth_process.transition(null, function(err) {
|
||||
if (err) return callback(err, null);
|
||||
callback(null, r);
|
||||
});
|
||||
}
|
||||
function performGssapiCanonicalizeHostName(host, mechanismProperties, callback) {
|
||||
const canonicalizeHostName =
|
||||
typeof mechanismProperties.gssapiCanonicalizeHostName === 'boolean'
|
||||
? mechanismProperties.gssapiCanonicalizeHostName
|
||||
: false;
|
||||
if (!canonicalizeHostName) return callback(undefined, host);
|
||||
// Attempt to resolve the host name
|
||||
dns.resolveCname(host, (err, r) => {
|
||||
if (err) return callback(err);
|
||||
// Get the first resolve host id
|
||||
if (Array.isArray(r) && r.length > 0) {
|
||||
return callback(undefined, r[0]);
|
||||
}
|
||||
callback(undefined, host);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a result from a authentication strategy
|
||||
*
|
||||
* @callback authResultCallback
|
||||
* @param {error} error An error object. Set to null if no error present
|
||||
* @param {boolean} result The result of the authentication process
|
||||
*/
|
||||
|
||||
module.exports = GSSAPI;
|
||||
}
|
||||
|
||||
35
node_modules/mongodb/lib/core/auth/mongo_credentials.js
generated
vendored
35
node_modules/mongodb/lib/core/auth/mongo_credentials.js
generated
vendored
@@ -47,7 +47,27 @@ class MongoCredentials {
|
||||
this.password = options.password;
|
||||
this.source = options.source || options.db;
|
||||
this.mechanism = options.mechanism || 'default';
|
||||
this.mechanismProperties = options.mechanismProperties;
|
||||
this.mechanismProperties = options.mechanismProperties || {};
|
||||
|
||||
if (/MONGODB-AWS/i.test(this.mechanism)) {
|
||||
if (!this.username && process.env.AWS_ACCESS_KEY_ID) {
|
||||
this.username = process.env.AWS_ACCESS_KEY_ID;
|
||||
}
|
||||
|
||||
if (!this.password && process.env.AWS_SECRET_ACCESS_KEY) {
|
||||
this.password = process.env.AWS_SECRET_ACCESS_KEY;
|
||||
}
|
||||
|
||||
if (
|
||||
this.mechanismProperties.AWS_SESSION_TOKEN == null &&
|
||||
process.env.AWS_SESSION_TOKEN != null
|
||||
) {
|
||||
this.mechanismProperties.AWS_SESSION_TOKEN = process.env.AWS_SESSION_TOKEN;
|
||||
}
|
||||
}
|
||||
|
||||
Object.freeze(this.mechanismProperties);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,12 +89,21 @@ class MongoCredentials {
|
||||
* based on the server version and server supported sasl mechanisms.
|
||||
*
|
||||
* @param {Object} [ismaster] An ismaster response from the server
|
||||
* @returns {MongoCredentials}
|
||||
*/
|
||||
resolveAuthMechanism(ismaster) {
|
||||
// If the mechanism is not "default", then it does not need to be resolved
|
||||
if (this.mechanism.toLowerCase() === 'default') {
|
||||
this.mechanism = getDefaultAuthMechanism(ismaster);
|
||||
if (/DEFAULT/i.test(this.mechanism)) {
|
||||
return new MongoCredentials({
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
source: this.source,
|
||||
mechanism: getDefaultAuthMechanism(ismaster),
|
||||
mechanismProperties: this.mechanismProperties
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
18
node_modules/mongodb/lib/core/auth/mongocr.js
generated
vendored
18
node_modules/mongodb/lib/core/auth/mongocr.js
generated
vendored
@@ -3,27 +3,21 @@
|
||||
const crypto = require('crypto');
|
||||
const AuthProvider = require('./auth_provider').AuthProvider;
|
||||
|
||||
/**
|
||||
* Creates a new MongoCR authentication mechanism
|
||||
*
|
||||
* @extends AuthProvider
|
||||
*/
|
||||
class MongoCR extends AuthProvider {
|
||||
/**
|
||||
* Implementation of authentication for a single connection
|
||||
* @override
|
||||
*/
|
||||
_authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) {
|
||||
auth(authContext, callback) {
|
||||
const connection = authContext.connection;
|
||||
const credentials = authContext.credentials;
|
||||
const username = credentials.username;
|
||||
const password = credentials.password;
|
||||
const source = credentials.source;
|
||||
|
||||
sendAuthCommand(connection, `${source}.$cmd`, { getnonce: 1 }, (err, r) => {
|
||||
connection.command(`${source}.$cmd`, { getnonce: 1 }, (err, result) => {
|
||||
let nonce = null;
|
||||
let key = null;
|
||||
|
||||
// Get nonce
|
||||
if (err == null) {
|
||||
const r = result.result;
|
||||
nonce = r.nonce;
|
||||
// Use node md5 generator
|
||||
let md5 = crypto.createHash('md5');
|
||||
@@ -43,7 +37,7 @@ class MongoCR extends AuthProvider {
|
||||
key
|
||||
};
|
||||
|
||||
sendAuthCommand(connection, `${source}.$cmd`, authenticateCommand, callback);
|
||||
connection.command(`${source}.$cmd`, authenticateCommand, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
17
node_modules/mongodb/lib/core/auth/plain.js
generated
vendored
17
node_modules/mongodb/lib/core/auth/plain.js
generated
vendored
@@ -1,5 +1,4 @@
|
||||
'use strict';
|
||||
|
||||
const retrieveBSON = require('../connection/utils').retrieveBSON;
|
||||
const AuthProvider = require('./auth_provider').AuthProvider;
|
||||
|
||||
@@ -7,19 +6,13 @@ const AuthProvider = require('./auth_provider').AuthProvider;
|
||||
const BSON = retrieveBSON();
|
||||
const Binary = BSON.Binary;
|
||||
|
||||
/**
|
||||
* Creates a new Plain authentication mechanism
|
||||
*
|
||||
* @extends AuthProvider
|
||||
*/
|
||||
class Plain extends AuthProvider {
|
||||
/**
|
||||
* Implementation of authentication for a single connection
|
||||
* @override
|
||||
*/
|
||||
_authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) {
|
||||
auth(authContext, callback) {
|
||||
const connection = authContext.connection;
|
||||
const credentials = authContext.credentials;
|
||||
const username = credentials.username;
|
||||
const password = credentials.password;
|
||||
|
||||
const payload = new Binary(`\x00${username}\x00${password}`);
|
||||
const command = {
|
||||
saslStart: 1,
|
||||
@@ -28,7 +21,7 @@ class Plain extends AuthProvider {
|
||||
autoAuthorize: 1
|
||||
};
|
||||
|
||||
sendAuthCommand(connection, '$external.$cmd', command, callback);
|
||||
connection.command('$external.$cmd', command, callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
443
node_modules/mongodb/lib/core/auth/scram.js
generated
vendored
443
node_modules/mongodb/lib/core/auth/scram.js
generated
vendored
@@ -1,47 +1,252 @@
|
||||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
const Buffer = require('safe-buffer').Buffer;
|
||||
const retrieveBSON = require('../connection/utils').retrieveBSON;
|
||||
const MongoError = require('../error').MongoError;
|
||||
const AuthProvider = require('./auth_provider').AuthProvider;
|
||||
const emitWarningOnce = require('../../utils').emitWarning;
|
||||
|
||||
const BSON = retrieveBSON();
|
||||
const Binary = BSON.Binary;
|
||||
|
||||
let saslprep;
|
||||
try {
|
||||
// Ensure you always wrap an optional require in the try block NODE-3199
|
||||
saslprep = require('saslprep');
|
||||
} catch (e) {
|
||||
// don't do anything;
|
||||
}
|
||||
|
||||
var parsePayload = function(payload) {
|
||||
var dict = {};
|
||||
var parts = payload.split(',');
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var valueParts = parts[i].split('=');
|
||||
class ScramSHA extends AuthProvider {
|
||||
constructor(bson, cryptoMethod) {
|
||||
super(bson);
|
||||
this.cryptoMethod = cryptoMethod || 'sha1';
|
||||
}
|
||||
|
||||
prepare(handshakeDoc, authContext, callback) {
|
||||
const cryptoMethod = this.cryptoMethod;
|
||||
if (cryptoMethod === 'sha256' && saslprep == null) {
|
||||
emitWarningOnce('Warning: no saslprep library specified. Passwords will not be sanitized');
|
||||
}
|
||||
|
||||
crypto.randomBytes(24, (err, nonce) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// store the nonce for later use
|
||||
Object.assign(authContext, { nonce });
|
||||
|
||||
const credentials = authContext.credentials;
|
||||
const request = Object.assign({}, handshakeDoc, {
|
||||
speculativeAuthenticate: Object.assign(makeFirstMessage(cryptoMethod, credentials, nonce), {
|
||||
db: credentials.source
|
||||
})
|
||||
});
|
||||
|
||||
callback(undefined, request);
|
||||
});
|
||||
}
|
||||
|
||||
auth(authContext, callback) {
|
||||
const response = authContext.response;
|
||||
if (response && response.speculativeAuthenticate) {
|
||||
continueScramConversation(
|
||||
this.cryptoMethod,
|
||||
response.speculativeAuthenticate,
|
||||
authContext,
|
||||
callback
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
executeScram(this.cryptoMethod, authContext, callback);
|
||||
}
|
||||
}
|
||||
|
||||
function cleanUsername(username) {
|
||||
return username.replace('=', '=3D').replace(',', '=2C');
|
||||
}
|
||||
|
||||
function clientFirstMessageBare(username, nonce) {
|
||||
// NOTE: This is done b/c Javascript uses UTF-16, but the server is hashing in UTF-8.
|
||||
// Since the username is not sasl-prep-d, we need to do this here.
|
||||
return Buffer.concat([
|
||||
Buffer.from('n=', 'utf8'),
|
||||
Buffer.from(username, 'utf8'),
|
||||
Buffer.from(',r=', 'utf8'),
|
||||
Buffer.from(nonce.toString('base64'), 'utf8')
|
||||
]);
|
||||
}
|
||||
|
||||
function makeFirstMessage(cryptoMethod, credentials, nonce) {
|
||||
const username = cleanUsername(credentials.username);
|
||||
const mechanism = cryptoMethod === 'sha1' ? 'SCRAM-SHA-1' : 'SCRAM-SHA-256';
|
||||
|
||||
// NOTE: This is done b/c Javascript uses UTF-16, but the server is hashing in UTF-8.
|
||||
// Since the username is not sasl-prep-d, we need to do this here.
|
||||
return {
|
||||
saslStart: 1,
|
||||
mechanism,
|
||||
payload: new Binary(
|
||||
Buffer.concat([Buffer.from('n,,', 'utf8'), clientFirstMessageBare(username, nonce)])
|
||||
),
|
||||
autoAuthorize: 1,
|
||||
options: { skipEmptyExchange: true }
|
||||
};
|
||||
}
|
||||
|
||||
function executeScram(cryptoMethod, authContext, callback) {
|
||||
const connection = authContext.connection;
|
||||
const credentials = authContext.credentials;
|
||||
const nonce = authContext.nonce;
|
||||
const db = credentials.source;
|
||||
|
||||
const saslStartCmd = makeFirstMessage(cryptoMethod, credentials, nonce);
|
||||
connection.command(`${db}.$cmd`, saslStartCmd, (_err, result) => {
|
||||
const err = resolveError(_err, result);
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
continueScramConversation(cryptoMethod, result.result, authContext, callback);
|
||||
});
|
||||
}
|
||||
|
||||
function continueScramConversation(cryptoMethod, response, authContext, callback) {
|
||||
const connection = authContext.connection;
|
||||
const credentials = authContext.credentials;
|
||||
const nonce = authContext.nonce;
|
||||
|
||||
const db = credentials.source;
|
||||
const username = cleanUsername(credentials.username);
|
||||
const password = credentials.password;
|
||||
|
||||
let processedPassword;
|
||||
if (cryptoMethod === 'sha256') {
|
||||
processedPassword = saslprep ? saslprep(password) : password;
|
||||
} else {
|
||||
try {
|
||||
processedPassword = passwordDigest(username, password);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
}
|
||||
|
||||
const payload = Buffer.isBuffer(response.payload)
|
||||
? new Binary(response.payload)
|
||||
: response.payload;
|
||||
const dict = parsePayload(payload.value());
|
||||
|
||||
const iterations = parseInt(dict.i, 10);
|
||||
if (iterations && iterations < 4096) {
|
||||
callback(new MongoError(`Server returned an invalid iteration count ${iterations}`), false);
|
||||
return;
|
||||
}
|
||||
|
||||
const salt = dict.s;
|
||||
const rnonce = dict.r;
|
||||
if (rnonce.startsWith('nonce')) {
|
||||
callback(new MongoError(`Server returned an invalid nonce: ${rnonce}`), false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up start of proof
|
||||
const withoutProof = `c=biws,r=${rnonce}`;
|
||||
const saltedPassword = HI(
|
||||
processedPassword,
|
||||
Buffer.from(salt, 'base64'),
|
||||
iterations,
|
||||
cryptoMethod
|
||||
);
|
||||
|
||||
const clientKey = HMAC(cryptoMethod, saltedPassword, 'Client Key');
|
||||
const serverKey = HMAC(cryptoMethod, saltedPassword, 'Server Key');
|
||||
const storedKey = H(cryptoMethod, clientKey);
|
||||
const authMessage = [
|
||||
clientFirstMessageBare(username, nonce),
|
||||
payload.value().toString('base64'),
|
||||
withoutProof
|
||||
].join(',');
|
||||
|
||||
const clientSignature = HMAC(cryptoMethod, storedKey, authMessage);
|
||||
const clientProof = `p=${xor(clientKey, clientSignature)}`;
|
||||
const clientFinal = [withoutProof, clientProof].join(',');
|
||||
|
||||
const serverSignature = HMAC(cryptoMethod, serverKey, authMessage);
|
||||
const saslContinueCmd = {
|
||||
saslContinue: 1,
|
||||
conversationId: response.conversationId,
|
||||
payload: new Binary(Buffer.from(clientFinal))
|
||||
};
|
||||
|
||||
connection.command(`${db}.$cmd`, saslContinueCmd, (_err, result) => {
|
||||
const err = resolveError(_err, result);
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
const r = result.result;
|
||||
const parsedResponse = parsePayload(r.payload.value());
|
||||
if (!compareDigest(Buffer.from(parsedResponse.v, 'base64'), serverSignature)) {
|
||||
callback(new MongoError('Server returned an invalid signature'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!r || r.done !== false) {
|
||||
return callback(err, r);
|
||||
}
|
||||
|
||||
const retrySaslContinueCmd = {
|
||||
saslContinue: 1,
|
||||
conversationId: r.conversationId,
|
||||
payload: Buffer.alloc(0)
|
||||
};
|
||||
|
||||
connection.command(`${db}.$cmd`, retrySaslContinueCmd, callback);
|
||||
});
|
||||
}
|
||||
|
||||
function parsePayload(payload) {
|
||||
const dict = {};
|
||||
const parts = payload.split(',');
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const valueParts = parts[i].split('=');
|
||||
dict[valueParts[0]] = valueParts[1];
|
||||
}
|
||||
|
||||
return dict;
|
||||
};
|
||||
}
|
||||
|
||||
var passwordDigest = function(username, password) {
|
||||
if (typeof username !== 'string') throw new MongoError('username must be a string');
|
||||
if (typeof password !== 'string') throw new MongoError('password must be a string');
|
||||
if (password.length === 0) throw new MongoError('password cannot be empty');
|
||||
// Use node md5 generator
|
||||
var md5 = crypto.createHash('md5');
|
||||
// Generate keys used for authentication
|
||||
md5.update(username + ':mongo:' + password, 'utf8');
|
||||
function passwordDigest(username, password) {
|
||||
if (typeof username !== 'string') {
|
||||
throw new MongoError('username must be a string');
|
||||
}
|
||||
|
||||
if (typeof password !== 'string') {
|
||||
throw new MongoError('password must be a string');
|
||||
}
|
||||
|
||||
if (password.length === 0) {
|
||||
throw new MongoError('password cannot be empty');
|
||||
}
|
||||
|
||||
const md5 = crypto.createHash('md5');
|
||||
md5.update(`${username}:mongo:${password}`, 'utf8');
|
||||
return md5.digest('hex');
|
||||
};
|
||||
}
|
||||
|
||||
// XOR two buffers
|
||||
function xor(a, b) {
|
||||
if (!Buffer.isBuffer(a)) a = Buffer.from(a);
|
||||
if (!Buffer.isBuffer(b)) b = Buffer.from(b);
|
||||
if (!Buffer.isBuffer(a)) {
|
||||
a = Buffer.from(a);
|
||||
}
|
||||
|
||||
if (!Buffer.isBuffer(b)) {
|
||||
b = Buffer.from(b);
|
||||
}
|
||||
|
||||
const length = Math.max(a.length, b.length);
|
||||
const res = [];
|
||||
|
||||
@@ -66,12 +271,12 @@ function HMAC(method, key, text) {
|
||||
.digest();
|
||||
}
|
||||
|
||||
var _hiCache = {};
|
||||
var _hiCacheCount = 0;
|
||||
var _hiCachePurge = function() {
|
||||
let _hiCache = {};
|
||||
let _hiCacheCount = 0;
|
||||
function _hiCachePurge() {
|
||||
_hiCache = {};
|
||||
_hiCacheCount = 0;
|
||||
};
|
||||
}
|
||||
|
||||
const hiLengthMap = {
|
||||
sha256: 32,
|
||||
@@ -121,205 +326,19 @@ function compareDigest(lhs, rhs) {
|
||||
return result === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ScramSHA authentication mechanism
|
||||
* @class
|
||||
* @extends AuthProvider
|
||||
*/
|
||||
class ScramSHA extends AuthProvider {
|
||||
constructor(bson, cryptoMethod) {
|
||||
super(bson);
|
||||
this.cryptoMethod = cryptoMethod || 'sha1';
|
||||
}
|
||||
function resolveError(err, result) {
|
||||
if (err) return err;
|
||||
|
||||
static _getError(err, r) {
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (r.$err || r.errmsg) {
|
||||
return new MongoError(r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
_executeScram(sendAuthCommand, connection, credentials, nonce, callback) {
|
||||
let username = credentials.username;
|
||||
const password = credentials.password;
|
||||
const db = credentials.source;
|
||||
|
||||
const cryptoMethod = this.cryptoMethod;
|
||||
let mechanism = 'SCRAM-SHA-1';
|
||||
let processedPassword;
|
||||
|
||||
if (cryptoMethod === 'sha256') {
|
||||
mechanism = 'SCRAM-SHA-256';
|
||||
|
||||
processedPassword = saslprep ? saslprep(password) : password;
|
||||
} else {
|
||||
try {
|
||||
processedPassword = passwordDigest(username, password);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up the user
|
||||
username = username.replace('=', '=3D').replace(',', '=2C');
|
||||
|
||||
// NOTE: This is done b/c Javascript uses UTF-16, but the server is hashing in UTF-8.
|
||||
// Since the username is not sasl-prep-d, we need to do this here.
|
||||
const firstBare = Buffer.concat([
|
||||
Buffer.from('n=', 'utf8'),
|
||||
Buffer.from(username, 'utf8'),
|
||||
Buffer.from(',r=', 'utf8'),
|
||||
Buffer.from(nonce, 'utf8')
|
||||
]);
|
||||
|
||||
// Build command structure
|
||||
const saslStartCmd = {
|
||||
saslStart: 1,
|
||||
mechanism,
|
||||
payload: new Binary(Buffer.concat([Buffer.from('n,,', 'utf8'), firstBare])),
|
||||
autoAuthorize: 1
|
||||
};
|
||||
|
||||
// Write the commmand on the connection
|
||||
sendAuthCommand(connection, `${db}.$cmd`, saslStartCmd, (err, r) => {
|
||||
let tmpError = ScramSHA._getError(err, r);
|
||||
if (tmpError) {
|
||||
return callback(tmpError, null);
|
||||
}
|
||||
|
||||
const payload = Buffer.isBuffer(r.payload) ? new Binary(r.payload) : r.payload;
|
||||
const dict = parsePayload(payload.value());
|
||||
|
||||
const iterations = parseInt(dict.i, 10);
|
||||
if (iterations && iterations < 4096) {
|
||||
callback(new MongoError(`Server returned an invalid iteration count ${iterations}`), false);
|
||||
return;
|
||||
}
|
||||
|
||||
const salt = dict.s;
|
||||
const rnonce = dict.r;
|
||||
if (rnonce.startsWith('nonce')) {
|
||||
callback(new MongoError(`Server returned an invalid nonce: ${rnonce}`), false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up start of proof
|
||||
const withoutProof = `c=biws,r=${rnonce}`;
|
||||
const saltedPassword = HI(
|
||||
processedPassword,
|
||||
Buffer.from(salt, 'base64'),
|
||||
iterations,
|
||||
cryptoMethod
|
||||
);
|
||||
|
||||
const clientKey = HMAC(cryptoMethod, saltedPassword, 'Client Key');
|
||||
const serverKey = HMAC(cryptoMethod, saltedPassword, 'Server Key');
|
||||
const storedKey = H(cryptoMethod, clientKey);
|
||||
const authMessage = [firstBare, payload.value().toString('base64'), withoutProof].join(',');
|
||||
|
||||
const clientSignature = HMAC(cryptoMethod, storedKey, authMessage);
|
||||
const clientProof = `p=${xor(clientKey, clientSignature)}`;
|
||||
const clientFinal = [withoutProof, clientProof].join(',');
|
||||
|
||||
const serverSignature = HMAC(cryptoMethod, serverKey, authMessage);
|
||||
|
||||
const saslContinueCmd = {
|
||||
saslContinue: 1,
|
||||
conversationId: r.conversationId,
|
||||
payload: new Binary(Buffer.from(clientFinal))
|
||||
};
|
||||
|
||||
sendAuthCommand(connection, `${db}.$cmd`, saslContinueCmd, (err, r) => {
|
||||
if (err || (r && typeof r.ok === 'number' && r.ok === 0)) {
|
||||
callback(err, r);
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedResponse = parsePayload(r.payload.value());
|
||||
if (!compareDigest(Buffer.from(parsedResponse.v, 'base64'), serverSignature)) {
|
||||
callback(new MongoError('Server returned an invalid signature'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!r || r.done !== false) {
|
||||
return callback(err, r);
|
||||
}
|
||||
|
||||
const retrySaslContinueCmd = {
|
||||
saslContinue: 1,
|
||||
conversationId: r.conversationId,
|
||||
payload: Buffer.alloc(0)
|
||||
};
|
||||
|
||||
sendAuthCommand(connection, `${db}.$cmd`, retrySaslContinueCmd, callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of authentication for a single connection
|
||||
* @override
|
||||
*/
|
||||
_authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) {
|
||||
// Create a random nonce
|
||||
crypto.randomBytes(24, (err, buff) => {
|
||||
if (err) {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
return this._executeScram(
|
||||
sendAuthCommand,
|
||||
connection,
|
||||
credentials,
|
||||
buff.toString('base64'),
|
||||
callback
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate
|
||||
* @override
|
||||
* @method
|
||||
*/
|
||||
auth(sendAuthCommand, connections, credentials, callback) {
|
||||
this._checkSaslprep();
|
||||
super.auth(sendAuthCommand, connections, credentials, callback);
|
||||
}
|
||||
|
||||
_checkSaslprep() {
|
||||
const cryptoMethod = this.cryptoMethod;
|
||||
|
||||
if (cryptoMethod === 'sha256') {
|
||||
if (!saslprep) {
|
||||
console.warn('Warning: no saslprep library specified. Passwords will not be sanitized');
|
||||
}
|
||||
}
|
||||
}
|
||||
const r = result.result;
|
||||
if (r.$err || r.errmsg) return new MongoError(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ScramSHA1 authentication mechanism
|
||||
* @class
|
||||
* @extends ScramSHA
|
||||
*/
|
||||
class ScramSHA1 extends ScramSHA {
|
||||
constructor(bson) {
|
||||
super(bson, 'sha1');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ScramSHA256 authentication mechanism
|
||||
* @class
|
||||
* @extends ScramSHA
|
||||
*/
|
||||
class ScramSHA256 extends ScramSHA {
|
||||
constructor(bson) {
|
||||
super(bson, 'sha256');
|
||||
|
||||
131
node_modules/mongodb/lib/core/auth/sspi.js
generated
vendored
131
node_modules/mongodb/lib/core/auth/sspi.js
generated
vendored
@@ -1,131 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const AuthProvider = require('./auth_provider').AuthProvider;
|
||||
const retrieveKerberos = require('../utils').retrieveKerberos;
|
||||
let kerberos;
|
||||
|
||||
/**
|
||||
* Creates a new SSPI authentication mechanism
|
||||
* @class
|
||||
* @extends AuthProvider
|
||||
*/
|
||||
class SSPI extends AuthProvider {
|
||||
/**
|
||||
* Implementation of authentication for a single connection
|
||||
* @override
|
||||
*/
|
||||
_authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) {
|
||||
// TODO: Destructure this
|
||||
const username = credentials.username;
|
||||
const password = credentials.password;
|
||||
const mechanismProperties = credentials.mechanismProperties;
|
||||
const gssapiServiceName =
|
||||
mechanismProperties['gssapiservicename'] ||
|
||||
mechanismProperties['gssapiServiceName'] ||
|
||||
'mongodb';
|
||||
|
||||
SSIPAuthenticate(
|
||||
this,
|
||||
kerberos.processes.MongoAuthProcess,
|
||||
username,
|
||||
password,
|
||||
gssapiServiceName,
|
||||
sendAuthCommand,
|
||||
connection,
|
||||
mechanismProperties,
|
||||
callback
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate
|
||||
* @override
|
||||
* @method
|
||||
*/
|
||||
auth(sendAuthCommand, connections, credentials, callback) {
|
||||
if (kerberos == null) {
|
||||
try {
|
||||
kerberos = retrieveKerberos();
|
||||
} catch (e) {
|
||||
return callback(e, null);
|
||||
}
|
||||
}
|
||||
|
||||
super.auth(sendAuthCommand, connections, credentials, callback);
|
||||
}
|
||||
}
|
||||
|
||||
function SSIPAuthenticate(
|
||||
self,
|
||||
MongoAuthProcess,
|
||||
username,
|
||||
password,
|
||||
gssapiServiceName,
|
||||
sendAuthCommand,
|
||||
connection,
|
||||
options,
|
||||
callback
|
||||
) {
|
||||
const authProcess = new MongoAuthProcess(
|
||||
connection.host,
|
||||
connection.port,
|
||||
gssapiServiceName,
|
||||
options
|
||||
);
|
||||
|
||||
function authCommand(command, authCb) {
|
||||
sendAuthCommand(connection, '$external.$cmd', command, authCb);
|
||||
}
|
||||
|
||||
authProcess.init(username, password, err => {
|
||||
if (err) return callback(err, false);
|
||||
|
||||
authProcess.transition('', (err, payload) => {
|
||||
if (err) return callback(err, false);
|
||||
|
||||
const command = {
|
||||
saslStart: 1,
|
||||
mechanism: 'GSSAPI',
|
||||
payload,
|
||||
autoAuthorize: 1
|
||||
};
|
||||
|
||||
authCommand(command, (err, doc) => {
|
||||
if (err) return callback(err, false);
|
||||
|
||||
authProcess.transition(doc.payload, (err, payload) => {
|
||||
if (err) return callback(err, false);
|
||||
const command = {
|
||||
saslContinue: 1,
|
||||
conversationId: doc.conversationId,
|
||||
payload
|
||||
};
|
||||
|
||||
authCommand(command, (err, doc) => {
|
||||
if (err) return callback(err, false);
|
||||
|
||||
authProcess.transition(doc.payload, (err, payload) => {
|
||||
if (err) return callback(err, false);
|
||||
const command = {
|
||||
saslContinue: 1,
|
||||
conversationId: doc.conversationId,
|
||||
payload
|
||||
};
|
||||
|
||||
authCommand(command, (err, response) => {
|
||||
if (err) return callback(err, false);
|
||||
|
||||
authProcess.transition(null, err => {
|
||||
if (err) return callback(err, null);
|
||||
callback(null, response);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = SSPI;
|
||||
41
node_modules/mongodb/lib/core/auth/x509.js
generated
vendored
41
node_modules/mongodb/lib/core/auth/x509.js
generated
vendored
@@ -1,26 +1,35 @@
|
||||
'use strict';
|
||||
|
||||
const AuthProvider = require('./auth_provider').AuthProvider;
|
||||
|
||||
/**
|
||||
* Creates a new X509 authentication mechanism
|
||||
* @class
|
||||
* @extends AuthProvider
|
||||
*/
|
||||
class X509 extends AuthProvider {
|
||||
/**
|
||||
* Implementation of authentication for a single connection
|
||||
* @override
|
||||
*/
|
||||
_authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) {
|
||||
const username = credentials.username;
|
||||
const command = { authenticate: 1, mechanism: 'MONGODB-X509' };
|
||||
if (username) {
|
||||
command.user = username;
|
||||
prepare(handshakeDoc, authContext, callback) {
|
||||
const credentials = authContext.credentials;
|
||||
Object.assign(handshakeDoc, {
|
||||
speculativeAuthenticate: x509AuthenticateCommand(credentials)
|
||||
});
|
||||
|
||||
callback(undefined, handshakeDoc);
|
||||
}
|
||||
|
||||
auth(authContext, callback) {
|
||||
const connection = authContext.connection;
|
||||
const credentials = authContext.credentials;
|
||||
const response = authContext.response;
|
||||
if (response.speculativeAuthenticate) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
sendAuthCommand(connection, '$external.$cmd', command, callback);
|
||||
connection.command('$external.$cmd', x509AuthenticateCommand(credentials), callback);
|
||||
}
|
||||
}
|
||||
|
||||
function x509AuthenticateCommand(credentials) {
|
||||
const command = { authenticate: 1, mechanism: 'MONGODB-X509' };
|
||||
if (credentials.username) {
|
||||
Object.assign(command, { user: credentials.username });
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
module.exports = X509;
|
||||
|
||||
133
node_modules/mongodb/lib/core/connection/apm.js
generated
vendored
133
node_modules/mongodb/lib/core/connection/apm.js
generated
vendored
@@ -1,123 +1,16 @@
|
||||
'use strict';
|
||||
const Msg = require('../connection/msg').Msg;
|
||||
const KillCursor = require('../connection/commands').KillCursor;
|
||||
const GetMore = require('../connection/commands').GetMore;
|
||||
const calculateDurationInMs = require('../../utils').calculateDurationInMs;
|
||||
|
||||
/** Commands that we want to redact because of the sensitive nature of their contents */
|
||||
const SENSITIVE_COMMANDS = new Set([
|
||||
'authenticate',
|
||||
'saslStart',
|
||||
'saslContinue',
|
||||
'getnonce',
|
||||
'createUser',
|
||||
'updateUser',
|
||||
'copydbgetnonce',
|
||||
'copydbsaslstart',
|
||||
'copydb'
|
||||
]);
|
||||
const extractCommand = require('../../command_utils').extractCommand;
|
||||
|
||||
// helper methods
|
||||
const extractCommandName = commandDoc => Object.keys(commandDoc)[0];
|
||||
const namespace = command => command.ns;
|
||||
const databaseName = command => command.ns.split('.')[0];
|
||||
const collectionName = command => command.ns.split('.')[1];
|
||||
const generateConnectionId = pool =>
|
||||
pool.options ? `${pool.options.host}:${pool.options.port}` : pool.address;
|
||||
const maybeRedact = (commandName, result) => (SENSITIVE_COMMANDS.has(commandName) ? {} : result);
|
||||
const isLegacyPool = pool => pool.s && pool.queue;
|
||||
|
||||
const LEGACY_FIND_QUERY_MAP = {
|
||||
$query: 'filter',
|
||||
$orderby: 'sort',
|
||||
$hint: 'hint',
|
||||
$comment: 'comment',
|
||||
$maxScan: 'maxScan',
|
||||
$max: 'max',
|
||||
$min: 'min',
|
||||
$returnKey: 'returnKey',
|
||||
$showDiskLoc: 'showRecordId',
|
||||
$maxTimeMS: 'maxTimeMS',
|
||||
$snapshot: 'snapshot'
|
||||
};
|
||||
|
||||
const LEGACY_FIND_OPTIONS_MAP = {
|
||||
numberToSkip: 'skip',
|
||||
numberToReturn: 'batchSize',
|
||||
returnFieldsSelector: 'projection'
|
||||
};
|
||||
|
||||
const OP_QUERY_KEYS = [
|
||||
'tailable',
|
||||
'oplogReplay',
|
||||
'noCursorTimeout',
|
||||
'awaitData',
|
||||
'partial',
|
||||
'exhaust'
|
||||
];
|
||||
|
||||
/**
|
||||
* Extract the actual command from the query, possibly upconverting if it's a legacy
|
||||
* format
|
||||
*
|
||||
* @param {Object} command the command
|
||||
*/
|
||||
const extractCommand = command => {
|
||||
if (command instanceof GetMore) {
|
||||
return {
|
||||
getMore: command.cursorId,
|
||||
collection: collectionName(command),
|
||||
batchSize: command.numberToReturn
|
||||
};
|
||||
}
|
||||
|
||||
if (command instanceof KillCursor) {
|
||||
return {
|
||||
killCursors: collectionName(command),
|
||||
cursors: command.cursorIds
|
||||
};
|
||||
}
|
||||
|
||||
if (command instanceof Msg) {
|
||||
return command.command;
|
||||
}
|
||||
|
||||
if (command.query && command.query.$query) {
|
||||
let result;
|
||||
if (command.ns === 'admin.$cmd') {
|
||||
// upconvert legacy command
|
||||
result = Object.assign({}, command.query.$query);
|
||||
} else {
|
||||
// upconvert legacy find command
|
||||
result = { find: collectionName(command) };
|
||||
Object.keys(LEGACY_FIND_QUERY_MAP).forEach(key => {
|
||||
if (typeof command.query[key] !== 'undefined')
|
||||
result[LEGACY_FIND_QUERY_MAP[key]] = command.query[key];
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => {
|
||||
if (typeof command[key] !== 'undefined') result[LEGACY_FIND_OPTIONS_MAP[key]] = command[key];
|
||||
});
|
||||
|
||||
OP_QUERY_KEYS.forEach(key => {
|
||||
if (command[key]) result[key] = command[key];
|
||||
});
|
||||
|
||||
if (typeof command.pre32Limit !== 'undefined') {
|
||||
result.limit = command.pre32Limit;
|
||||
}
|
||||
|
||||
if (command.query.$explain) {
|
||||
return { explain: result };
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return command.query ? command.query : command;
|
||||
};
|
||||
|
||||
const extractReply = (command, reply) => {
|
||||
if (command instanceof GetMore) {
|
||||
return {
|
||||
@@ -177,21 +70,15 @@ class CommandStartedEvent {
|
||||
* @param {Object} command the command
|
||||
*/
|
||||
constructor(pool, command) {
|
||||
const cmd = extractCommand(command);
|
||||
const commandName = extractCommandName(cmd);
|
||||
const extractedCommand = extractCommand(command);
|
||||
const commandName = extractedCommand.name;
|
||||
const connectionDetails = extractConnectionDetails(pool);
|
||||
|
||||
// NOTE: remove in major revision, this is not spec behavior
|
||||
if (SENSITIVE_COMMANDS.has(commandName)) {
|
||||
this.commandObj = {};
|
||||
this.commandObj[commandName] = true;
|
||||
}
|
||||
|
||||
Object.assign(this, connectionDetails, {
|
||||
requestId: command.requestId,
|
||||
databaseName: databaseName(command),
|
||||
commandName,
|
||||
command: cmd
|
||||
command: extractedCommand.shouldRedact ? {} : extractedCommand.cmd
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -207,15 +94,15 @@ class CommandSucceededEvent {
|
||||
* @param {Array} started a high resolution tuple timestamp of when the command was first sent, to calculate duration
|
||||
*/
|
||||
constructor(pool, command, reply, started) {
|
||||
const cmd = extractCommand(command);
|
||||
const commandName = extractCommandName(cmd);
|
||||
const extractedCommand = extractCommand(command);
|
||||
const commandName = extractedCommand.name;
|
||||
const connectionDetails = extractConnectionDetails(pool);
|
||||
|
||||
Object.assign(this, connectionDetails, {
|
||||
requestId: command.requestId,
|
||||
commandName,
|
||||
duration: calculateDurationInMs(started),
|
||||
reply: maybeRedact(commandName, extractReply(command, reply))
|
||||
reply: extractedCommand.shouldRedact ? {} : extractReply(command, reply)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -231,15 +118,15 @@ class CommandFailedEvent {
|
||||
* @param {Array} started a high resolution tuple timestamp of when the command was first sent, to calculate duration
|
||||
*/
|
||||
constructor(pool, command, error, started) {
|
||||
const cmd = extractCommand(command);
|
||||
const commandName = extractCommandName(cmd);
|
||||
const extractedCommand = extractCommand(command);
|
||||
const commandName = extractedCommand.name;
|
||||
const connectionDetails = extractConnectionDetails(pool);
|
||||
|
||||
Object.assign(this, connectionDetails, {
|
||||
requestId: command.requestId,
|
||||
commandName,
|
||||
duration: calculateDurationInMs(started),
|
||||
failure: maybeRedact(commandName, error)
|
||||
failure: extractedCommand.shouldRedact ? {} : error
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
13
node_modules/mongodb/lib/core/connection/commands.js
generated
vendored
13
node_modules/mongodb/lib/core/connection/commands.js
generated
vendored
@@ -398,7 +398,12 @@ KillCursor.prototype.toBin = function() {
|
||||
};
|
||||
|
||||
var Response = function(bson, message, msgHeader, msgBody, opts) {
|
||||
opts = opts || { promoteLongs: true, promoteValues: true, promoteBuffers: false };
|
||||
opts = opts || {
|
||||
promoteLongs: true,
|
||||
promoteValues: true,
|
||||
promoteBuffers: false,
|
||||
bsonRegExp: false
|
||||
};
|
||||
this.parsed = false;
|
||||
this.raw = message;
|
||||
this.data = msgBody;
|
||||
@@ -429,6 +434,7 @@ var Response = function(bson, message, msgHeader, msgBody, opts) {
|
||||
this.promoteLongs = typeof opts.promoteLongs === 'boolean' ? opts.promoteLongs : true;
|
||||
this.promoteValues = typeof opts.promoteValues === 'boolean' ? opts.promoteValues : true;
|
||||
this.promoteBuffers = typeof opts.promoteBuffers === 'boolean' ? opts.promoteBuffers : false;
|
||||
this.bsonRegExp = typeof opts.bsonRegExp === 'boolean' ? opts.bsonRegExp : false;
|
||||
};
|
||||
|
||||
Response.prototype.isParsed = function() {
|
||||
@@ -449,13 +455,16 @@ Response.prototype.parse = function(options) {
|
||||
typeof options.promoteValues === 'boolean' ? options.promoteValues : this.opts.promoteValues;
|
||||
var promoteBuffers =
|
||||
typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : this.opts.promoteBuffers;
|
||||
var bsonRegExp =
|
||||
typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : this.opts.bsonRegExp;
|
||||
var bsonSize, _options;
|
||||
|
||||
// Set up the options
|
||||
_options = {
|
||||
promoteLongs: promoteLongs,
|
||||
promoteValues: promoteValues,
|
||||
promoteBuffers: promoteBuffers
|
||||
promoteBuffers: promoteBuffers,
|
||||
bsonRegExp: bsonRegExp
|
||||
};
|
||||
|
||||
// Position within OP_REPLY at which documents start
|
||||
|
||||
288
node_modules/mongodb/lib/core/connection/connect.js
generated
vendored
288
node_modules/mongodb/lib/core/connection/connect.js
generated
vendored
@@ -2,10 +2,11 @@
|
||||
const net = require('net');
|
||||
const tls = require('tls');
|
||||
const Connection = require('./connection');
|
||||
const Query = require('./commands').Query;
|
||||
const MongoError = require('../error').MongoError;
|
||||
const MongoNetworkError = require('../error').MongoNetworkError;
|
||||
const MongoNetworkTimeoutError = require('../error').MongoNetworkTimeoutError;
|
||||
const defaultAuthProviders = require('../auth/defaultAuthProviders').defaultAuthProviders;
|
||||
const AuthContext = require('../auth/auth_provider').AuthContext;
|
||||
const WIRE_CONSTANTS = require('../wireprotocol/constants');
|
||||
const makeClientMetadata = require('../utils').makeClientMetadata;
|
||||
const MAX_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_WIRE_VERSION;
|
||||
@@ -37,30 +38,7 @@ function connect(options, cancellationToken, callback) {
|
||||
}
|
||||
|
||||
function isModernConnectionType(conn) {
|
||||
return typeof conn.command === 'function';
|
||||
}
|
||||
|
||||
function getSaslSupportedMechs(options) {
|
||||
if (!(options && options.credentials)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const credentials = options.credentials;
|
||||
|
||||
// TODO: revisit whether or not items like `options.user` and `options.dbName` should be checked here
|
||||
const authMechanism = credentials.mechanism;
|
||||
const authSource = credentials.source || options.dbName || 'admin';
|
||||
const user = credentials.username || options.user;
|
||||
|
||||
if (typeof authMechanism === 'string' && authMechanism.toUpperCase() !== 'DEFAULT') {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return { saslSupportedMechs: `${authSource}.${user}` };
|
||||
return !(conn instanceof Connection);
|
||||
}
|
||||
|
||||
function checkSupportedServer(ismaster, options) {
|
||||
@@ -97,77 +75,130 @@ function performInitialHandshake(conn, options, _callback) {
|
||||
_callback(err, ret);
|
||||
};
|
||||
|
||||
let compressors = [];
|
||||
if (options.compression && options.compression.compressors) {
|
||||
compressors = options.compression.compressors;
|
||||
const credentials = options.credentials;
|
||||
if (credentials) {
|
||||
if (!credentials.mechanism.match(/DEFAULT/i) && !AUTH_PROVIDERS[credentials.mechanism]) {
|
||||
callback(new MongoError(`authMechanism '${credentials.mechanism}' not supported`));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const handshakeDoc = Object.assign(
|
||||
{
|
||||
ismaster: true,
|
||||
client: options.metadata || makeClientMetadata(options),
|
||||
compression: compressors
|
||||
},
|
||||
getSaslSupportedMechs(options)
|
||||
);
|
||||
|
||||
const handshakeOptions = Object.assign({}, options);
|
||||
|
||||
// The handshake technically is a monitoring check, so its socket timeout should be connectTimeoutMS
|
||||
if (options.connectTimeoutMS || options.connectionTimeout) {
|
||||
handshakeOptions.socketTimeout = options.connectTimeoutMS || options.connectionTimeout;
|
||||
}
|
||||
|
||||
const start = new Date().getTime();
|
||||
runCommand(conn, 'admin.$cmd', handshakeDoc, handshakeOptions, (err, ismaster) => {
|
||||
const authContext = new AuthContext(conn, credentials, options);
|
||||
prepareHandshakeDocument(authContext, (err, handshakeDoc) => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (ismaster.ok === 0) {
|
||||
callback(new MongoError(ismaster));
|
||||
return;
|
||||
const handshakeOptions = Object.assign({}, options);
|
||||
if (options.connectTimeoutMS || options.connectionTimeout) {
|
||||
// The handshake technically is a monitoring check, so its socket timeout should be connectTimeoutMS
|
||||
handshakeOptions.socketTimeout = options.connectTimeoutMS || options.connectionTimeout;
|
||||
}
|
||||
|
||||
const supportedServerErr = checkSupportedServer(ismaster, options);
|
||||
if (supportedServerErr) {
|
||||
callback(supportedServerErr);
|
||||
return;
|
||||
}
|
||||
handshakeDoc.helloOk = !!options.useUnifiedTopology;
|
||||
|
||||
if (!isModernConnectionType(conn)) {
|
||||
// resolve compression
|
||||
if (ismaster.compression) {
|
||||
const agreedCompressors = compressors.filter(
|
||||
compressor => ismaster.compression.indexOf(compressor) !== -1
|
||||
);
|
||||
const start = new Date().getTime();
|
||||
conn.command('admin.$cmd', handshakeDoc, handshakeOptions, (err, result) => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (agreedCompressors.length) {
|
||||
conn.agreedCompressor = agreedCompressors[0];
|
||||
}
|
||||
const response = result.result;
|
||||
if (response.ok === 0) {
|
||||
callback(new MongoError(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.compression && options.compression.zlibCompressionLevel) {
|
||||
conn.zlibCompressionLevel = options.compression.zlibCompressionLevel;
|
||||
if ('isWritablePrimary' in response) {
|
||||
// Provide pre-hello-style response document.
|
||||
response.ismaster = response.isWritablePrimary;
|
||||
}
|
||||
|
||||
if (options.useUnifiedTopology && response.helloOk) {
|
||||
conn.helloOk = true;
|
||||
}
|
||||
|
||||
const supportedServerErr = checkSupportedServer(response, options);
|
||||
if (supportedServerErr) {
|
||||
callback(supportedServerErr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isModernConnectionType(conn)) {
|
||||
// resolve compression
|
||||
if (response.compression) {
|
||||
const agreedCompressors = handshakeDoc.compression.filter(
|
||||
compressor => response.compression.indexOf(compressor) !== -1
|
||||
);
|
||||
|
||||
if (agreedCompressors.length) {
|
||||
conn.agreedCompressor = agreedCompressors[0];
|
||||
}
|
||||
|
||||
if (options.compression && options.compression.zlibCompressionLevel) {
|
||||
conn.zlibCompressionLevel = options.compression.zlibCompressionLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This is metadata attached to the connection while porting away from
|
||||
// handshake being done in the `Server` class. Likely, it should be
|
||||
// relocated, or at very least restructured.
|
||||
conn.ismaster = ismaster;
|
||||
conn.lastIsMasterMS = new Date().getTime() - start;
|
||||
// NOTE: This is metadata attached to the connection while porting away from
|
||||
// handshake being done in the `Server` class. Likely, it should be
|
||||
// relocated, or at very least restructured.
|
||||
conn.ismaster = response;
|
||||
conn.lastIsMasterMS = new Date().getTime() - start;
|
||||
|
||||
const credentials = options.credentials;
|
||||
if (!ismaster.arbiterOnly && credentials) {
|
||||
credentials.resolveAuthMechanism(ismaster);
|
||||
authenticate(conn, credentials, callback);
|
||||
if (!response.arbiterOnly && credentials) {
|
||||
// store the response on auth context
|
||||
Object.assign(authContext, { response });
|
||||
|
||||
const resolvedCredentials = credentials.resolveAuthMechanism(response);
|
||||
const authProvider = AUTH_PROVIDERS[resolvedCredentials.mechanism];
|
||||
authProvider.auth(authContext, err => {
|
||||
if (err) return callback(err);
|
||||
callback(undefined, conn);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
callback(undefined, conn);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function prepareHandshakeDocument(authContext, callback) {
|
||||
const options = authContext.options;
|
||||
const serverApi = authContext.connection.serverApi;
|
||||
const compressors =
|
||||
options.compression && options.compression.compressors ? options.compression.compressors : [];
|
||||
|
||||
const handshakeDoc = {
|
||||
[serverApi ? 'hello' : 'ismaster']: true,
|
||||
client: options.metadata || makeClientMetadata(options),
|
||||
compression: compressors
|
||||
};
|
||||
|
||||
const credentials = authContext.credentials;
|
||||
if (credentials) {
|
||||
if (credentials.mechanism.match(/DEFAULT/i) && credentials.username) {
|
||||
Object.assign(handshakeDoc, {
|
||||
saslSupportedMechs: `${credentials.source}.${credentials.username}`
|
||||
});
|
||||
|
||||
AUTH_PROVIDERS['scram-sha-256'].prepare(handshakeDoc, authContext, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(undefined, conn);
|
||||
});
|
||||
const authProvider = AUTH_PROVIDERS[credentials.mechanism];
|
||||
if (authProvider == null) {
|
||||
return callback(new MongoError(`No AuthProvider for ${credentials.mechanism} defined.`));
|
||||
}
|
||||
authProvider.prepare(handshakeDoc, authContext, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(undefined, handshakeDoc);
|
||||
}
|
||||
|
||||
const LEGAL_SSL_SOCKET_OPTIONS = [
|
||||
@@ -227,7 +258,7 @@ function parseSslOptions(family, options) {
|
||||
}
|
||||
|
||||
// Set default sni servername to be the same as host
|
||||
if (result.servername == null) {
|
||||
if (result.servername == null && !net.isIP(result.host)) {
|
||||
result.servername = result.host;
|
||||
}
|
||||
|
||||
@@ -239,7 +270,7 @@ function makeConnection(family, options, cancellationToken, _callback) {
|
||||
const useSsl = typeof options.ssl === 'boolean' ? options.ssl : false;
|
||||
const keepAlive = typeof options.keepAlive === 'boolean' ? options.keepAlive : true;
|
||||
let keepAliveInitialDelay =
|
||||
typeof options.keepAliveInitialDelay === 'number' ? options.keepAliveInitialDelay : 300000;
|
||||
typeof options.keepAliveInitialDelay === 'number' ? options.keepAliveInitialDelay : 120000;
|
||||
const noDelay = typeof options.noDelay === 'boolean' ? options.noDelay : true;
|
||||
const connectionTimeout =
|
||||
typeof options.connectionTimeout === 'number'
|
||||
@@ -247,12 +278,17 @@ function makeConnection(family, options, cancellationToken, _callback) {
|
||||
: typeof options.connectTimeoutMS === 'number'
|
||||
? options.connectTimeoutMS
|
||||
: 30000;
|
||||
const socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
|
||||
const socketTimeoutMS =
|
||||
typeof options.socketTimeoutMS === 'number'
|
||||
? options.socketTimeoutMS
|
||||
: typeof options.socketTimeout === 'number'
|
||||
? options.socketTimeout
|
||||
: 0;
|
||||
const rejectUnauthorized =
|
||||
typeof options.rejectUnauthorized === 'boolean' ? options.rejectUnauthorized : true;
|
||||
|
||||
if (keepAliveInitialDelay > socketTimeout) {
|
||||
keepAliveInitialDelay = Math.round(socketTimeout / 2);
|
||||
if (keepAliveInitialDelay > socketTimeoutMS) {
|
||||
keepAliveInitialDelay = Math.round(socketTimeoutMS / 2);
|
||||
}
|
||||
|
||||
let socket;
|
||||
@@ -305,7 +341,7 @@ function makeConnection(family, options, cancellationToken, _callback) {
|
||||
return callback(socket.authorizationError);
|
||||
}
|
||||
|
||||
socket.setTimeout(socketTimeout);
|
||||
socket.setTimeout(socketTimeoutMS);
|
||||
callback(null, socket);
|
||||
}
|
||||
|
||||
@@ -318,92 +354,12 @@ function makeConnection(family, options, cancellationToken, _callback) {
|
||||
socket.once(connectEvent, connectHandler);
|
||||
}
|
||||
|
||||
const CONNECTION_ERROR_EVENTS = ['error', 'close', 'timeout', 'parseError'];
|
||||
function runCommand(conn, ns, command, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
|
||||
// are we using the new connection type? if so, no need to simulate a rpc `command` method
|
||||
if (isModernConnectionType(conn)) {
|
||||
conn.command(ns, command, options, (err, result) => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// NODE-2382: raw wire protocol messages, or command results should not be used anymore
|
||||
callback(undefined, result.result);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
|
||||
const bson = conn.options.bson;
|
||||
const query = new Query(bson, ns, command, {
|
||||
numberToSkip: 0,
|
||||
numberToReturn: 1
|
||||
});
|
||||
|
||||
const noop = () => {};
|
||||
function _callback(err, result) {
|
||||
callback(err, result);
|
||||
callback = noop;
|
||||
}
|
||||
|
||||
function errorHandler(err) {
|
||||
conn.resetSocketTimeout();
|
||||
CONNECTION_ERROR_EVENTS.forEach(eventName => conn.removeListener(eventName, errorHandler));
|
||||
conn.removeListener('message', messageHandler);
|
||||
|
||||
if (err == null) {
|
||||
err = new MongoError(`runCommand failed for connection to '${conn.address}'`);
|
||||
}
|
||||
|
||||
// ignore all future errors
|
||||
conn.on('error', noop);
|
||||
|
||||
_callback(err);
|
||||
}
|
||||
|
||||
function messageHandler(msg) {
|
||||
if (msg.responseTo !== query.requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
conn.resetSocketTimeout();
|
||||
CONNECTION_ERROR_EVENTS.forEach(eventName => conn.removeListener(eventName, errorHandler));
|
||||
conn.removeListener('message', messageHandler);
|
||||
|
||||
msg.parse({ promoteValues: true });
|
||||
_callback(undefined, msg.documents[0]);
|
||||
}
|
||||
|
||||
conn.setSocketTimeout(socketTimeout);
|
||||
CONNECTION_ERROR_EVENTS.forEach(eventName => conn.once(eventName, errorHandler));
|
||||
conn.on('message', messageHandler);
|
||||
conn.write(query.toBin());
|
||||
}
|
||||
|
||||
function authenticate(conn, credentials, callback) {
|
||||
const mechanism = credentials.mechanism;
|
||||
if (!AUTH_PROVIDERS[mechanism]) {
|
||||
callback(new MongoError(`authMechanism '${mechanism}' not supported`));
|
||||
return;
|
||||
}
|
||||
|
||||
const provider = AUTH_PROVIDERS[mechanism];
|
||||
provider.auth(runCommand, [conn], credentials, err => {
|
||||
if (err) return callback(err);
|
||||
callback(undefined, conn);
|
||||
});
|
||||
}
|
||||
|
||||
function connectionFailureError(type, err) {
|
||||
switch (type) {
|
||||
case 'error':
|
||||
return new MongoNetworkError(err);
|
||||
case 'timeout':
|
||||
return new MongoNetworkError(`connection timed out`);
|
||||
return new MongoNetworkTimeoutError(`connection timed out`);
|
||||
case 'close':
|
||||
return new MongoNetworkError(`connection closed`);
|
||||
case 'cancel':
|
||||
|
||||
88
node_modules/mongodb/lib/core/connection/connection.js
generated
vendored
88
node_modules/mongodb/lib/core/connection/connection.js
generated
vendored
@@ -8,12 +8,15 @@ const decompress = require('../wireprotocol/compression').decompress;
|
||||
const Response = require('./commands').Response;
|
||||
const BinMsg = require('./msg').BinMsg;
|
||||
const MongoNetworkError = require('../error').MongoNetworkError;
|
||||
const MongoNetworkTimeoutError = require('../error').MongoNetworkTimeoutError;
|
||||
const MongoError = require('../error').MongoError;
|
||||
const Logger = require('./logger');
|
||||
const OP_COMPRESSED = require('../wireprotocol/shared').opcodes.OP_COMPRESSED;
|
||||
const OP_MSG = require('../wireprotocol/shared').opcodes.OP_MSG;
|
||||
const MESSAGE_HEADER_SIZE = require('../wireprotocol/shared').MESSAGE_HEADER_SIZE;
|
||||
const Buffer = require('safe-buffer').Buffer;
|
||||
const Query = require('./commands').Query;
|
||||
const CommandResult = require('./command_result');
|
||||
|
||||
let _id = 0;
|
||||
|
||||
@@ -35,6 +38,7 @@ const DEBUG_FIELDS = [
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'bsonRegExp',
|
||||
'checkServerIdentity'
|
||||
];
|
||||
|
||||
@@ -64,12 +68,13 @@ class Connection extends EventEmitter {
|
||||
* @param {string} [options.host='localhost'] The host the socket is connected to
|
||||
* @param {number} [options.port=27017] The port used for the socket connection
|
||||
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=300000] Initial delay before TCP keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=120000] Initial delay before TCP keep alive enabled
|
||||
* @param {number} [options.connectionTimeout=30000] TCP Connection timeout setting
|
||||
* @param {number} [options.socketTimeout=360000] TCP Socket timeout setting
|
||||
* @param {number} [options.socketTimeout=0] TCP Socket timeout setting
|
||||
* @param {boolean} [options.promoteLongs] Convert Long values from the db into Numbers if they fit into 53 bits
|
||||
* @param {boolean} [options.promoteValues] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
||||
* @param {boolean} [options.promoteBuffers] Promotes Binary BSON values to native Node Buffers.
|
||||
* @param {boolean} [options.bsonRegExp] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
||||
* @param {number} [options.maxBsonMessageSize=0x4000000] Largest possible size of a BSON message (for legacy purposes)
|
||||
*/
|
||||
constructor(socket, options) {
|
||||
@@ -86,15 +91,16 @@ class Connection extends EventEmitter {
|
||||
this.bson = options.bson;
|
||||
this.tag = options.tag;
|
||||
this.maxBsonMessageSize = options.maxBsonMessageSize || DEFAULT_MAX_BSON_MESSAGE_SIZE;
|
||||
this.helloOk = undefined;
|
||||
|
||||
this.port = options.port || 27017;
|
||||
this.host = options.host || 'localhost';
|
||||
this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
|
||||
this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 0;
|
||||
|
||||
// These values are inspected directly in tests, but maybe not necessary to keep around
|
||||
this.keepAlive = typeof options.keepAlive === 'boolean' ? options.keepAlive : true;
|
||||
this.keepAliveInitialDelay =
|
||||
typeof options.keepAliveInitialDelay === 'number' ? options.keepAliveInitialDelay : 300000;
|
||||
typeof options.keepAliveInitialDelay === 'number' ? options.keepAliveInitialDelay : 120000;
|
||||
this.connectionTimeout =
|
||||
typeof options.connectionTimeout === 'number' ? options.connectionTimeout : 30000;
|
||||
if (this.keepAliveInitialDelay > this.socketTimeout) {
|
||||
@@ -114,7 +120,8 @@ class Connection extends EventEmitter {
|
||||
this.responseOptions = {
|
||||
promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true,
|
||||
promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true,
|
||||
promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false
|
||||
promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false,
|
||||
bsonRegExp: typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : false
|
||||
};
|
||||
|
||||
// Flushing
|
||||
@@ -184,6 +191,7 @@ class Connection extends EventEmitter {
|
||||
* Unref this connection
|
||||
* @method
|
||||
* @return {boolean}
|
||||
* @deprecated This function is deprecated and will be removed in the next major version.
|
||||
*/
|
||||
unref() {
|
||||
if (this.socket == null) {
|
||||
@@ -251,10 +259,10 @@ class Connection extends EventEmitter {
|
||||
// Debug Log
|
||||
if (this.logger.isDebug()) {
|
||||
if (!Array.isArray(buffer)) {
|
||||
this.logger.debug(`writing buffer [${buffer.toString('hex')}] to ${this.address}`);
|
||||
this.logger.debug(`writing buffer [ ${buffer.length} ] to ${this.address}`);
|
||||
} else {
|
||||
for (let i = 0; i < buffer.length; i++)
|
||||
this.logger.debug(`writing buffer [${buffer[i].toString('hex')}] to ${this.address}`);
|
||||
this.logger.debug(`writing buffer [ ${buffer[i].length} ] to ${this.address}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,8 +313,70 @@ class Connection extends EventEmitter {
|
||||
if (this.destroyed) return false;
|
||||
return !this.socket.destroyed && this.socket.writable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
command(ns, command, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
|
||||
const conn = this;
|
||||
const socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 0;
|
||||
const bson = conn.options.bson;
|
||||
const query = new Query(bson, ns, command, {
|
||||
numberToSkip: 0,
|
||||
numberToReturn: 1
|
||||
});
|
||||
|
||||
const noop = () => {};
|
||||
function _callback(err, result) {
|
||||
callback(err, result);
|
||||
callback = noop;
|
||||
}
|
||||
|
||||
function errorHandler(err) {
|
||||
conn.resetSocketTimeout();
|
||||
CONNECTION_ERROR_EVENTS.forEach(eventName => conn.removeListener(eventName, errorHandler));
|
||||
conn.removeListener('message', messageHandler);
|
||||
|
||||
if (err == null) {
|
||||
err = new MongoError(`runCommand failed for connection to '${conn.address}'`);
|
||||
}
|
||||
|
||||
// ignore all future errors
|
||||
conn.on('error', noop);
|
||||
_callback(err);
|
||||
}
|
||||
|
||||
function messageHandler(msg) {
|
||||
if (msg.responseTo !== query.requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
conn.resetSocketTimeout();
|
||||
CONNECTION_ERROR_EVENTS.forEach(eventName => conn.removeListener(eventName, errorHandler));
|
||||
conn.removeListener('message', messageHandler);
|
||||
|
||||
msg.parse({ promoteValues: true });
|
||||
|
||||
const response = msg.documents[0];
|
||||
if (response.ok === 0 || response.$err || response.errmsg || response.code) {
|
||||
_callback(new MongoError(response));
|
||||
return;
|
||||
}
|
||||
|
||||
_callback(undefined, new CommandResult(response, this, msg));
|
||||
}
|
||||
|
||||
conn.setSocketTimeout(socketTimeout);
|
||||
CONNECTION_ERROR_EVENTS.forEach(eventName => conn.once(eventName, errorHandler));
|
||||
conn.on('message', messageHandler);
|
||||
conn.write(query.toBin());
|
||||
}
|
||||
}
|
||||
|
||||
const CONNECTION_ERROR_EVENTS = ['error', 'close', 'timeout', 'parseError'];
|
||||
|
||||
function deleteConnection(id) {
|
||||
// console.log("=== deleted connection " + id + " :: " + (connections[id] ? connections[id].port : ''))
|
||||
delete connections[id];
|
||||
@@ -352,7 +422,9 @@ function timeoutHandler(conn) {
|
||||
conn.timedOut = true;
|
||||
conn.emit(
|
||||
'timeout',
|
||||
new MongoNetworkError(`connection ${conn.id} to ${conn.address} timed out`),
|
||||
new MongoNetworkTimeoutError(`connection ${conn.id} to ${conn.address} timed out`, {
|
||||
beforeHandshake: conn.ismaster == null
|
||||
}),
|
||||
conn
|
||||
);
|
||||
};
|
||||
|
||||
1
node_modules/mongodb/lib/core/connection/logger.js
generated
vendored
1
node_modules/mongodb/lib/core/connection/logger.js
generated
vendored
@@ -37,6 +37,7 @@ var Logger = function(className, options) {
|
||||
if (options.logger) {
|
||||
currentLogger = options.logger;
|
||||
} else if (currentLogger == null) {
|
||||
// eslint-disable-next-line no-console
|
||||
currentLogger = console.log;
|
||||
}
|
||||
|
||||
|
||||
17
node_modules/mongodb/lib/core/connection/msg.js
generated
vendored
17
node_modules/mongodb/lib/core/connection/msg.js
generated
vendored
@@ -31,6 +31,7 @@ const Buffer = require('safe-buffer').Buffer;
|
||||
const opcodes = require('../wireprotocol/shared').opcodes;
|
||||
const databaseNamespace = require('../wireprotocol/shared').databaseNamespace;
|
||||
const ReadPreference = require('../topologies/read_preference');
|
||||
const MongoError = require('../../core/error').MongoError;
|
||||
|
||||
// Incrementing request id
|
||||
let _requestId = 0;
|
||||
@@ -138,7 +139,12 @@ Msg.getRequestId = function() {
|
||||
|
||||
class BinMsg {
|
||||
constructor(bson, message, msgHeader, msgBody, opts) {
|
||||
opts = opts || { promoteLongs: true, promoteValues: true, promoteBuffers: false };
|
||||
opts = opts || {
|
||||
promoteLongs: true,
|
||||
promoteValues: true,
|
||||
promoteBuffers: false,
|
||||
bsonRegExp: false
|
||||
};
|
||||
this.parsed = false;
|
||||
this.raw = message;
|
||||
this.data = msgBody;
|
||||
@@ -160,6 +166,7 @@ class BinMsg {
|
||||
this.promoteLongs = typeof opts.promoteLongs === 'boolean' ? opts.promoteLongs : true;
|
||||
this.promoteValues = typeof opts.promoteValues === 'boolean' ? opts.promoteValues : true;
|
||||
this.promoteBuffers = typeof opts.promoteBuffers === 'boolean' ? opts.promoteBuffers : false;
|
||||
this.bsonRegExp = typeof opts.bsonRegExp === 'boolean' ? opts.bsonRegExp : false;
|
||||
|
||||
this.documents = [];
|
||||
}
|
||||
@@ -185,18 +192,22 @@ class BinMsg {
|
||||
typeof options.promoteBuffers === 'boolean'
|
||||
? options.promoteBuffers
|
||||
: this.opts.promoteBuffers;
|
||||
const bsonRegExp =
|
||||
typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : this.opts.bsonRegExp;
|
||||
|
||||
// Set up the options
|
||||
const _options = {
|
||||
promoteLongs: promoteLongs,
|
||||
promoteValues: promoteValues,
|
||||
promoteBuffers: promoteBuffers
|
||||
promoteBuffers: promoteBuffers,
|
||||
bsonRegExp: bsonRegExp
|
||||
};
|
||||
|
||||
while (this.index < this.data.length) {
|
||||
const payloadType = this.data.readUInt8(this.index++);
|
||||
if (payloadType === 1) {
|
||||
console.error('TYPE 1');
|
||||
// It was decided that no driver makes use of payload type 1
|
||||
throw new MongoError('OP_MSG Payload Type 1 detected unsupported protocol');
|
||||
} else if (payloadType === 0) {
|
||||
const bsonSize = this.data.readUInt32LE(this.index);
|
||||
const bin = this.data.slice(this.index, this.index + bsonSize);
|
||||
|
||||
19
node_modules/mongodb/lib/core/connection/pool.js
generated
vendored
19
node_modules/mongodb/lib/core/connection/pool.js
generated
vendored
@@ -60,11 +60,11 @@ var _id = 0;
|
||||
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
|
||||
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
|
||||
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=300000] Initial delay before TCP keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=120000] Initial delay before TCP keep alive enabled
|
||||
* @param {boolean} [options.noDelay=true] TCP Connection no delay
|
||||
* @param {number} [options.connectionTimeout=30000] TCP Connection timeout setting
|
||||
* @param {number} [options.socketTimeout=360000] TCP Socket timeout setting
|
||||
* @param {number} [options.monitoringSocketTimeout=30000] TCP Socket timeout setting for replicaset monitoring socket
|
||||
* @param {number} [options.socketTimeout=0] TCP Socket timeout setting
|
||||
* @param {number} [options.monitoringSocketTimeout=0] TCP Socket timeout setting for replicaset monitoring socket
|
||||
* @param {boolean} [options.ssl=false] Use SSL for connection
|
||||
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
|
||||
* @param {Buffer} [options.ca] SSL Certificate store binary buffer
|
||||
@@ -76,6 +76,7 @@ var _id = 0;
|
||||
* @param {boolean} [options.promoteLongs=true] Convert Long values from the db into Numbers if they fit into 53 bits
|
||||
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
||||
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
||||
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
||||
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
|
||||
* @fires Pool#connect
|
||||
* @fires Pool#close
|
||||
@@ -111,9 +112,9 @@ var Pool = function(topology, options) {
|
||||
minSize: 0,
|
||||
// socket settings
|
||||
connectionTimeout: 30000,
|
||||
socketTimeout: 360000,
|
||||
socketTimeout: 0,
|
||||
keepAlive: true,
|
||||
keepAliveInitialDelay: 300000,
|
||||
keepAliveInitialDelay: 120000,
|
||||
noDelay: true,
|
||||
// SSL Settings
|
||||
ssl: false,
|
||||
@@ -127,6 +128,7 @@ var Pool = function(topology, options) {
|
||||
promoteLongs: true,
|
||||
promoteValues: true,
|
||||
promoteBuffers: false,
|
||||
bsonRegExp: false,
|
||||
// Reconnection options
|
||||
reconnect: true,
|
||||
reconnectInterval: 1000,
|
||||
@@ -390,8 +392,8 @@ function messageHandler(self) {
|
||||
if (self.logger.isDebug()) {
|
||||
self.logger.debug(
|
||||
f(
|
||||
'message [%s] received from %s:%s',
|
||||
message.raw.toString('hex'),
|
||||
'message [ %s ] received from %s:%s',
|
||||
message.raw.length,
|
||||
self.options.host,
|
||||
self.options.port
|
||||
)
|
||||
@@ -602,6 +604,7 @@ Pool.prototype.logout = function(dbName, callback) {
|
||||
/**
|
||||
* Unref the pool
|
||||
* @method
|
||||
* @deprecated This function is deprecated and will be removed in the next major version.
|
||||
*/
|
||||
Pool.prototype.unref = function() {
|
||||
// Get all the known connections
|
||||
@@ -870,6 +873,7 @@ Pool.prototype.write = function(command, options, cb) {
|
||||
promoteLongs: true,
|
||||
promoteValues: true,
|
||||
promoteBuffers: false,
|
||||
bsonRegExp: false,
|
||||
fullResult: false
|
||||
};
|
||||
|
||||
@@ -879,6 +883,7 @@ Pool.prototype.write = function(command, options, cb) {
|
||||
typeof options.promoteValues === 'boolean' ? options.promoteValues : true;
|
||||
operation.promoteBuffers =
|
||||
typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false;
|
||||
operation.bsonRegExp = typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : false;
|
||||
operation.raw = typeof options.raw === 'boolean' ? options.raw : false;
|
||||
operation.immediateRelease =
|
||||
typeof options.immediateRelease === 'boolean' ? options.immediateRelease : false;
|
||||
|
||||
56
node_modules/mongodb/lib/core/connection/utils.js
generated
vendored
56
node_modules/mongodb/lib/core/connection/utils.js
generated
vendored
@@ -1,9 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
const require_optional = require('require_optional');
|
||||
const parsePackageVersion = require('../../utils').parsePackageVersion;
|
||||
const MongoError = require('../error').MongoError;
|
||||
|
||||
const require_optional = require('optional-require')(require);
|
||||
|
||||
function debugOptions(debugFields, options) {
|
||||
var finaloptions = {};
|
||||
const finaloptions = {};
|
||||
debugFields.forEach(function(n) {
|
||||
finaloptions[n] = options[n];
|
||||
});
|
||||
@@ -12,16 +15,22 @@ function debugOptions(debugFields, options) {
|
||||
}
|
||||
|
||||
function retrieveBSON() {
|
||||
var BSON = require('bson');
|
||||
const BSON = require('bson');
|
||||
BSON.native = false;
|
||||
|
||||
try {
|
||||
var optionalBSON = require_optional('bson-ext');
|
||||
if (optionalBSON) {
|
||||
optionalBSON.native = true;
|
||||
return optionalBSON;
|
||||
const optionalBSON = require_optional('bson-ext');
|
||||
const bsonExtVersion = parsePackageVersion(
|
||||
require_optional('bson-ext/package.json') || { version: '0.0.0' }
|
||||
);
|
||||
if (optionalBSON) {
|
||||
if (bsonExtVersion.major >= 4) {
|
||||
throw new MongoError(
|
||||
'bson-ext version 4 and above does not work with the 3.x version of the mongodb driver'
|
||||
);
|
||||
}
|
||||
} catch (err) {} // eslint-disable-line
|
||||
optionalBSON.native = true;
|
||||
return optionalBSON;
|
||||
}
|
||||
|
||||
return BSON;
|
||||
}
|
||||
@@ -33,24 +42,43 @@ function noSnappyWarning() {
|
||||
);
|
||||
}
|
||||
|
||||
const PKG_VERSION = Symbol('kPkgVersion');
|
||||
|
||||
// Facilitate loading Snappy optionally
|
||||
function retrieveSnappy() {
|
||||
var snappy = null;
|
||||
try {
|
||||
snappy = require_optional('snappy');
|
||||
} catch (error) {} // eslint-disable-line
|
||||
const snappy = require_optional('snappy');
|
||||
if (!snappy) {
|
||||
snappy = {
|
||||
return {
|
||||
compress: noSnappyWarning,
|
||||
uncompress: noSnappyWarning,
|
||||
compressSync: noSnappyWarning,
|
||||
uncompressSync: noSnappyWarning
|
||||
};
|
||||
}
|
||||
|
||||
const snappyPkg = require_optional('snappy/package.json') || { version: '0.0.0' };
|
||||
const version = parsePackageVersion(snappyPkg);
|
||||
snappy[PKG_VERSION] = version;
|
||||
if (version.major >= 7) {
|
||||
const compressOriginal = snappy.compress;
|
||||
const uncompressOriginal = snappy.uncompress;
|
||||
snappy.compress = (data, callback) => {
|
||||
compressOriginal(data)
|
||||
.then(res => callback(undefined, res))
|
||||
.catch(error => callback(error));
|
||||
};
|
||||
snappy.uncompress = (data, callback) => {
|
||||
uncompressOriginal(data)
|
||||
.then(res => callback(undefined, res))
|
||||
.catch(error => callback(error));
|
||||
};
|
||||
}
|
||||
|
||||
return snappy;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
PKG_VERSION,
|
||||
debugOptions,
|
||||
retrieveBSON,
|
||||
retrieveSnappy
|
||||
|
||||
108
node_modules/mongodb/lib/core/cursor.js
generated
vendored
108
node_modules/mongodb/lib/core/cursor.js
generated
vendored
@@ -11,6 +11,7 @@ const executeOperation = require('../operations/execute_operation');
|
||||
const Readable = require('stream').Readable;
|
||||
const SUPPORTS = require('../utils').SUPPORTS;
|
||||
const MongoDBNamespace = require('../utils').MongoDBNamespace;
|
||||
const mergeOptions = require('../utils').mergeOptions;
|
||||
const OperationBase = require('../operations/operation').OperationBase;
|
||||
|
||||
const BSON = retrieveBSON();
|
||||
@@ -145,6 +146,13 @@ class CoreCursor extends Readable {
|
||||
this.cursorState.promoteBuffers = options.promoteBuffers;
|
||||
}
|
||||
|
||||
// Add bsonRegExp to cursor state
|
||||
if (typeof topologyOptions.bsonRegExp === 'boolean') {
|
||||
this.cursorState.bsonRegExp = topologyOptions.bsonRegExp;
|
||||
} else if (typeof options.bsonRegExp === 'boolean') {
|
||||
this.cursorState.bsonRegExp = options.bsonRegExp;
|
||||
}
|
||||
|
||||
if (topologyOptions.reconnect) {
|
||||
this.cursorState.reconnect = topologyOptions.reconnect;
|
||||
}
|
||||
@@ -207,7 +215,9 @@ class CoreCursor extends Readable {
|
||||
* @return {Cursor}
|
||||
*/
|
||||
clone() {
|
||||
return this.topology.cursor(this.ns, this.cmd, this.options);
|
||||
const clonedOptions = mergeOptions({}, this.options);
|
||||
delete clonedOptions.session;
|
||||
return this.topology.cursor(this.ns, this.cmd, clonedOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -464,50 +474,41 @@ class CoreCursor extends Readable {
|
||||
}
|
||||
|
||||
const result = r.message;
|
||||
if (result.queryFailure) {
|
||||
return done(new MongoError(result.documents[0]), null);
|
||||
}
|
||||
|
||||
// Check if we have a command cursor
|
||||
if (
|
||||
Array.isArray(result.documents) &&
|
||||
result.documents.length === 1 &&
|
||||
(!cursor.cmd.find || (cursor.cmd.find && cursor.cmd.virtual === false)) &&
|
||||
(typeof result.documents[0].cursor !== 'string' ||
|
||||
result.documents[0]['$err'] ||
|
||||
result.documents[0]['errmsg'] ||
|
||||
Array.isArray(result.documents[0].result))
|
||||
) {
|
||||
// We have an error document, return the error
|
||||
if (result.documents[0]['$err'] || result.documents[0]['errmsg']) {
|
||||
return done(new MongoError(result.documents[0]), null);
|
||||
if (Array.isArray(result.documents) && result.documents.length === 1) {
|
||||
const document = result.documents[0];
|
||||
|
||||
if (result.queryFailure) {
|
||||
return done(new MongoError(document), null);
|
||||
}
|
||||
|
||||
// We have a cursor document
|
||||
if (result.documents[0].cursor != null && typeof result.documents[0].cursor !== 'string') {
|
||||
const id = result.documents[0].cursor.id;
|
||||
// If we have a namespace change set the new namespace for getmores
|
||||
if (result.documents[0].cursor.ns) {
|
||||
cursor.ns = result.documents[0].cursor.ns;
|
||||
}
|
||||
// Promote id to long if needed
|
||||
cursor.cursorState.cursorId = typeof id === 'number' ? Long.fromNumber(id) : id;
|
||||
cursor.cursorState.lastCursorId = cursor.cursorState.cursorId;
|
||||
cursor.cursorState.operationTime = result.documents[0].operationTime;
|
||||
|
||||
// If we have a firstBatch set it
|
||||
if (Array.isArray(result.documents[0].cursor.firstBatch)) {
|
||||
cursor.cursorState.documents = result.documents[0].cursor.firstBatch; //.reverse();
|
||||
// Check if we have a command cursor
|
||||
if (!cursor.cmd.find || (cursor.cmd.find && cursor.cmd.virtual === false)) {
|
||||
// We have an error document, return the error
|
||||
if (document.$err || document.errmsg) {
|
||||
return done(new MongoError(document), null);
|
||||
}
|
||||
|
||||
// Return after processing command cursor
|
||||
return done(null, result);
|
||||
}
|
||||
// We have a cursor document
|
||||
if (document.cursor != null && typeof document.cursor !== 'string') {
|
||||
const id = document.cursor.id;
|
||||
// If we have a namespace change set the new namespace for getmores
|
||||
if (document.cursor.ns) {
|
||||
cursor.ns = document.cursor.ns;
|
||||
}
|
||||
// Promote id to long if needed
|
||||
cursor.cursorState.cursorId = typeof id === 'number' ? Long.fromNumber(id) : id;
|
||||
cursor.cursorState.lastCursorId = cursor.cursorState.cursorId;
|
||||
cursor.cursorState.operationTime = document.operationTime;
|
||||
|
||||
if (Array.isArray(result.documents[0].result)) {
|
||||
cursor.cursorState.documents = result.documents[0].result;
|
||||
cursor.cursorState.cursorId = Long.ZERO;
|
||||
return done(null, result);
|
||||
// If we have a firstBatch set it
|
||||
if (Array.isArray(document.cursor.firstBatch)) {
|
||||
cursor.cursorState.documents = document.cursor.firstBatch; //.reverse();
|
||||
}
|
||||
|
||||
// Return after processing command cursor
|
||||
return done(null, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -754,9 +755,10 @@ function nextFunction(self, callback) {
|
||||
|
||||
if (self.cursorState.limit > 0 && self.cursorState.currentLimit >= self.cursorState.limit) {
|
||||
// Ensure we kill the cursor on the server
|
||||
self.kill();
|
||||
// Set cursor in dead and notified state
|
||||
return setCursorDeadAndNotified(self, callback);
|
||||
self.kill(() =>
|
||||
// Set cursor in dead and notified state
|
||||
setCursorDeadAndNotified(self, callback)
|
||||
);
|
||||
} else if (
|
||||
self.cursorState.cursorIndex === self.cursorState.documents.length &&
|
||||
!Long.ZERO.equals(self.cursorState.cursorId)
|
||||
@@ -836,9 +838,12 @@ function nextFunction(self, callback) {
|
||||
} else {
|
||||
if (self.cursorState.limit > 0 && self.cursorState.currentLimit >= self.cursorState.limit) {
|
||||
// Ensure we kill the cursor on the server
|
||||
self.kill();
|
||||
// Set cursor in dead and notified state
|
||||
return setCursorDeadAndNotified(self, callback);
|
||||
self.kill(() =>
|
||||
// Set cursor in dead and notified state
|
||||
setCursorDeadAndNotified(self, callback)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Increment the current cursor limit
|
||||
@@ -850,11 +855,14 @@ function nextFunction(self, callback) {
|
||||
// Doc overflow
|
||||
if (!doc || doc.$err) {
|
||||
// Ensure we kill the cursor on the server
|
||||
self.kill();
|
||||
// Set cursor in dead and notified state
|
||||
return setCursorDeadAndNotified(self, function() {
|
||||
handleCallback(callback, new MongoError(doc ? doc.$err : undefined));
|
||||
});
|
||||
self.kill(() =>
|
||||
// Set cursor in dead and notified state
|
||||
setCursorDeadAndNotified(self, function() {
|
||||
handleCallback(callback, new MongoError(doc ? doc.$err : undefined));
|
||||
})
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Transform the doc with passed in transformation method if provided
|
||||
|
||||
158
node_modules/mongodb/lib/core/error.js
generated
vendored
158
node_modules/mongodb/lib/core/error.js
generated
vendored
@@ -1,5 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const MONGODB_ERROR_CODES = require('../error_codes').MONGODB_ERROR_CODES;
|
||||
|
||||
const kErrorLabels = Symbol('errorLabels');
|
||||
|
||||
/**
|
||||
* Creates a new MongoError
|
||||
*
|
||||
@@ -18,8 +22,12 @@ class MongoError extends Error {
|
||||
super(message);
|
||||
} else {
|
||||
super(message.message || message.errmsg || message.$err || 'n/a');
|
||||
if (message.errorLabels) {
|
||||
this[kErrorLabels] = new Set(message.errorLabels);
|
||||
}
|
||||
|
||||
for (var name in message) {
|
||||
if (name === 'errmsg') {
|
||||
if (name === 'errorLabels' || name === 'errmsg') {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -57,8 +65,29 @@ class MongoError extends Error {
|
||||
* @returns {boolean} returns true if the error has the provided error label
|
||||
*/
|
||||
hasErrorLabel(label) {
|
||||
return this.errorLabels && this.errorLabels.indexOf(label) !== -1;
|
||||
if (this[kErrorLabels] == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this[kErrorLabels].has(label);
|
||||
}
|
||||
|
||||
addErrorLabel(label) {
|
||||
if (this[kErrorLabels] == null) {
|
||||
this[kErrorLabels] = new Set();
|
||||
}
|
||||
|
||||
this[kErrorLabels].add(label);
|
||||
}
|
||||
|
||||
get errorLabels() {
|
||||
return this[kErrorLabels] ? Array.from(this[kErrorLabels]) : [];
|
||||
}
|
||||
}
|
||||
|
||||
const kBeforeHandshake = Symbol('beforeHandshake');
|
||||
function isNetworkErrorBeforeHandshake(err) {
|
||||
return err[kBeforeHandshake] === true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,9 +100,28 @@ class MongoError extends Error {
|
||||
* @extends MongoError
|
||||
*/
|
||||
class MongoNetworkError extends MongoError {
|
||||
constructor(message) {
|
||||
constructor(message, options) {
|
||||
super(message);
|
||||
this.name = 'MongoNetworkError';
|
||||
|
||||
if (options && typeof options.beforeHandshake === 'boolean') {
|
||||
this[kBeforeHandshake] = options.beforeHandshake;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An error indicating a network timeout occurred
|
||||
*
|
||||
* @param {Error|string|object} message The error message
|
||||
* @property {string} message The error message
|
||||
* @property {object} [options.beforeHandshake] Indicates the timeout happened before a connection handshake completed
|
||||
* @extends MongoError
|
||||
*/
|
||||
class MongoNetworkTimeoutError extends MongoNetworkError {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = 'MongoNetworkTimeoutError';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +206,10 @@ class MongoWriteConcernError extends MongoError {
|
||||
super(message);
|
||||
this.name = 'MongoWriteConcernError';
|
||||
|
||||
if (result && Array.isArray(result.errorLabels)) {
|
||||
this[kErrorLabels] = new Set(result.errorLabels);
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
this.result = makeWriteConcernResultObject(result);
|
||||
}
|
||||
@@ -166,19 +218,45 @@ class MongoWriteConcernError extends MongoError {
|
||||
|
||||
// see: https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.rst#terms
|
||||
const RETRYABLE_ERROR_CODES = new Set([
|
||||
6, // HostUnreachable
|
||||
7, // HostNotFound
|
||||
89, // NetworkTimeout
|
||||
91, // ShutdownInProgress
|
||||
189, // PrimarySteppedDown
|
||||
9001, // SocketException
|
||||
10107, // NotMaster
|
||||
11600, // InterruptedAtShutdown
|
||||
11602, // InterruptedDueToReplStateChange
|
||||
13435, // NotMasterNoSlaveOk
|
||||
13436 // NotMasterOrSecondary
|
||||
MONGODB_ERROR_CODES.HostUnreachable,
|
||||
MONGODB_ERROR_CODES.HostNotFound,
|
||||
MONGODB_ERROR_CODES.NetworkTimeout,
|
||||
MONGODB_ERROR_CODES.ShutdownInProgress,
|
||||
MONGODB_ERROR_CODES.PrimarySteppedDown,
|
||||
MONGODB_ERROR_CODES.SocketException,
|
||||
MONGODB_ERROR_CODES.NotMaster,
|
||||
MONGODB_ERROR_CODES.InterruptedAtShutdown,
|
||||
MONGODB_ERROR_CODES.InterruptedDueToReplStateChange,
|
||||
MONGODB_ERROR_CODES.NotMasterNoSlaveOk,
|
||||
MONGODB_ERROR_CODES.NotMasterOrSecondary
|
||||
]);
|
||||
|
||||
const RETRYABLE_WRITE_ERROR_CODES = new Set([
|
||||
MONGODB_ERROR_CODES.InterruptedAtShutdown,
|
||||
MONGODB_ERROR_CODES.InterruptedDueToReplStateChange,
|
||||
MONGODB_ERROR_CODES.NotMaster,
|
||||
MONGODB_ERROR_CODES.NotMasterNoSlaveOk,
|
||||
MONGODB_ERROR_CODES.NotMasterOrSecondary,
|
||||
MONGODB_ERROR_CODES.PrimarySteppedDown,
|
||||
MONGODB_ERROR_CODES.ShutdownInProgress,
|
||||
MONGODB_ERROR_CODES.HostNotFound,
|
||||
MONGODB_ERROR_CODES.HostUnreachable,
|
||||
MONGODB_ERROR_CODES.NetworkTimeout,
|
||||
MONGODB_ERROR_CODES.SocketException,
|
||||
MONGODB_ERROR_CODES.ExceededTimeLimit
|
||||
]);
|
||||
|
||||
function isRetryableWriteError(error) {
|
||||
if (error instanceof MongoWriteConcernError) {
|
||||
return (
|
||||
RETRYABLE_WRITE_ERROR_CODES.has(error.code) ||
|
||||
RETRYABLE_WRITE_ERROR_CODES.has(error.result.code)
|
||||
);
|
||||
}
|
||||
|
||||
return RETRYABLE_WRITE_ERROR_CODES.has(error.code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an error is something the driver should attempt to retry
|
||||
*
|
||||
@@ -195,41 +273,44 @@ function isRetryableError(error) {
|
||||
}
|
||||
|
||||
const SDAM_RECOVERING_CODES = new Set([
|
||||
91, // ShutdownInProgress
|
||||
189, // PrimarySteppedDown
|
||||
11600, // InterruptedAtShutdown
|
||||
11602, // InterruptedDueToReplStateChange
|
||||
13436 // NotMasterOrSecondary
|
||||
MONGODB_ERROR_CODES.ShutdownInProgress,
|
||||
MONGODB_ERROR_CODES.PrimarySteppedDown,
|
||||
MONGODB_ERROR_CODES.InterruptedAtShutdown,
|
||||
MONGODB_ERROR_CODES.InterruptedDueToReplStateChange,
|
||||
MONGODB_ERROR_CODES.NotMasterOrSecondary
|
||||
]);
|
||||
|
||||
const SDAM_NOTMASTER_CODES = new Set([
|
||||
10107, // NotMaster
|
||||
13435 // NotMasterNoSlaveOk
|
||||
MONGODB_ERROR_CODES.NotMaster,
|
||||
MONGODB_ERROR_CODES.NotMasterNoSlaveOk,
|
||||
MONGODB_ERROR_CODES.LegacyNotPrimary
|
||||
]);
|
||||
|
||||
const SDAM_NODE_SHUTTING_DOWN_ERROR_CODES = new Set([
|
||||
11600, // InterruptedAtShutdown
|
||||
91 // ShutdownInProgress
|
||||
MONGODB_ERROR_CODES.InterruptedAtShutdown,
|
||||
MONGODB_ERROR_CODES.ShutdownInProgress
|
||||
]);
|
||||
|
||||
function isRecoveringError(err) {
|
||||
if (err.code && SDAM_RECOVERING_CODES.has(err.code)) {
|
||||
return true;
|
||||
if (typeof err.code === 'number') {
|
||||
// If any error code exists, we ignore the error.message
|
||||
return SDAM_RECOVERING_CODES.has(err.code);
|
||||
}
|
||||
|
||||
return err.message.match(/not master or secondary/) || err.message.match(/node is recovering/);
|
||||
return /not master or secondary/.test(err.message) || /node is recovering/.test(err.message);
|
||||
}
|
||||
|
||||
function isNotMasterError(err) {
|
||||
if (err.code && SDAM_NOTMASTER_CODES.has(err.code)) {
|
||||
return true;
|
||||
if (typeof err.code === 'number') {
|
||||
// If any error code exists, we ignore the error.message
|
||||
return SDAM_NOTMASTER_CODES.has(err.code);
|
||||
}
|
||||
|
||||
if (isRecoveringError(err)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return err.message.match(/not master/);
|
||||
return /not master/.test(err.message);
|
||||
}
|
||||
|
||||
function isNodeShuttingDownError(err) {
|
||||
@@ -240,10 +321,9 @@ function isNodeShuttingDownError(err) {
|
||||
* Determines whether SDAM can recover from a given error. If it cannot
|
||||
* then the pool will be cleared, and server state will completely reset
|
||||
* locally.
|
||||
*
|
||||
* @ignore
|
||||
* @see https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#not-master-and-node-is-recovering
|
||||
* @param {MongoError|Error} error
|
||||
* @param {MongoError} error
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isSDAMUnrecoverableError(error) {
|
||||
// NOTE: null check is here for a strictly pre-CMAP world, a timeout or
|
||||
@@ -252,20 +332,13 @@ function isSDAMUnrecoverableError(error) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isRecoveringError(error) || isNotMasterError(error)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isNetworkTimeoutError(err) {
|
||||
return err instanceof MongoNetworkError && err.message.match(/timed out/);
|
||||
return isRecoveringError(error) || isNotMasterError(error);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
MongoError,
|
||||
MongoNetworkError,
|
||||
MongoNetworkTimeoutError,
|
||||
MongoParseError,
|
||||
MongoTimeoutError,
|
||||
MongoServerSelectionError,
|
||||
@@ -273,5 +346,6 @@ module.exports = {
|
||||
isRetryableError,
|
||||
isSDAMUnrecoverableError,
|
||||
isNodeShuttingDownError,
|
||||
isNetworkTimeoutError
|
||||
isRetryableWriteError,
|
||||
isNetworkErrorBeforeHandshake
|
||||
};
|
||||
|
||||
12
node_modules/mongodb/lib/core/index.js
generated
vendored
12
node_modules/mongodb/lib/core/index.js
generated
vendored
@@ -1,10 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
let BSON = require('bson');
|
||||
const require_optional = require('require_optional');
|
||||
const require_optional = require('optional-require')(require);
|
||||
const EJSON = require('./utils').retrieveEJSON();
|
||||
|
||||
try {
|
||||
// Ensure you always wrap an optional require in the try block NODE-3199
|
||||
// Attempt to grab the native BSON parser
|
||||
const BSONNative = require_optional('bson-ext');
|
||||
// If we got the native parser, use it instead of the
|
||||
@@ -14,7 +15,16 @@ try {
|
||||
}
|
||||
} catch (err) {} // eslint-disable-line
|
||||
|
||||
/** An enumeration of valid server API versions */
|
||||
const ServerApiVersion = Object.freeze({
|
||||
v1: '1'
|
||||
});
|
||||
const ValidServerApiVersions = Object.keys(ServerApiVersion).map(key => ServerApiVersion[key]);
|
||||
|
||||
module.exports = {
|
||||
// Versioned API
|
||||
ServerApiVersion,
|
||||
ValidServerApiVersions,
|
||||
// Errors
|
||||
MongoError: require('./error').MongoError,
|
||||
MongoNetworkError: require('./error').MongoNetworkError,
|
||||
|
||||
8
node_modules/mongodb/lib/core/sdam/common.js
generated
vendored
8
node_modules/mongodb/lib/core/sdam/common.js
generated
vendored
@@ -28,6 +28,13 @@ const ServerType = {
|
||||
Unknown: 'Unknown'
|
||||
};
|
||||
|
||||
// helper to get a server's type that works for both legacy and unified topologies
|
||||
function serverType(server) {
|
||||
let description = server.s.description || server.s.serverDescription;
|
||||
if (description.topologyType === TopologyType.Single) return description.servers[0].type;
|
||||
return description.type;
|
||||
}
|
||||
|
||||
const TOPOLOGY_DEFAULTS = {
|
||||
useUnifiedTopology: true,
|
||||
localThresholdMS: 15,
|
||||
@@ -54,6 +61,7 @@ module.exports = {
|
||||
TOPOLOGY_DEFAULTS,
|
||||
TopologyType,
|
||||
ServerType,
|
||||
serverType,
|
||||
drainTimerQueue,
|
||||
clearAndRemoveTimerFrom
|
||||
};
|
||||
|
||||
352
node_modules/mongodb/lib/core/sdam/monitor.js
generated
vendored
352
node_modules/mongodb/lib/core/sdam/monitor.js
generated
vendored
@@ -6,7 +6,8 @@ const connect = require('../connection/connect');
|
||||
const Connection = require('../../cmap/connection').Connection;
|
||||
const common = require('./common');
|
||||
const makeStateMachine = require('../utils').makeStateMachine;
|
||||
const MongoError = require('../error').MongoError;
|
||||
const MongoNetworkError = require('../error').MongoNetworkError;
|
||||
const BSON = require('../connection/utils').retrieveBSON();
|
||||
const makeInterruptableAsyncInterval = require('../../utils').makeInterruptableAsyncInterval;
|
||||
const calculateDurationInMs = require('../../utils').calculateDurationInMs;
|
||||
const now = require('../../utils').now;
|
||||
@@ -20,13 +21,15 @@ const kServer = Symbol('server');
|
||||
const kMonitorId = Symbol('monitorId');
|
||||
const kConnection = Symbol('connection');
|
||||
const kCancellationToken = Symbol('cancellationToken');
|
||||
const kRTTPinger = Symbol('rttPinger');
|
||||
const kRoundTripTime = Symbol('roundTripTime');
|
||||
|
||||
const STATE_CLOSED = common.STATE_CLOSED;
|
||||
const STATE_CLOSING = common.STATE_CLOSING;
|
||||
const STATE_IDLE = 'idle';
|
||||
const STATE_MONITORING = 'monitoring';
|
||||
const stateTransition = makeStateMachine({
|
||||
[STATE_CLOSING]: [STATE_CLOSING, STATE_CLOSED],
|
||||
[STATE_CLOSING]: [STATE_CLOSING, STATE_IDLE, STATE_CLOSED],
|
||||
[STATE_CLOSED]: [STATE_CLOSED, STATE_MONITORING],
|
||||
[STATE_IDLE]: [STATE_IDLE, STATE_MONITORING, STATE_CLOSING],
|
||||
[STATE_MONITORING]: [STATE_MONITORING, STATE_IDLE, STATE_CLOSING]
|
||||
@@ -62,32 +65,39 @@ class Monitor extends EventEmitter {
|
||||
heartbeatFrequencyMS:
|
||||
typeof options.heartbeatFrequencyMS === 'number' ? options.heartbeatFrequencyMS : 10000,
|
||||
minHeartbeatFrequencyMS:
|
||||
typeof options.minHeartbeatFrequencyMS === 'number' ? options.minHeartbeatFrequencyMS : 500
|
||||
typeof options.minHeartbeatFrequencyMS === 'number' ? options.minHeartbeatFrequencyMS : 500,
|
||||
useUnifiedTopology: options.useUnifiedTopology
|
||||
});
|
||||
|
||||
// TODO: refactor this to pull it directly from the pool, requires new ConnectionPool integration
|
||||
const addressParts = server.description.address.split(':');
|
||||
this.connectOptions = Object.freeze(
|
||||
Object.assign(
|
||||
{
|
||||
id: '<monitor>',
|
||||
host: addressParts[0],
|
||||
port: parseInt(addressParts[1], 10),
|
||||
bson: server.s.bson,
|
||||
connectionType: Connection
|
||||
},
|
||||
server.s.options,
|
||||
this.options,
|
||||
const connectOptions = Object.assign(
|
||||
{
|
||||
id: '<monitor>',
|
||||
host: server.description.host,
|
||||
port: server.description.port,
|
||||
bson: server.s.bson,
|
||||
connectionType: Connection
|
||||
},
|
||||
server.s.options,
|
||||
this.options,
|
||||
|
||||
// force BSON serialization options
|
||||
{
|
||||
raw: false,
|
||||
promoteLongs: true,
|
||||
promoteValues: true,
|
||||
promoteBuffers: true
|
||||
}
|
||||
)
|
||||
// force BSON serialization options
|
||||
{
|
||||
raw: false,
|
||||
promoteLongs: true,
|
||||
promoteValues: true,
|
||||
promoteBuffers: true,
|
||||
bsonRegExp: true
|
||||
}
|
||||
);
|
||||
|
||||
// ensure no authentication is used for monitoring
|
||||
delete connectOptions.credentials;
|
||||
|
||||
// ensure encryption is not requested for monitoring
|
||||
delete connectOptions.autoEncrypter;
|
||||
|
||||
this.connectOptions = Object.freeze(connectOptions);
|
||||
}
|
||||
|
||||
connect() {
|
||||
@@ -113,88 +123,182 @@ class Monitor extends EventEmitter {
|
||||
this[kMonitorId].wake();
|
||||
}
|
||||
|
||||
reset() {
|
||||
const topologyVersion = this[kServer].description.topologyVersion;
|
||||
if (isInCloseState(this) || topologyVersion == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
stateTransition(this, STATE_CLOSING);
|
||||
resetMonitorState(this);
|
||||
|
||||
// restart monitor
|
||||
stateTransition(this, STATE_IDLE);
|
||||
|
||||
// restart monitoring
|
||||
const heartbeatFrequencyMS = this.options.heartbeatFrequencyMS;
|
||||
const minHeartbeatFrequencyMS = this.options.minHeartbeatFrequencyMS;
|
||||
this[kMonitorId] = makeInterruptableAsyncInterval(monitorServer(this), {
|
||||
interval: heartbeatFrequencyMS,
|
||||
minInterval: minHeartbeatFrequencyMS
|
||||
});
|
||||
}
|
||||
|
||||
close() {
|
||||
if (isInCloseState(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
stateTransition(this, STATE_CLOSING);
|
||||
this[kCancellationToken].emit('cancel');
|
||||
if (this[kMonitorId]) {
|
||||
this[kMonitorId].stop();
|
||||
this[kMonitorId] = null;
|
||||
}
|
||||
|
||||
if (this[kConnection]) {
|
||||
this[kConnection].destroy({ force: true });
|
||||
}
|
||||
resetMonitorState(this);
|
||||
|
||||
// close monitor
|
||||
this.emit('close');
|
||||
stateTransition(this, STATE_CLOSED);
|
||||
}
|
||||
}
|
||||
|
||||
function checkServer(monitor, callback) {
|
||||
if (monitor[kConnection] && monitor[kConnection].closed) {
|
||||
monitor[kConnection] = undefined;
|
||||
function resetMonitorState(monitor) {
|
||||
if (monitor[kMonitorId]) {
|
||||
monitor[kMonitorId].stop();
|
||||
monitor[kMonitorId] = null;
|
||||
}
|
||||
|
||||
const start = now();
|
||||
if (monitor[kRTTPinger]) {
|
||||
monitor[kRTTPinger].close();
|
||||
monitor[kRTTPinger] = undefined;
|
||||
}
|
||||
|
||||
monitor[kCancellationToken].emit('cancel');
|
||||
if (monitor[kMonitorId]) {
|
||||
clearTimeout(monitor[kMonitorId]);
|
||||
monitor[kMonitorId] = undefined;
|
||||
}
|
||||
|
||||
if (monitor[kConnection]) {
|
||||
monitor[kConnection].destroy({ force: true });
|
||||
}
|
||||
}
|
||||
|
||||
function checkServer(monitor, callback) {
|
||||
let start = now();
|
||||
monitor.emit('serverHeartbeatStarted', new ServerHeartbeatStartedEvent(monitor.address));
|
||||
|
||||
function failureHandler(err) {
|
||||
if (monitor[kConnection]) {
|
||||
monitor[kConnection].destroy({ force: true });
|
||||
monitor[kConnection] = undefined;
|
||||
}
|
||||
|
||||
monitor.emit(
|
||||
'serverHeartbeatFailed',
|
||||
new ServerHeartbeatFailedEvent(calculateDurationInMs(start), err, monitor.address)
|
||||
);
|
||||
|
||||
monitor.emit('resetServer', err);
|
||||
monitor.emit('resetConnectionPool');
|
||||
callback(err);
|
||||
}
|
||||
|
||||
function successHandler(isMaster) {
|
||||
monitor.emit(
|
||||
'serverHeartbeatSucceeded',
|
||||
new ServerHeartbeatSucceededEvent(calculateDurationInMs(start), isMaster, monitor.address)
|
||||
);
|
||||
|
||||
return callback(undefined, isMaster);
|
||||
}
|
||||
|
||||
if (monitor[kConnection] != null) {
|
||||
if (monitor[kConnection] != null && !monitor[kConnection].closed) {
|
||||
const connectTimeoutMS = monitor.options.connectTimeoutMS;
|
||||
monitor[kConnection].command(
|
||||
'admin.$cmd',
|
||||
{ ismaster: true },
|
||||
{ socketTimeout: connectTimeoutMS },
|
||||
(err, result) => {
|
||||
if (err) {
|
||||
failureHandler(err);
|
||||
return;
|
||||
const maxAwaitTimeMS = monitor.options.heartbeatFrequencyMS;
|
||||
const topologyVersion = monitor[kServer].description.topologyVersion;
|
||||
const isAwaitable = topologyVersion != null;
|
||||
const serverApi = monitor[kConnection].serverApi;
|
||||
const helloOk = monitor[kConnection].helloOk;
|
||||
|
||||
const cmd = {
|
||||
[serverApi || helloOk ? 'hello' : 'ismaster']: true
|
||||
};
|
||||
|
||||
// written this way omit helloOk from the command if its false-y (do not want -> helloOk: null)
|
||||
if (helloOk) cmd.helloOk = helloOk;
|
||||
|
||||
const options = { socketTimeout: connectTimeoutMS };
|
||||
|
||||
if (isAwaitable) {
|
||||
cmd.maxAwaitTimeMS = maxAwaitTimeMS;
|
||||
cmd.topologyVersion = makeTopologyVersion(topologyVersion);
|
||||
if (connectTimeoutMS) {
|
||||
options.socketTimeout = connectTimeoutMS + maxAwaitTimeMS;
|
||||
}
|
||||
options.exhaustAllowed = true;
|
||||
if (monitor[kRTTPinger] == null) {
|
||||
monitor[kRTTPinger] = new RTTPinger(monitor[kCancellationToken], monitor.connectOptions);
|
||||
}
|
||||
}
|
||||
|
||||
monitor[kConnection].command('admin.$cmd', cmd, options, (err, result) => {
|
||||
if (err) {
|
||||
failureHandler(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const isMaster = result.result;
|
||||
const rttPinger = monitor[kRTTPinger];
|
||||
|
||||
if ('isWritablePrimary' in isMaster) {
|
||||
// Provide pre-hello-style response document.
|
||||
isMaster.ismaster = isMaster.isWritablePrimary;
|
||||
}
|
||||
|
||||
const duration =
|
||||
isAwaitable && rttPinger ? rttPinger.roundTripTime : calculateDurationInMs(start);
|
||||
|
||||
monitor.emit(
|
||||
'serverHeartbeatSucceeded',
|
||||
new ServerHeartbeatSucceededEvent(duration, isMaster, monitor.address)
|
||||
);
|
||||
|
||||
// if we are using the streaming protocol then we immediately issue another `started`
|
||||
// event, otherwise the "check" is complete and return to the main monitor loop
|
||||
if (isAwaitable && isMaster.topologyVersion) {
|
||||
monitor.emit('serverHeartbeatStarted', new ServerHeartbeatStartedEvent(monitor.address));
|
||||
start = now();
|
||||
} else {
|
||||
if (monitor[kRTTPinger]) {
|
||||
monitor[kRTTPinger].close();
|
||||
monitor[kRTTPinger] = undefined;
|
||||
}
|
||||
|
||||
successHandler(result.result);
|
||||
callback(undefined, isMaster);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// connecting does an implicit `ismaster`
|
||||
connect(monitor.connectOptions, monitor[kCancellationToken], (err, conn) => {
|
||||
if (conn && isInCloseState(monitor)) {
|
||||
conn.destroy({ force: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
monitor[kConnection] = undefined;
|
||||
|
||||
// we already reset the connection pool on network errors in all cases
|
||||
if (!(err instanceof MongoNetworkError)) {
|
||||
monitor.emit('resetConnectionPool');
|
||||
}
|
||||
|
||||
failureHandler(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInCloseState(monitor)) {
|
||||
conn.destroy({ force: true });
|
||||
failureHandler(new MongoError('monitor was destroyed'));
|
||||
return;
|
||||
}
|
||||
|
||||
monitor[kConnection] = conn;
|
||||
successHandler(conn.ismaster);
|
||||
monitor.emit(
|
||||
'serverHeartbeatSucceeded',
|
||||
new ServerHeartbeatSucceededEvent(
|
||||
calculateDurationInMs(start),
|
||||
conn.ismaster,
|
||||
monitor.address
|
||||
)
|
||||
);
|
||||
|
||||
callback(undefined, conn.ismaster);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -212,33 +316,113 @@ function monitorServer(monitor) {
|
||||
// TODO: the next line is a legacy event, remove in v4
|
||||
process.nextTick(() => monitor.emit('monitoring', monitor[kServer]));
|
||||
|
||||
checkServer(monitor, e0 => {
|
||||
if (e0 == null) {
|
||||
return done();
|
||||
}
|
||||
|
||||
// otherwise an error occured on initial discovery, also bail
|
||||
if (monitor[kServer].description.type === ServerType.Unknown) {
|
||||
monitor.emit('resetServer', e0);
|
||||
return done();
|
||||
}
|
||||
|
||||
// According to the SDAM specification's "Network error during server check" section, if
|
||||
// an ismaster call fails we reset the server's pool. If a server was once connected,
|
||||
// change its type to `Unknown` only after retrying once.
|
||||
monitor.emit('resetConnectionPool');
|
||||
|
||||
checkServer(monitor, e1 => {
|
||||
if (e1) {
|
||||
monitor.emit('resetServer', e1);
|
||||
checkServer(monitor, (err, isMaster) => {
|
||||
if (err) {
|
||||
// otherwise an error occured on initial discovery, also bail
|
||||
if (monitor[kServer].description.type === ServerType.Unknown) {
|
||||
monitor.emit('resetServer', err);
|
||||
return done();
|
||||
}
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
// if the check indicates streaming is supported, immediately reschedule monitoring
|
||||
if (isMaster && isMaster.topologyVersion) {
|
||||
setTimeout(() => {
|
||||
if (!isInCloseState(monitor)) {
|
||||
monitor[kMonitorId].wake();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function makeTopologyVersion(tv) {
|
||||
return {
|
||||
processId: tv.processId,
|
||||
counter: BSON.Long.fromNumber(tv.counter)
|
||||
};
|
||||
}
|
||||
|
||||
class RTTPinger {
|
||||
constructor(cancellationToken, options) {
|
||||
this[kConnection] = null;
|
||||
this[kCancellationToken] = cancellationToken;
|
||||
this[kRoundTripTime] = 0;
|
||||
this.closed = false;
|
||||
|
||||
const heartbeatFrequencyMS = options.heartbeatFrequencyMS;
|
||||
this[kMonitorId] = setTimeout(() => measureRoundTripTime(this, options), heartbeatFrequencyMS);
|
||||
}
|
||||
|
||||
get roundTripTime() {
|
||||
return this[kRoundTripTime];
|
||||
}
|
||||
|
||||
close() {
|
||||
this.closed = true;
|
||||
|
||||
clearTimeout(this[kMonitorId]);
|
||||
this[kMonitorId] = undefined;
|
||||
|
||||
if (this[kConnection]) {
|
||||
this[kConnection].destroy({ force: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function measureRoundTripTime(rttPinger, options) {
|
||||
const start = now();
|
||||
const cancellationToken = rttPinger[kCancellationToken];
|
||||
const heartbeatFrequencyMS = options.heartbeatFrequencyMS;
|
||||
if (rttPinger.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
function measureAndReschedule(conn) {
|
||||
if (rttPinger.closed) {
|
||||
conn.destroy({ force: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (rttPinger[kConnection] == null) {
|
||||
rttPinger[kConnection] = conn;
|
||||
}
|
||||
|
||||
rttPinger[kRoundTripTime] = calculateDurationInMs(start);
|
||||
rttPinger[kMonitorId] = setTimeout(
|
||||
() => measureRoundTripTime(rttPinger, options),
|
||||
heartbeatFrequencyMS
|
||||
);
|
||||
}
|
||||
|
||||
if (rttPinger[kConnection] == null) {
|
||||
connect(options, cancellationToken, (err, conn) => {
|
||||
if (err) {
|
||||
rttPinger[kConnection] = undefined;
|
||||
rttPinger[kRoundTripTime] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
measureAndReschedule(conn);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
rttPinger[kConnection].command('admin.$cmd', { ismaster: 1 }, err => {
|
||||
if (err) {
|
||||
rttPinger[kConnection] = undefined;
|
||||
rttPinger[kRoundTripTime] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
measureAndReschedule();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Monitor
|
||||
};
|
||||
|
||||
110
node_modules/mongodb/lib/core/sdam/server.js
generated
vendored
110
node_modules/mongodb/lib/core/sdam/server.js
generated
vendored
@@ -7,17 +7,23 @@ const relayEvents = require('../utils').relayEvents;
|
||||
const BSON = require('../connection/utils').retrieveBSON();
|
||||
const Logger = require('../connection/logger');
|
||||
const ServerDescription = require('./server_description').ServerDescription;
|
||||
const compareTopologyVersion = require('./server_description').compareTopologyVersion;
|
||||
const ReadPreference = require('../topologies/read_preference');
|
||||
const Monitor = require('./monitor').Monitor;
|
||||
const MongoNetworkError = require('../error').MongoNetworkError;
|
||||
const MongoNetworkTimeoutError = require('../error').MongoNetworkTimeoutError;
|
||||
const collationNotSupported = require('../utils').collationNotSupported;
|
||||
const debugOptions = require('../connection/utils').debugOptions;
|
||||
const isSDAMUnrecoverableError = require('../error').isSDAMUnrecoverableError;
|
||||
const isNetworkTimeoutError = require('../error').isNetworkTimeoutError;
|
||||
const isRetryableWriteError = require('../error').isRetryableWriteError;
|
||||
const isNodeShuttingDownError = require('../error').isNodeShuttingDownError;
|
||||
const isNetworkErrorBeforeHandshake = require('../error').isNetworkErrorBeforeHandshake;
|
||||
const maxWireVersion = require('../utils').maxWireVersion;
|
||||
const makeStateMachine = require('../utils').makeStateMachine;
|
||||
const extractCommand = require('../../command_utils').extractCommand;
|
||||
const common = require('./common');
|
||||
const ServerType = common.ServerType;
|
||||
const isTransactionCommand = require('../transactions').isTransactionCommand;
|
||||
|
||||
// Used for filtering out fields for logging
|
||||
const DEBUG_FIELDS = [
|
||||
@@ -44,6 +50,7 @@ const DEBUG_FIELDS = [
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'bsonRegExp',
|
||||
'servername'
|
||||
];
|
||||
|
||||
@@ -107,12 +114,12 @@ class Server extends EventEmitter {
|
||||
credentials: options.credentials,
|
||||
topology
|
||||
};
|
||||
this.serverApi = options.serverApi;
|
||||
|
||||
// create the connection pool
|
||||
// NOTE: this used to happen in `connect`, we supported overriding pool options there
|
||||
const addressParts = this.description.address.split(':');
|
||||
const poolOptions = Object.assign(
|
||||
{ host: addressParts[0], port: parseInt(addressParts[1], 10), bson: this.s.bson },
|
||||
{ host: this.description.host, port: this.description.port, bson: this.s.bson },
|
||||
options
|
||||
);
|
||||
|
||||
@@ -162,6 +169,10 @@ class Server extends EventEmitter {
|
||||
return this.s.description;
|
||||
}
|
||||
|
||||
get supportsRetryableWrites() {
|
||||
return supportsRetryableWrites(this);
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.s.description.address;
|
||||
}
|
||||
@@ -241,6 +252,7 @@ class Server extends EventEmitter {
|
||||
if (typeof options === 'function') {
|
||||
(callback = options), (options = {}), (options = options || {});
|
||||
}
|
||||
options.serverApi = this.serverApi;
|
||||
|
||||
if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
|
||||
callback(new MongoError('server is closed'));
|
||||
@@ -257,10 +269,11 @@ class Server extends EventEmitter {
|
||||
|
||||
// Debug log
|
||||
if (this.s.logger.isDebug()) {
|
||||
const extractedCommand = extractCommand(cmd);
|
||||
this.s.logger.debug(
|
||||
`executing command [${JSON.stringify({
|
||||
ns,
|
||||
cmd,
|
||||
cmd: extractedCommand.shouldRedact ? `${extractedCommand.name} details REDACTED` : cmd,
|
||||
options: debugOptions(DEBUG_FIELDS, options)
|
||||
})}] against ${this.name}`
|
||||
);
|
||||
@@ -278,7 +291,7 @@ class Server extends EventEmitter {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
conn.command(ns, cmd, options, makeOperationHandler(this, options, cb));
|
||||
conn.command(ns, cmd, options, makeOperationHandler(this, conn, cmd, options, cb));
|
||||
}, callback);
|
||||
}
|
||||
|
||||
@@ -302,7 +315,7 @@ class Server extends EventEmitter {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
conn.query(ns, cmd, cursorState, options, makeOperationHandler(this, options, cb));
|
||||
conn.query(ns, cmd, cursorState, options, makeOperationHandler(this, conn, cmd, options, cb));
|
||||
}, callback);
|
||||
}
|
||||
|
||||
@@ -326,7 +339,13 @@ class Server extends EventEmitter {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
conn.getMore(ns, cursorState, batchSize, options, makeOperationHandler(this, options, cb));
|
||||
conn.getMore(
|
||||
ns,
|
||||
cursorState,
|
||||
batchSize,
|
||||
options,
|
||||
makeOperationHandler(this, conn, null, options, cb)
|
||||
);
|
||||
}, callback);
|
||||
}
|
||||
|
||||
@@ -352,7 +371,7 @@ class Server extends EventEmitter {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
conn.killCursors(ns, cursorState, makeOperationHandler(this, null, cb));
|
||||
conn.killCursors(ns, cursorState, makeOperationHandler(this, conn, null, undefined, cb));
|
||||
}, callback);
|
||||
}
|
||||
|
||||
@@ -414,6 +433,14 @@ Object.defineProperty(Server.prototype, 'clusterTime', {
|
||||
}
|
||||
});
|
||||
|
||||
function supportsRetryableWrites(server) {
|
||||
return (
|
||||
server.description.maxWireVersion >= 6 &&
|
||||
server.description.logicalSessionTimeoutMinutes &&
|
||||
server.description.type !== ServerType.Standalone
|
||||
);
|
||||
}
|
||||
|
||||
function calculateRoundTripTime(oldRtt, duration) {
|
||||
if (oldRtt === -1) {
|
||||
return duration;
|
||||
@@ -448,6 +475,13 @@ function executeWriteOperation(args, options, callback) {
|
||||
callback(new MongoError(`server ${server.name} does not support collation`));
|
||||
return;
|
||||
}
|
||||
const unacknowledgedWrite = options.writeConcern && options.writeConcern.w === 0;
|
||||
if (unacknowledgedWrite || maxWireVersion(server) < 5) {
|
||||
if ((op === 'update' || op === 'remove') && ops.find(o => o.hint)) {
|
||||
callback(new MongoError(`servers < 3.4 do not support hint on ${op}`));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
server.s.pool.withConnection((err, conn, cb) => {
|
||||
if (err) {
|
||||
@@ -455,38 +489,78 @@ function executeWriteOperation(args, options, callback) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
conn[op](ns, ops, options, makeOperationHandler(server, options, cb));
|
||||
conn[op](ns, ops, options, makeOperationHandler(server, conn, ops, options, cb));
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function markServerUnknown(server, error) {
|
||||
if (error instanceof MongoNetworkError && !(error instanceof MongoNetworkTimeoutError)) {
|
||||
server[kMonitor].reset();
|
||||
}
|
||||
|
||||
server.emit(
|
||||
'descriptionReceived',
|
||||
new ServerDescription(server.description.address, null, { error })
|
||||
new ServerDescription(server.description.address, null, {
|
||||
error,
|
||||
topologyVersion:
|
||||
error && error.topologyVersion ? error.topologyVersion : server.description.topologyVersion
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function makeOperationHandler(server, options, callback) {
|
||||
function connectionIsStale(pool, connection) {
|
||||
return connection.generation !== pool.generation;
|
||||
}
|
||||
|
||||
function shouldHandleStateChangeError(server, err) {
|
||||
const etv = err.topologyVersion;
|
||||
const stv = server.description.topologyVersion;
|
||||
|
||||
return compareTopologyVersion(stv, etv) < 0;
|
||||
}
|
||||
|
||||
function inActiveTransaction(session, cmd) {
|
||||
return session && session.inTransaction() && !isTransactionCommand(cmd);
|
||||
}
|
||||
|
||||
function makeOperationHandler(server, connection, cmd, options, callback) {
|
||||
const session = options && options.session;
|
||||
|
||||
return function handleOperationResult(err, result) {
|
||||
if (err) {
|
||||
if (err && !connectionIsStale(server.s.pool, connection)) {
|
||||
if (err instanceof MongoNetworkError) {
|
||||
if (session && !session.hasEnded) {
|
||||
session.serverSession.isDirty = true;
|
||||
}
|
||||
|
||||
if (!isNetworkTimeoutError(err)) {
|
||||
if (supportsRetryableWrites(server) && !inActiveTransaction(session, cmd)) {
|
||||
err.addErrorLabel('RetryableWriteError');
|
||||
}
|
||||
|
||||
if (!(err instanceof MongoNetworkTimeoutError) || isNetworkErrorBeforeHandshake(err)) {
|
||||
markServerUnknown(server, err);
|
||||
server.s.pool.clear();
|
||||
}
|
||||
} else if (isSDAMUnrecoverableError(err)) {
|
||||
if (maxWireVersion(server) <= 7 || isNodeShuttingDownError(err)) {
|
||||
server.s.pool.clear();
|
||||
} else {
|
||||
// if pre-4.4 server, then add error label if its a retryable write error
|
||||
if (
|
||||
maxWireVersion(server) < 9 &&
|
||||
isRetryableWriteError(err) &&
|
||||
!inActiveTransaction(session, cmd)
|
||||
) {
|
||||
err.addErrorLabel('RetryableWriteError');
|
||||
}
|
||||
|
||||
markServerUnknown(server, err);
|
||||
process.nextTick(() => server.requestCheck());
|
||||
if (isSDAMUnrecoverableError(err)) {
|
||||
if (shouldHandleStateChangeError(server, err)) {
|
||||
if (maxWireVersion(server) <= 7 || isNodeShuttingDownError(err)) {
|
||||
server.s.pool.clear();
|
||||
}
|
||||
|
||||
markServerUnknown(server, err);
|
||||
process.nextTick(() => server.requestCheck());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
53
node_modules/mongodb/lib/core/sdam/server_description.js
generated
vendored
53
node_modules/mongodb/lib/core/sdam/server_description.js
generated
vendored
@@ -53,6 +53,8 @@ class ServerDescription {
|
||||
* @param {Object} [ismaster] An optional ismaster response for this server
|
||||
* @param {Object} [options] Optional settings
|
||||
* @param {Number} [options.roundTripTime] The round trip time to ping this server (in ms)
|
||||
* @param {Error} [options.error] An Error used for better reporting debugging
|
||||
* @param {any} [options.topologyVersion] The topologyVersion
|
||||
*/
|
||||
constructor(address, ismaster, options) {
|
||||
options = options || {};
|
||||
@@ -68,6 +70,10 @@ class ServerDescription {
|
||||
ismaster
|
||||
);
|
||||
|
||||
if (ismaster.isWritablePrimary != null) {
|
||||
ismaster.ismaster = ismaster.isWritablePrimary;
|
||||
}
|
||||
|
||||
this.address = address;
|
||||
this.error = options.error;
|
||||
this.roundTripTime = options.roundTripTime || -1;
|
||||
@@ -75,6 +81,7 @@ class ServerDescription {
|
||||
this.lastWriteDate = ismaster.lastWrite ? ismaster.lastWrite.lastWriteDate : null;
|
||||
this.opTime = ismaster.lastWrite ? ismaster.lastWrite.opTime : null;
|
||||
this.type = parseServerType(ismaster);
|
||||
this.topologyVersion = options.topologyVersion || ismaster.topologyVersion;
|
||||
|
||||
// direct mappings
|
||||
ISMASTER_FIELDS.forEach(field => {
|
||||
@@ -113,6 +120,16 @@ class ServerDescription {
|
||||
return WRITABLE_SERVER_TYPES.has(this.type);
|
||||
}
|
||||
|
||||
get host() {
|
||||
const chopLength = `:${this.port}`.length;
|
||||
return this.address.slice(0, -chopLength);
|
||||
}
|
||||
|
||||
get port() {
|
||||
const port = this.address.split(':').pop();
|
||||
return port ? Number.parseInt(port, 10) : port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if another `ServerDescription` is equal to this one per the rules defined
|
||||
* in the {@link https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#serverdescription|SDAM spec}
|
||||
@@ -121,6 +138,10 @@ class ServerDescription {
|
||||
* @return {Boolean}
|
||||
*/
|
||||
equals(other) {
|
||||
const topologyVersionsEqual =
|
||||
this.topologyVersion === other.topologyVersion ||
|
||||
compareTopologyVersion(this.topologyVersion, other.topologyVersion) === 0;
|
||||
|
||||
return (
|
||||
other != null &&
|
||||
errorStrictEqual(this.error, other.error) &&
|
||||
@@ -135,7 +156,8 @@ class ServerDescription {
|
||||
? other.electionId && this.electionId.equals(other.electionId)
|
||||
: this.electionId === other.electionId) &&
|
||||
this.primary === other.primary &&
|
||||
this.logicalSessionTimeoutMinutes === other.logicalSessionTimeoutMinutes
|
||||
this.logicalSessionTimeoutMinutes === other.logicalSessionTimeoutMinutes &&
|
||||
topologyVersionsEqual
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -176,7 +198,34 @@ function parseServerType(ismaster) {
|
||||
return ServerType.Standalone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two topology versions.
|
||||
*
|
||||
* @param {object} lhs
|
||||
* @param {object} rhs
|
||||
* @returns A negative number if `lhs` is older than `rhs`; positive if `lhs` is newer than `rhs`; 0 if they are equivalent.
|
||||
*/
|
||||
function compareTopologyVersion(lhs, rhs) {
|
||||
if (lhs == null || rhs == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lhs.processId.equals(rhs.processId)) {
|
||||
// TODO: handle counters as Longs
|
||||
if (lhs.counter === rhs.counter) {
|
||||
return 0;
|
||||
} else if (lhs.counter < rhs.counter) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ServerDescription,
|
||||
parseServerType
|
||||
parseServerType,
|
||||
compareTopologyVersion
|
||||
};
|
||||
|
||||
126
node_modules/mongodb/lib/core/sdam/topology.js
generated
vendored
126
node_modules/mongodb/lib/core/sdam/topology.js
generated
vendored
@@ -9,12 +9,10 @@ const events = require('./events');
|
||||
const Server = require('./server').Server;
|
||||
const relayEvents = require('../utils').relayEvents;
|
||||
const ReadPreference = require('../topologies/read_preference');
|
||||
const isRetryableWritesSupported = require('../topologies/shared').isRetryableWritesSupported;
|
||||
const CoreCursor = require('../cursor').CoreCursor;
|
||||
const deprecate = require('util').deprecate;
|
||||
const BSON = require('../connection/utils').retrieveBSON();
|
||||
const createCompressionInfo = require('../topologies/shared').createCompressionInfo;
|
||||
const isRetryableError = require('../error').isRetryableError;
|
||||
const ClientSession = require('../sessions').ClientSession;
|
||||
const MongoError = require('../error').MongoError;
|
||||
const MongoServerSelectionError = require('../error').MongoServerSelectionError;
|
||||
@@ -27,6 +25,8 @@ const emitDeprecationWarning = require('../../utils').emitDeprecationWarning;
|
||||
const ServerSessionPool = require('../sessions').ServerSessionPool;
|
||||
const makeClientMetadata = require('../utils').makeClientMetadata;
|
||||
const CMAP_EVENT_NAMES = require('../../cmap/events').CMAP_EVENT_NAMES;
|
||||
const compareTopologyVersion = require('./server_description').compareTopologyVersion;
|
||||
const emitWarning = require('../../utils').emitWarning;
|
||||
|
||||
const common = require('./common');
|
||||
const drainTimerQueue = common.drainTimerQueue;
|
||||
@@ -200,6 +200,7 @@ class Topology extends EventEmitter {
|
||||
// timer management
|
||||
connectionTimers: new Set()
|
||||
};
|
||||
this.serverApi = options.serverApi;
|
||||
|
||||
if (options.srvHost) {
|
||||
this.s.srvPoller =
|
||||
@@ -275,9 +276,9 @@ class Topology extends EventEmitter {
|
||||
// connect all known servers, then attempt server selection to connect
|
||||
connectServers(this, Array.from(this.s.description.servers.values()));
|
||||
|
||||
translateReadPreference(options);
|
||||
ReadPreference.translate(options);
|
||||
const readPreference = options.readPreference || ReadPreference.primary;
|
||||
this.selectServer(readPreferenceServerSelector(readPreference), options, err => {
|
||||
const connectHandler = err => {
|
||||
if (err) {
|
||||
this.close();
|
||||
|
||||
@@ -295,7 +296,15 @@ class Topology extends EventEmitter {
|
||||
this.emit('connect', this);
|
||||
|
||||
if (typeof callback === 'function') callback(err, this);
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: NODE-2471
|
||||
if (this.s.credentials) {
|
||||
this.command('admin.$cmd', { ping: 1 }, { readPreference }, connectHandler);
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectServer(readPreferenceServerSelector(readPreference), options, connectHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -350,7 +359,6 @@ class Topology extends EventEmitter {
|
||||
this.emit('topologyClosed', new events.TopologyClosedEvent(this.s.id));
|
||||
|
||||
stateTransition(this, STATE_CLOSED);
|
||||
this.emit('close');
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback(err);
|
||||
@@ -381,7 +389,7 @@ class Topology extends EventEmitter {
|
||||
} else if (typeof selector === 'string') {
|
||||
readPreference = new ReadPreference(selector);
|
||||
} else {
|
||||
translateReadPreference(options);
|
||||
ReadPreference.translate(options);
|
||||
readPreference = options.readPreference || ReadPreference.primary;
|
||||
}
|
||||
|
||||
@@ -487,7 +495,11 @@ class Topology extends EventEmitter {
|
||||
this.command(
|
||||
'admin.$cmd',
|
||||
{ endSessions: sessions },
|
||||
{ readPreference: ReadPreference.primaryPreferred, noResponse: true },
|
||||
{
|
||||
readPreference: ReadPreference.primaryPreferred,
|
||||
noResponse: true,
|
||||
serverApi: this.serverApi
|
||||
},
|
||||
() => {
|
||||
// intentionally ignored, per spec
|
||||
if (typeof callback === 'function') callback();
|
||||
@@ -505,6 +517,11 @@ class Topology extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore this server update if its from an outdated topologyVersion
|
||||
if (isStaleServerDescription(this.s.description, serverDescription)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// these will be used for monitoring events later
|
||||
const previousTopologyDescription = this.s.description;
|
||||
const previousServerDescription = this.s.description.servers.get(serverDescription.address);
|
||||
@@ -647,7 +664,7 @@ class Topology extends EventEmitter {
|
||||
(callback = options), (options = {}), (options = options || {});
|
||||
}
|
||||
|
||||
translateReadPreference(options);
|
||||
ReadPreference.translate(options);
|
||||
const readPreference = options.readPreference || ReadPreference.primary;
|
||||
|
||||
this.selectServer(readPreferenceServerSelector(readPreference), options, (err, server) => {
|
||||
@@ -656,17 +673,22 @@ class Topology extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
const notAlreadyRetrying = !options.retrying;
|
||||
const retryWrites = !!options.retryWrites;
|
||||
const hasSession = !!options.session;
|
||||
const supportsRetryableWrites = server.supportsRetryableWrites;
|
||||
const notInTransaction = !hasSession || !options.session.inTransaction();
|
||||
const willRetryWrite =
|
||||
!options.retrying &&
|
||||
!!options.retryWrites &&
|
||||
options.session &&
|
||||
isRetryableWritesSupported(this) &&
|
||||
!options.session.inTransaction() &&
|
||||
notAlreadyRetrying &&
|
||||
retryWrites &&
|
||||
hasSession &&
|
||||
supportsRetryableWrites &&
|
||||
notInTransaction &&
|
||||
isWriteCommand(cmd);
|
||||
|
||||
const cb = (err, result) => {
|
||||
if (!err) return callback(null, result);
|
||||
if (!isRetryableError(err)) {
|
||||
if (!shouldRetryOperation(err)) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
@@ -708,7 +730,7 @@ class Topology extends EventEmitter {
|
||||
options = options || {};
|
||||
const topology = options.topology || this;
|
||||
const CursorClass = options.cursorFactory || this.s.Cursor;
|
||||
translateReadPreference(options);
|
||||
ReadPreference.translate(options);
|
||||
|
||||
return new CursorClass(topology, ns, cmd, options);
|
||||
}
|
||||
@@ -725,8 +747,11 @@ class Topology extends EventEmitter {
|
||||
return this.s.state === STATE_CLOSED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This function is deprecated and will be removed in the next major version.
|
||||
*/
|
||||
unref() {
|
||||
console.log('not implemented: `unref`');
|
||||
emitWarning('`unref` is a noop and will be removed in the next major version');
|
||||
}
|
||||
|
||||
// NOTE: There are many places in code where we explicitly check the last isMaster
|
||||
@@ -771,6 +796,16 @@ function isWriteCommand(command) {
|
||||
return RETRYABLE_WRITE_OPERATIONS.some(op => command[op]);
|
||||
}
|
||||
|
||||
function isStaleServerDescription(topologyDescription, incomingServerDescription) {
|
||||
const currentServerDescription = topologyDescription.servers.get(
|
||||
incomingServerDescription.address
|
||||
);
|
||||
const currentTopologyVersion = currentServerDescription.topologyVersion;
|
||||
return (
|
||||
compareTopologyVersion(currentTopologyVersion, incomingServerDescription.topologyVersion) > 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys a server, and removes all event listeners from the instance
|
||||
*
|
||||
@@ -806,10 +841,16 @@ function parseStringSeedlist(seedlist) {
|
||||
}
|
||||
|
||||
function topologyTypeFromSeedlist(seedlist, options) {
|
||||
if (options.directConnection) {
|
||||
return TopologyType.Single;
|
||||
}
|
||||
|
||||
const replicaSet = options.replicaSet || options.setName || options.rs_name;
|
||||
if (seedlist.length === 1 && !replicaSet) return TopologyType.Single;
|
||||
if (replicaSet) return TopologyType.ReplicaSetNoPrimary;
|
||||
return TopologyType.Unknown;
|
||||
if (replicaSet == null) {
|
||||
return TopologyType.Unknown;
|
||||
}
|
||||
|
||||
return TopologyType.ReplicaSetNoPrimary;
|
||||
}
|
||||
|
||||
function randomSelection(array) {
|
||||
@@ -896,22 +937,29 @@ function executeWriteOperation(args, options, callback) {
|
||||
const ns = args.ns;
|
||||
const ops = args.ops;
|
||||
|
||||
const willRetryWrite =
|
||||
!args.retrying &&
|
||||
!!options.retryWrites &&
|
||||
options.session &&
|
||||
isRetryableWritesSupported(topology) &&
|
||||
!options.session.inTransaction();
|
||||
|
||||
topology.selectServer(writableServerSelector(), options, (err, server) => {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
|
||||
const notAlreadyRetrying = !args.retrying;
|
||||
const retryWrites = !!options.retryWrites;
|
||||
const hasSession = !!options.session;
|
||||
const supportsRetryableWrites = server.supportsRetryableWrites;
|
||||
const notInTransaction = !hasSession || !options.session.inTransaction();
|
||||
const notExplaining = options.explain === undefined;
|
||||
const willRetryWrite =
|
||||
notAlreadyRetrying &&
|
||||
retryWrites &&
|
||||
hasSession &&
|
||||
supportsRetryableWrites &&
|
||||
notInTransaction &&
|
||||
notExplaining;
|
||||
|
||||
const handler = (err, result) => {
|
||||
if (!err) return callback(null, result);
|
||||
if (!isRetryableError(err)) {
|
||||
if (!shouldRetryOperation(err)) {
|
||||
err = getMMAPError(err);
|
||||
return callback(err);
|
||||
}
|
||||
@@ -939,26 +987,8 @@ function executeWriteOperation(args, options, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
function translateReadPreference(options) {
|
||||
if (options.readPreference == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let r = options.readPreference;
|
||||
if (typeof r === 'string') {
|
||||
options.readPreference = new ReadPreference(r);
|
||||
} else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
|
||||
const mode = r.mode || r.preference;
|
||||
if (mode && typeof mode === 'string') {
|
||||
options.readPreference = new ReadPreference(mode, r.tags, {
|
||||
maxStalenessSeconds: r.maxStalenessSeconds
|
||||
});
|
||||
}
|
||||
} else if (!(r instanceof ReadPreference)) {
|
||||
throw new TypeError('Invalid read preference: ' + r);
|
||||
}
|
||||
|
||||
return options;
|
||||
function shouldRetryOperation(err) {
|
||||
return err instanceof MongoError && err.hasErrorLabel('RetryableWriteError');
|
||||
}
|
||||
|
||||
function srvPollingHandler(topology) {
|
||||
|
||||
55
node_modules/mongodb/lib/core/sdam/topology_description.js
generated
vendored
55
node_modules/mongodb/lib/core/sdam/topology_description.js
generated
vendored
@@ -72,12 +72,30 @@ class TopologyDescription {
|
||||
// value among ServerDescriptions of all data-bearing server types. If any have a null
|
||||
// logicalSessionTimeoutMinutes, then TopologyDescription.logicalSessionTimeoutMinutes MUST be
|
||||
// set to null.
|
||||
const readableServers = Array.from(this.servers.values()).filter(s => s.isReadable);
|
||||
this.logicalSessionTimeoutMinutes = readableServers.reduce((result, server) => {
|
||||
if (server.logicalSessionTimeoutMinutes == null) return null;
|
||||
if (result == null) return server.logicalSessionTimeoutMinutes;
|
||||
return Math.min(result, server.logicalSessionTimeoutMinutes);
|
||||
}, null);
|
||||
this.logicalSessionTimeoutMinutes = null;
|
||||
for (const addressServerTuple of this.servers) {
|
||||
const server = addressServerTuple[1];
|
||||
if (server.isReadable) {
|
||||
if (server.logicalSessionTimeoutMinutes == null) {
|
||||
// If any of the servers have a null logicalSessionsTimeout, then the whole topology does
|
||||
this.logicalSessionTimeoutMinutes = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.logicalSessionTimeoutMinutes == null) {
|
||||
// First server with a non null logicalSessionsTimeout
|
||||
this.logicalSessionTimeoutMinutes = server.logicalSessionTimeoutMinutes;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Always select the smaller of the:
|
||||
// current server logicalSessionsTimeout and the topologies logicalSessionsTimeout
|
||||
this.logicalSessionTimeoutMinutes = Math.min(
|
||||
this.logicalSessionTimeoutMinutes,
|
||||
server.logicalSessionTimeoutMinutes
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,6 +150,10 @@ class TopologyDescription {
|
||||
let maxElectionId = this.maxElectionId;
|
||||
let commonWireVersion = this.commonWireVersion;
|
||||
|
||||
if (serverDescription.setName && setName && serverDescription.setName !== setName) {
|
||||
serverDescription = new ServerDescription(address, null);
|
||||
}
|
||||
|
||||
const serverType = serverDescription.type;
|
||||
let serverDescriptions = new Map(this.servers);
|
||||
|
||||
@@ -161,7 +183,7 @@ class TopologyDescription {
|
||||
}
|
||||
|
||||
if (topologyType === TopologyType.Unknown) {
|
||||
if (serverType === ServerType.Standalone) {
|
||||
if (serverType === ServerType.Standalone && this.servers.size !== 1) {
|
||||
serverDescriptions.delete(address);
|
||||
} else {
|
||||
topologyType = topologyTypeForServerType(serverType);
|
||||
@@ -246,6 +268,7 @@ class TopologyDescription {
|
||||
if (descriptionsWithError.length > 0) {
|
||||
return descriptionsWithError[0].error;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,8 +297,22 @@ class TopologyDescription {
|
||||
}
|
||||
|
||||
function topologyTypeForServerType(serverType) {
|
||||
if (serverType === ServerType.Mongos) return TopologyType.Sharded;
|
||||
if (serverType === ServerType.RSPrimary) return TopologyType.ReplicaSetWithPrimary;
|
||||
if (serverType === ServerType.Standalone) {
|
||||
return TopologyType.Single;
|
||||
}
|
||||
|
||||
if (serverType === ServerType.Mongos) {
|
||||
return TopologyType.Sharded;
|
||||
}
|
||||
|
||||
if (serverType === ServerType.RSPrimary) {
|
||||
return TopologyType.ReplicaSetWithPrimary;
|
||||
}
|
||||
|
||||
if (serverType === ServerType.RSGhost || serverType === ServerType.Unknown) {
|
||||
return TopologyType.Unknown;
|
||||
}
|
||||
|
||||
return TopologyType.ReplicaSetNoPrimary;
|
||||
}
|
||||
|
||||
|
||||
111
node_modules/mongodb/lib/core/sessions.js
generated
vendored
111
node_modules/mongodb/lib/core/sessions.js
generated
vendored
@@ -13,6 +13,7 @@ const Transaction = require('./transactions').Transaction;
|
||||
const TxnState = require('./transactions').TxnState;
|
||||
const isPromiseLike = require('./utils').isPromiseLike;
|
||||
const ReadPreference = require('./topologies/read_preference');
|
||||
const maybePromise = require('../utils').maybePromise;
|
||||
const isTransactionCommand = require('./transactions').isTransactionCommand;
|
||||
const resolveClusterTime = require('./topologies/shared').resolveClusterTime;
|
||||
const isSharded = require('./wireprotocol/shared').isSharded;
|
||||
@@ -125,25 +126,36 @@ class ClientSession extends EventEmitter {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
if (this.hasEnded) {
|
||||
if (typeof callback === 'function') callback(null, null);
|
||||
return;
|
||||
}
|
||||
const session = this;
|
||||
return maybePromise(this, callback, done => {
|
||||
if (session.hasEnded) {
|
||||
return done();
|
||||
}
|
||||
|
||||
if (this.serverSession && this.inTransaction()) {
|
||||
this.abortTransaction(); // pass in callback?
|
||||
}
|
||||
function completeEndSession() {
|
||||
// release the server session back to the pool
|
||||
session.sessionPool.release(session.serverSession);
|
||||
session[kServerSession] = undefined;
|
||||
|
||||
// release the server session back to the pool
|
||||
this.sessionPool.release(this.serverSession);
|
||||
this[kServerSession] = undefined;
|
||||
// mark the session as ended, and emit a signal
|
||||
session.hasEnded = true;
|
||||
session.emit('ended', session);
|
||||
|
||||
// mark the session as ended, and emit a signal
|
||||
this.hasEnded = true;
|
||||
this.emit('ended', this);
|
||||
// spec indicates that we should ignore all errors for `endSessions`
|
||||
done();
|
||||
}
|
||||
|
||||
// spec indicates that we should ignore all errors for `endSessions`
|
||||
if (typeof callback === 'function') callback(null, null);
|
||||
if (session.serverSession && session.inTransaction()) {
|
||||
session.abortTransaction(err => {
|
||||
if (err) return done(err);
|
||||
completeEndSession();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
completeEndSession();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,16 +239,7 @@ class ClientSession extends EventEmitter {
|
||||
* @return {Promise} A promise is returned if no callback is provided
|
||||
*/
|
||||
commitTransaction(callback) {
|
||||
if (typeof callback === 'function') {
|
||||
endTransaction(this, 'commitTransaction', callback);
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
endTransaction(this, 'commitTransaction', (err, reply) =>
|
||||
err ? reject(err) : resolve(reply)
|
||||
);
|
||||
});
|
||||
return maybePromise(this, callback, done => endTransaction(this, 'commitTransaction', done));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,16 +249,7 @@ class ClientSession extends EventEmitter {
|
||||
* @return {Promise} A promise is returned if no callback is provided
|
||||
*/
|
||||
abortTransaction(callback) {
|
||||
if (typeof callback === 'function') {
|
||||
endTransaction(this, 'abortTransaction', callback);
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
endTransaction(this, 'abortTransaction', (err, reply) =>
|
||||
err ? reject(err) : resolve(reply)
|
||||
);
|
||||
});
|
||||
return maybePromise(this, callback, done => endTransaction(this, 'abortTransaction', done));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -386,10 +380,7 @@ function attemptTransaction(session, startTime, fn, options) {
|
||||
}
|
||||
|
||||
if (isMaxTimeMSExpiredError(err)) {
|
||||
if (err.errorLabels == null) {
|
||||
err.errorLabels = [];
|
||||
}
|
||||
err.errorLabels.push('UnknownTransactionCommitResult');
|
||||
err.addErrorLabel('UnknownTransactionCommitResult');
|
||||
}
|
||||
|
||||
throw err;
|
||||
@@ -481,26 +472,20 @@ function endTransaction(session, commandName, callback) {
|
||||
if (commandName === 'commitTransaction') {
|
||||
session.transaction.transition(TxnState.TRANSACTION_COMMITTED);
|
||||
|
||||
if (
|
||||
e &&
|
||||
(e instanceof MongoNetworkError ||
|
||||
if (e) {
|
||||
if (
|
||||
e instanceof MongoNetworkError ||
|
||||
e instanceof MongoWriteConcernError ||
|
||||
isRetryableError(e) ||
|
||||
isMaxTimeMSExpiredError(e))
|
||||
) {
|
||||
if (e.errorLabels) {
|
||||
const idx = e.errorLabels.indexOf('TransientTransactionError');
|
||||
if (idx !== -1) {
|
||||
e.errorLabels.splice(idx, 1);
|
||||
isMaxTimeMSExpiredError(e)
|
||||
) {
|
||||
if (isUnknownTransactionCommitResult(e)) {
|
||||
e.addErrorLabel('UnknownTransactionCommitResult');
|
||||
|
||||
// per txns spec, must unpin session in this case
|
||||
session.transaction.unpinServer();
|
||||
}
|
||||
} else {
|
||||
e.errorLabels = [];
|
||||
}
|
||||
|
||||
if (isUnknownTransactionCommitResult(e)) {
|
||||
e.errorLabels.push('UnknownTransactionCommitResult');
|
||||
|
||||
// per txns spec, must unpin session in this case
|
||||
} else if (e.hasErrorLabel('TransientTransactionError')) {
|
||||
session.transaction.unpinServer();
|
||||
}
|
||||
}
|
||||
@@ -685,7 +670,12 @@ function commandSupportsReadConcern(command, options) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (command.mapReduce && options.out && (options.out.inline === 1 || options.out === 'inline')) {
|
||||
if (
|
||||
command.mapReduce &&
|
||||
options &&
|
||||
options.out &&
|
||||
(options.out.inline === 1 || options.out === 'inline')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -708,6 +698,11 @@ function applySession(session, command, options) {
|
||||
return new MongoError('Cannot use a session that has ended');
|
||||
}
|
||||
|
||||
// SPEC-1019: silently ignore explicit session with unacknowledged write for backwards compatibility
|
||||
if (options && options.writeConcern && options.writeConcern.w === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const serverSession = session.serverSession;
|
||||
serverSession.lastUse = now();
|
||||
command.lsid = serverSession.id;
|
||||
@@ -715,7 +710,7 @@ function applySession(session, command, options) {
|
||||
// first apply non-transaction-specific sessions data
|
||||
const inTransaction = session.inTransaction() || isTransactionCommand(command);
|
||||
const isRetryableWrite = options.willRetryWrite;
|
||||
const shouldApplyReadConcern = commandSupportsReadConcern(command);
|
||||
const shouldApplyReadConcern = commandSupportsReadConcern(command, options);
|
||||
|
||||
if (serverSession.txnNumber && (isRetryableWrite || inTransaction)) {
|
||||
command.txnNumber = BSON.Long.fromNumber(serverSession.txnNumber);
|
||||
|
||||
1
node_modules/mongodb/lib/core/tools/smoke_plugin.js
generated
vendored
1
node_modules/mongodb/lib/core/tools/smoke_plugin.js
generated
vendored
@@ -52,6 +52,7 @@ exports.attachToRunner = function(runner, outputFile) {
|
||||
fs.writeFileSync(outputFile, JSON.stringify(smokeOutput));
|
||||
|
||||
// Standard NodeJS uncaught exception handler
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err.stack);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
28
node_modules/mongodb/lib/core/topologies/mongos.js
generated
vendored
28
node_modules/mongodb/lib/core/topologies/mongos.js
generated
vendored
@@ -13,10 +13,10 @@ const cloneOptions = require('./shared').cloneOptions;
|
||||
const SessionMixins = require('./shared').SessionMixins;
|
||||
const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported;
|
||||
const relayEvents = require('../utils').relayEvents;
|
||||
const isRetryableError = require('../error').isRetryableError;
|
||||
const BSON = retrieveBSON();
|
||||
const getMMAPError = require('./shared').getMMAPError;
|
||||
const makeClientMetadata = require('../utils').makeClientMetadata;
|
||||
const legacyIsRetryableWriteError = require('./shared').legacyIsRetryableWriteError;
|
||||
|
||||
/**
|
||||
* @fileOverview The **Mongos** class is a class that represents a Mongos Proxy topology and is
|
||||
@@ -71,7 +71,7 @@ var handlers = ['connect', 'close', 'error', 'timeout', 'parseError'];
|
||||
* @param {Cursor} [options.cursorFactory=Cursor] The cursor factory class used for all query cursors
|
||||
* @param {number} [options.size=5] Server connection pool size
|
||||
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=0] Initial delay before TCP keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=120000] Initial delay before TCP keep alive enabled
|
||||
* @param {number} [options.localThresholdMS=15] Cutoff latency point in MS for MongoS proxy selection
|
||||
* @param {boolean} [options.noDelay=true] TCP Connection no delay
|
||||
* @param {number} [options.connectionTimeout=1000] TCP Connection timeout setting
|
||||
@@ -88,6 +88,7 @@ var handlers = ['connect', 'close', 'error', 'timeout', 'parseError'];
|
||||
* @param {boolean} [options.promoteLongs=true] Convert Long values from the db into Numbers if they fit into 53 bits
|
||||
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
||||
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
||||
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
||||
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
|
||||
* @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
|
||||
* @return {Mongos} A cursor instance
|
||||
@@ -113,6 +114,18 @@ var Mongos = function(seedlist, options) {
|
||||
// Get replSet Id
|
||||
this.id = id++;
|
||||
|
||||
// deduplicate seedlist
|
||||
if (Array.isArray(seedlist)) {
|
||||
seedlist = seedlist.reduce((seeds, seed) => {
|
||||
if (seeds.find(s => s.host === seed.host && s.port === seed.port)) {
|
||||
return seeds;
|
||||
}
|
||||
|
||||
seeds.push(seed);
|
||||
return seeds;
|
||||
}, []);
|
||||
}
|
||||
|
||||
// Internal state
|
||||
this.s = {
|
||||
options: Object.assign({ metadata: makeClientMetadata(options) }, options),
|
||||
@@ -907,11 +920,12 @@ function executeWriteOperation(args, options, callback) {
|
||||
!!options.retryWrites &&
|
||||
options.session &&
|
||||
isRetryableWritesSupported(self) &&
|
||||
!options.session.inTransaction();
|
||||
!options.session.inTransaction() &&
|
||||
options.explain === undefined;
|
||||
|
||||
const handler = (err, result) => {
|
||||
if (!err) return callback(null, result);
|
||||
if (!isRetryableError(err) || !willRetryWrite) {
|
||||
if (!legacyIsRetryableWriteError(err, self) || !willRetryWrite) {
|
||||
err = getMMAPError(err);
|
||||
return callback(err);
|
||||
}
|
||||
@@ -1107,7 +1121,7 @@ Mongos.prototype.command = function(ns, cmd, options, callback) {
|
||||
|
||||
const cb = (err, result) => {
|
||||
if (!err) return callback(null, result);
|
||||
if (!isRetryableError(err)) {
|
||||
if (!legacyIsRetryableWriteError(err, self)) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
@@ -1121,8 +1135,8 @@ Mongos.prototype.command = function(ns, cmd, options, callback) {
|
||||
|
||||
// increment and assign txnNumber
|
||||
if (willRetryWrite) {
|
||||
options.session.incrementTransactionNumber();
|
||||
options.willRetryWrite = willRetryWrite;
|
||||
clonedOptions.session.incrementTransactionNumber();
|
||||
clonedOptions.willRetryWrite = willRetryWrite;
|
||||
}
|
||||
|
||||
// Execute the command
|
||||
|
||||
81
node_modules/mongodb/lib/core/topologies/read_preference.js
generated
vendored
81
node_modules/mongodb/lib/core/topologies/read_preference.js
generated
vendored
@@ -1,4 +1,5 @@
|
||||
'use strict';
|
||||
const emitWarningOnce = require('../../utils').emitWarningOnce;
|
||||
|
||||
/**
|
||||
* The **ReadPreference** class is a class that represents a MongoDB ReadPreference and is
|
||||
@@ -8,6 +9,8 @@
|
||||
* @param {array} tags The tags object
|
||||
* @param {object} [options] Additional read preference options
|
||||
* @param {number} [options.maxStalenessSeconds] Max secondary read staleness in seconds, Minimum value is 90 seconds.
|
||||
* @param {object} [options.hedge] Server mode in which the same query is dispatched in parallel to multiple replica set members.
|
||||
* @param {boolean} [options.hedge.enabled] Explicitly enable or disable hedged reads.
|
||||
* @see https://docs.mongodb.com/manual/core/read-preference/
|
||||
* @return {ReadPreference}
|
||||
*/
|
||||
@@ -18,11 +21,14 @@ const ReadPreference = function(mode, tags, options) {
|
||||
|
||||
// TODO(major): tags MUST be an array of tagsets
|
||||
if (tags && !Array.isArray(tags)) {
|
||||
console.warn(
|
||||
emitWarningOnce(
|
||||
'ReadPreference tags must be an array, this will change in the next major version'
|
||||
);
|
||||
|
||||
if (typeof tags.maxStalenessSeconds !== 'undefined') {
|
||||
const tagsHasMaxStalenessSeconds = typeof tags.maxStalenessSeconds !== 'undefined';
|
||||
const tagsHasHedge = typeof tags.hedge !== 'undefined';
|
||||
const tagsHasOptions = tagsHasMaxStalenessSeconds || tagsHasHedge;
|
||||
if (tagsHasOptions) {
|
||||
// this is likely an options object
|
||||
options = tags;
|
||||
tags = undefined;
|
||||
@@ -33,6 +39,7 @@ const ReadPreference = function(mode, tags, options) {
|
||||
|
||||
this.mode = mode;
|
||||
this.tags = tags;
|
||||
this.hedge = options && options.hedge;
|
||||
|
||||
options = options || {};
|
||||
if (options.maxStalenessSeconds != null) {
|
||||
@@ -55,6 +62,10 @@ const ReadPreference = function(mode, tags, options) {
|
||||
if (this.maxStalenessSeconds) {
|
||||
throw new TypeError('Primary read preference cannot be combined with maxStalenessSeconds');
|
||||
}
|
||||
|
||||
if (this.hedge) {
|
||||
throw new TypeError('Primary read preference cannot be combined with hedge');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -91,20 +102,19 @@ const VALID_MODES = [
|
||||
* @return {ReadPreference}
|
||||
*/
|
||||
ReadPreference.fromOptions = function(options) {
|
||||
if (!options) return null;
|
||||
const readPreference = options.readPreference;
|
||||
if (!readPreference) return null;
|
||||
const readPreferenceTags = options.readPreferenceTags;
|
||||
|
||||
if (readPreference == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const maxStalenessSeconds = options.maxStalenessSeconds;
|
||||
if (typeof readPreference === 'string') {
|
||||
return new ReadPreference(readPreference, readPreferenceTags);
|
||||
} else if (!(readPreference instanceof ReadPreference) && typeof readPreference === 'object') {
|
||||
const mode = readPreference.mode || readPreference.preference;
|
||||
if (mode && typeof mode === 'string') {
|
||||
return new ReadPreference(mode, readPreference.tags, {
|
||||
maxStalenessSeconds: readPreference.maxStalenessSeconds
|
||||
maxStalenessSeconds: readPreference.maxStalenessSeconds || maxStalenessSeconds,
|
||||
hedge: readPreference.hedge
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -112,6 +122,60 @@ ReadPreference.fromOptions = function(options) {
|
||||
return readPreference;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves a read preference based on well-defined inheritance rules. This method will not only
|
||||
* determine the read preference (if there is one), but will also ensure the returned value is a
|
||||
* properly constructed instance of `ReadPreference`.
|
||||
*
|
||||
* @param {Collection|Db|MongoClient} parent The parent of the operation on which to determine the read
|
||||
* preference, used for determining the inherited read preference.
|
||||
* @param {object} options The options passed into the method, potentially containing a read preference
|
||||
* @returns {(ReadPreference|null)} The resolved read preference
|
||||
*/
|
||||
ReadPreference.resolve = function(parent, options) {
|
||||
options = options || {};
|
||||
const session = options.session;
|
||||
|
||||
const inheritedReadPreference = parent && parent.readPreference;
|
||||
|
||||
let readPreference;
|
||||
if (options.readPreference) {
|
||||
readPreference = ReadPreference.fromOptions(options);
|
||||
} else if (session && session.inTransaction() && session.transaction.options.readPreference) {
|
||||
// The transaction’s read preference MUST override all other user configurable read preferences.
|
||||
readPreference = session.transaction.options.readPreference;
|
||||
} else if (inheritedReadPreference != null) {
|
||||
readPreference = inheritedReadPreference;
|
||||
} else {
|
||||
readPreference = ReadPreference.primary;
|
||||
}
|
||||
|
||||
return typeof readPreference === 'string' ? new ReadPreference(readPreference) : readPreference;
|
||||
};
|
||||
|
||||
/**
|
||||
* Replaces options.readPreference with a ReadPreference instance
|
||||
*/
|
||||
ReadPreference.translate = function(options) {
|
||||
if (options.readPreference == null) return options;
|
||||
const r = options.readPreference;
|
||||
|
||||
if (typeof r === 'string') {
|
||||
options.readPreference = new ReadPreference(r);
|
||||
} else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
|
||||
const mode = r.mode || r.preference;
|
||||
if (mode && typeof mode === 'string') {
|
||||
options.readPreference = new ReadPreference(mode, r.tags, {
|
||||
maxStalenessSeconds: r.maxStalenessSeconds
|
||||
});
|
||||
}
|
||||
} else if (!(r instanceof ReadPreference)) {
|
||||
throw new TypeError('Invalid read preference: ' + r);
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate if a mode is legal
|
||||
*
|
||||
@@ -165,6 +229,7 @@ ReadPreference.prototype.toJSON = function() {
|
||||
const readPreference = { mode: this.mode };
|
||||
if (Array.isArray(this.tags)) readPreference.tags = this.tags;
|
||||
if (this.maxStalenessSeconds) readPreference.maxStalenessSeconds = this.maxStalenessSeconds;
|
||||
if (this.hedge) readPreference.hedge = this.hedge;
|
||||
return readPreference;
|
||||
};
|
||||
|
||||
|
||||
31
node_modules/mongodb/lib/core/topologies/replset.js
generated
vendored
31
node_modules/mongodb/lib/core/topologies/replset.js
generated
vendored
@@ -15,10 +15,10 @@ const Interval = require('./shared').Interval;
|
||||
const SessionMixins = require('./shared').SessionMixins;
|
||||
const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported;
|
||||
const relayEvents = require('../utils').relayEvents;
|
||||
const isRetryableError = require('../error').isRetryableError;
|
||||
const BSON = retrieveBSON();
|
||||
const getMMAPError = require('./shared').getMMAPError;
|
||||
const makeClientMetadata = require('../utils').makeClientMetadata;
|
||||
const legacyIsRetryableWriteError = require('./shared').legacyIsRetryableWriteError;
|
||||
const now = require('../../utils').now;
|
||||
const calculateDurationInMs = require('../../utils').calculateDurationInMs;
|
||||
|
||||
@@ -72,7 +72,7 @@ var handlers = ['connect', 'close', 'error', 'timeout', 'parseError'];
|
||||
* @param {Cursor} [options.cursorFactory=Cursor] The cursor factory class used for all query cursors
|
||||
* @param {number} [options.size=5] Server connection pool size
|
||||
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=0] Initial delay before TCP keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=120000] Initial delay before TCP keep alive enabled
|
||||
* @param {boolean} [options.noDelay=true] TCP Connection no delay
|
||||
* @param {number} [options.connectionTimeout=10000] TCP Connection timeout setting
|
||||
* @param {number} [options.socketTimeout=0] TCP Socket timeout setting
|
||||
@@ -88,6 +88,7 @@ var handlers = ['connect', 'close', 'error', 'timeout', 'parseError'];
|
||||
* @param {boolean} [options.promoteLongs=true] Convert Long values from the db into Numbers if they fit into 53 bits
|
||||
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
||||
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
||||
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
||||
* @param {number} [options.pingInterval=5000] Ping interval to check the response time to the different servers
|
||||
* @param {number} [options.localThresholdMS=15] Cutoff latency point in MS for Replicaset member selection
|
||||
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
|
||||
@@ -541,7 +542,7 @@ var monitorServer = function(host, self, options) {
|
||||
self.s.options.secondaryOnlyConnectionAllowed) ||
|
||||
self.s.replicaSetState.hasPrimary())
|
||||
) {
|
||||
self.state = CONNECTED;
|
||||
stateTransition(self, CONNECTED);
|
||||
|
||||
// Emit connected sign
|
||||
process.nextTick(function() {
|
||||
@@ -558,7 +559,7 @@ var monitorServer = function(host, self, options) {
|
||||
self.s.options.secondaryOnlyConnectionAllowed) ||
|
||||
self.s.replicaSetState.hasPrimary())
|
||||
) {
|
||||
self.state = CONNECTED;
|
||||
stateTransition(self, CONNECTING);
|
||||
|
||||
// Rexecute any stalled operation
|
||||
rexecuteOperations(self);
|
||||
@@ -787,7 +788,7 @@ function handleInitialConnectEvent(self, event) {
|
||||
// Do we have a primary or primaryAndSecondary
|
||||
if (shouldTriggerConnect(self)) {
|
||||
// We are connected
|
||||
self.state = CONNECTED;
|
||||
stateTransition(self, CONNECTED);
|
||||
|
||||
// Set initial connect state
|
||||
self.initialConnectState.connect = true;
|
||||
@@ -919,7 +920,7 @@ ReplSet.prototype.connect = function(options) {
|
||||
);
|
||||
});
|
||||
|
||||
// Error out as high availbility interval must be < than socketTimeout
|
||||
// Error out as high availability interval must be < than socketTimeout
|
||||
if (
|
||||
this.s.options.socketTimeout > 0 &&
|
||||
this.s.options.socketTimeout <= this.s.options.haInterval
|
||||
@@ -975,14 +976,19 @@ ReplSet.prototype.destroy = function(options, callback) {
|
||||
// Emit toplogy closing event
|
||||
emitSDAMEvent(this, 'topologyClosed', { topologyId: this.id });
|
||||
|
||||
// Transition state
|
||||
stateTransition(this, DESTROYED);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback(null, null);
|
||||
}
|
||||
};
|
||||
|
||||
if (this.state === DESTROYED) {
|
||||
if (typeof callback === 'function') callback(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Transition state
|
||||
stateTransition(this, DESTROYED);
|
||||
|
||||
// Clear out any monitoring process
|
||||
if (this.haTimeoutId) clearTimeout(this.haTimeoutId);
|
||||
|
||||
@@ -1188,7 +1194,8 @@ function executeWriteOperation(args, options, callback) {
|
||||
!!options.retryWrites &&
|
||||
options.session &&
|
||||
isRetryableWritesSupported(self) &&
|
||||
!options.session.inTransaction();
|
||||
!options.session.inTransaction() &&
|
||||
options.explain === undefined;
|
||||
|
||||
if (!self.s.replicaSetState.hasPrimary()) {
|
||||
if (self.s.disconnectHandler) {
|
||||
@@ -1202,7 +1209,7 @@ function executeWriteOperation(args, options, callback) {
|
||||
|
||||
const handler = (err, result) => {
|
||||
if (!err) return callback(null, result);
|
||||
if (!isRetryableError(err)) {
|
||||
if (!legacyIsRetryableWriteError(err, self)) {
|
||||
err = getMMAPError(err);
|
||||
return callback(err);
|
||||
}
|
||||
@@ -1365,7 +1372,7 @@ ReplSet.prototype.command = function(ns, cmd, options, callback) {
|
||||
|
||||
const cb = (err, result) => {
|
||||
if (!err) return callback(null, result);
|
||||
if (!isRetryableError(err)) {
|
||||
if (!legacyIsRetryableWriteError(err, self)) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
|
||||
8
node_modules/mongodb/lib/core/topologies/replset_state.js
generated
vendored
8
node_modules/mongodb/lib/core/topologies/replset_state.js
generated
vendored
@@ -34,7 +34,7 @@ var ReplSetState = function(options) {
|
||||
// Add event listener
|
||||
EventEmitter.call(this);
|
||||
// Topology state
|
||||
this.topologyType = TopologyType.ReplicaSetNoPrimary;
|
||||
this.topologyType = options.setName ? TopologyType.ReplicaSetNoPrimary : TopologyType.Unknown;
|
||||
this.setName = options.setName;
|
||||
|
||||
// Server set
|
||||
@@ -218,7 +218,8 @@ const isArbiter = ismaster => ismaster.arbiterOnly && ismaster.setName;
|
||||
ReplSetState.prototype.update = function(server) {
|
||||
var self = this;
|
||||
// Get the current ismaster
|
||||
var ismaster = server.lastIsMaster();
|
||||
const ismaster = server.lastIsMaster();
|
||||
if (ismaster && ismaster.isWritablePrimary) ismaster.ismaster = ismaster.isWritablePrimary;
|
||||
|
||||
// Get the server name and lowerCase it
|
||||
var serverName = server.name.toLowerCase();
|
||||
@@ -358,7 +359,8 @@ ReplSetState.prototype.update = function(server) {
|
||||
// Standalone server, destroy and return
|
||||
//
|
||||
if (ismaster && ismaster.ismaster && !ismaster.setName) {
|
||||
this.topologyType = this.primary ? TopologyType.ReplicaSetWithPrimary : TopologyType.Unknown;
|
||||
// We should not mark the topology as Unknown because of one standalone
|
||||
// we should just remove this server from the set
|
||||
this.remove(server, { force: true });
|
||||
return false;
|
||||
}
|
||||
|
||||
20
node_modules/mongodb/lib/core/topologies/server.js
generated
vendored
20
node_modules/mongodb/lib/core/topologies/server.js
generated
vendored
@@ -16,6 +16,7 @@ var inherits = require('util').inherits,
|
||||
createCompressionInfo = require('./shared').createCompressionInfo,
|
||||
resolveClusterTime = require('./shared').resolveClusterTime,
|
||||
SessionMixins = require('./shared').SessionMixins,
|
||||
extractCommand = require('../../command_utils').extractCommand,
|
||||
relayEvents = require('../utils').relayEvents;
|
||||
|
||||
const collationNotSupported = require('../utils').collationNotSupported;
|
||||
@@ -46,6 +47,7 @@ var debugFields = [
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'bsonRegExp',
|
||||
'servername'
|
||||
];
|
||||
|
||||
@@ -72,10 +74,10 @@ function topologyId(server) {
|
||||
* @param {number} options.port The server port
|
||||
* @param {number} [options.size=5] Server connection pool size
|
||||
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=300000] Initial delay before TCP keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=120000] Initial delay before TCP keep alive enabled
|
||||
* @param {boolean} [options.noDelay=true] TCP Connection no delay
|
||||
* @param {number} [options.connectionTimeout=30000] TCP Connection timeout setting
|
||||
* @param {number} [options.socketTimeout=360000] TCP Socket timeout setting
|
||||
* @param {number} [options.socketTimeout=0] TCP Socket timeout setting
|
||||
* @param {boolean} [options.ssl=false] Use SSL for connection
|
||||
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
|
||||
* @param {Buffer} [options.ca] SSL Certificate store binary buffer
|
||||
@@ -88,6 +90,7 @@ function topologyId(server) {
|
||||
* @param {boolean} [options.promoteLongs=true] Convert Long values from the db into Numbers if they fit into 53 bits
|
||||
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
||||
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
||||
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
||||
* @param {string} [options.appname=null] Application name, passed in on ismaster call and logged in mongod server logs. Maximum size 128 bytes.
|
||||
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
|
||||
* @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
|
||||
@@ -389,7 +392,7 @@ var eventHandler = function(self, event) {
|
||||
event === 'timeout' ||
|
||||
event === 'reconnect' ||
|
||||
event === 'attemptReconnect' ||
|
||||
'reconnectFailed'
|
||||
event === 'reconnectFailed'
|
||||
) {
|
||||
// Remove server instance from accounting
|
||||
if (
|
||||
@@ -608,18 +611,20 @@ Server.prototype.command = function(ns, cmd, options, callback) {
|
||||
options = Object.assign({}, options, { wireProtocolCommand: false });
|
||||
|
||||
// Debug log
|
||||
if (self.s.logger.isDebug())
|
||||
if (self.s.logger.isDebug()) {
|
||||
const extractedCommand = extractCommand(cmd);
|
||||
self.s.logger.debug(
|
||||
f(
|
||||
'executing command [%s] against %s',
|
||||
JSON.stringify({
|
||||
ns: ns,
|
||||
cmd: cmd,
|
||||
cmd: extractedCommand.shouldRedact ? `${extractedCommand.name} details REDACTED` : cmd,
|
||||
options: debugOptions(debugFields, options)
|
||||
}),
|
||||
self.name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// If we are not connected or have a disconnectHandler specified
|
||||
if (disconnectHandler(self, 'command', ns, cmd, options, callback)) return;
|
||||
@@ -864,12 +869,14 @@ Server.prototype.destroy = function(options, callback) {
|
||||
}
|
||||
|
||||
// No pool, return
|
||||
if (!self.s.pool) {
|
||||
if (!self.s.pool || this._destroyed) {
|
||||
this._destroyed = true;
|
||||
if (typeof callback === 'function') callback(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
this._destroyed = true;
|
||||
|
||||
// Emit close event
|
||||
if (options.emitClose) {
|
||||
self.emit('close', self);
|
||||
@@ -900,7 +907,6 @@ Server.prototype.destroy = function(options, callback) {
|
||||
|
||||
// Destroy the pool
|
||||
this.s.pool.destroy(options.force, callback);
|
||||
this._destroyed = true;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
58
node_modules/mongodb/lib/core/topologies/shared.js
generated
vendored
58
node_modules/mongodb/lib/core/topologies/shared.js
generated
vendored
@@ -1,9 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
const MONGODB_ERROR_CODES = require('../../error_codes').MONGODB_ERROR_CODES;
|
||||
const ReadPreference = require('./read_preference');
|
||||
const TopologyType = require('../sdam/common').TopologyType;
|
||||
const MongoError = require('../error').MongoError;
|
||||
const isRetryableWriteError = require('../error').isRetryableWriteError;
|
||||
const maxWireVersion = require('../utils').maxWireVersion;
|
||||
const MongoNetworkError = require('../error').MongoNetworkError;
|
||||
|
||||
const MMAPv1_RETRY_WRITES_ERROR_CODE = 20;
|
||||
const MMAPv1_RETRY_WRITES_ERROR_CODE = MONGODB_ERROR_CODES.IllegalOperation;
|
||||
|
||||
/**
|
||||
* Emit event if it exists
|
||||
@@ -416,18 +421,39 @@ function getMMAPError(err) {
|
||||
return newErr;
|
||||
}
|
||||
|
||||
module.exports.SessionMixins = SessionMixins;
|
||||
module.exports.resolveClusterTime = resolveClusterTime;
|
||||
module.exports.inquireServerState = inquireServerState;
|
||||
module.exports.getTopologyType = getTopologyType;
|
||||
module.exports.emitServerDescriptionChanged = emitServerDescriptionChanged;
|
||||
module.exports.emitTopologyDescriptionChanged = emitTopologyDescriptionChanged;
|
||||
module.exports.cloneOptions = cloneOptions;
|
||||
module.exports.createCompressionInfo = createCompressionInfo;
|
||||
module.exports.clone = clone;
|
||||
module.exports.diff = diff;
|
||||
module.exports.Interval = Interval;
|
||||
module.exports.Timeout = Timeout;
|
||||
module.exports.isRetryableWritesSupported = isRetryableWritesSupported;
|
||||
module.exports.getMMAPError = getMMAPError;
|
||||
module.exports.topologyType = topologyType;
|
||||
// NOTE: only used for legacy topology types
|
||||
function legacyIsRetryableWriteError(err, topology) {
|
||||
if (!(err instanceof MongoError)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if pre-4.4 server, then add error label if its a retryable write error
|
||||
if (
|
||||
isRetryableWritesSupported(topology) &&
|
||||
(err instanceof MongoNetworkError ||
|
||||
(maxWireVersion(topology) < 9 && isRetryableWriteError(err)))
|
||||
) {
|
||||
err.addErrorLabel('RetryableWriteError');
|
||||
}
|
||||
|
||||
return err.hasErrorLabel('RetryableWriteError');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
SessionMixins,
|
||||
resolveClusterTime,
|
||||
inquireServerState,
|
||||
getTopologyType,
|
||||
emitServerDescriptionChanged,
|
||||
emitTopologyDescriptionChanged,
|
||||
cloneOptions,
|
||||
createCompressionInfo,
|
||||
clone,
|
||||
diff,
|
||||
Interval,
|
||||
Timeout,
|
||||
isRetryableWritesSupported,
|
||||
getMMAPError,
|
||||
topologyType,
|
||||
legacyIsRetryableWriteError
|
||||
};
|
||||
|
||||
6
node_modules/mongodb/lib/core/transactions.js
generated
vendored
6
node_modules/mongodb/lib/core/transactions.js
generated
vendored
@@ -150,7 +150,11 @@ class Transaction {
|
||||
const nextStates = stateMachine[this.state];
|
||||
if (nextStates && nextStates.indexOf(nextState) !== -1) {
|
||||
this.state = nextState;
|
||||
if (this.state === TxnState.NO_TRANSACTION || this.state === TxnState.STARTING_TRANSACTION) {
|
||||
if (
|
||||
this.state === TxnState.NO_TRANSACTION ||
|
||||
this.state === TxnState.STARTING_TRANSACTION ||
|
||||
this.state === TxnState.TRANSACTION_ABORTED
|
||||
) {
|
||||
this.unpinServer();
|
||||
}
|
||||
return;
|
||||
|
||||
79
node_modules/mongodb/lib/core/uri_parser.js
generated
vendored
79
node_modules/mongodb/lib/core/uri_parser.js
generated
vendored
@@ -4,6 +4,7 @@ const qs = require('querystring');
|
||||
const dns = require('dns');
|
||||
const MongoParseError = require('./error').MongoParseError;
|
||||
const ReadPreference = require('./topologies/read_preference');
|
||||
const emitWarningOnce = require('../utils').emitWarningOnce;
|
||||
|
||||
/**
|
||||
* The following regular expression validates a connection string and breaks the
|
||||
@@ -11,6 +12,11 @@ const ReadPreference = require('./topologies/read_preference');
|
||||
*/
|
||||
const HOSTS_RX = /(mongodb(?:\+srv|)):\/\/(?: (?:[^:]*) (?: : ([^@]*) )? @ )?([^/?]*)(?:\/|)(.*)/;
|
||||
|
||||
// Options that reference file paths should not be parsed
|
||||
const FILE_PATH_OPTIONS = new Set(
|
||||
['sslCA', 'sslCert', 'sslKey', 'tlsCAFile', 'tlsCertificateKeyFile'].map(key => key.toLowerCase())
|
||||
);
|
||||
|
||||
/**
|
||||
* Determines whether a provided address matches the provided parent domain in order
|
||||
* to avoid certain attack vectors.
|
||||
@@ -37,12 +43,18 @@ function matchesParentDomain(srvAddress, parentDomain) {
|
||||
function parseSrvConnectionString(uri, options, callback) {
|
||||
const result = URL.parse(uri, true);
|
||||
|
||||
if (options.directConnection || options.directconnection) {
|
||||
return callback(new MongoParseError('directConnection not supported with SRV URI'));
|
||||
}
|
||||
|
||||
if (result.hostname.split('.').length < 3) {
|
||||
return callback(new MongoParseError('URI does not have hostname, domain name and tld'));
|
||||
}
|
||||
|
||||
result.domainLength = result.hostname.split('.').length;
|
||||
if (result.pathname && result.pathname.match(',')) {
|
||||
|
||||
const hostname = uri.substring('mongodb+srv://'.length).split('/')[0];
|
||||
if (hostname.match(',')) {
|
||||
return callback(new MongoParseError('Invalid URI, cannot contain multiple hostnames'));
|
||||
}
|
||||
|
||||
@@ -82,7 +94,7 @@ function parseSrvConnectionString(uri, options, callback) {
|
||||
// Resolve TXT record and add options from there if they exist.
|
||||
dns.resolveTxt(lookupAddress, (err, record) => {
|
||||
if (err) {
|
||||
if (err.code !== 'ENODATA') {
|
||||
if (err.code !== 'ENODATA' && err.code !== 'ENOTFOUND') {
|
||||
return callback(err);
|
||||
}
|
||||
record = null;
|
||||
@@ -94,6 +106,11 @@ function parseSrvConnectionString(uri, options, callback) {
|
||||
}
|
||||
|
||||
record = qs.parse(record[0].join(''));
|
||||
|
||||
if (Object.keys(record).some(k => k.toLowerCase() === 'loadbalanced')) {
|
||||
return callback(new MongoParseError('Load balancer mode requires driver version 4+'));
|
||||
}
|
||||
|
||||
if (Object.keys(record).some(key => key !== 'authSource' && key !== 'replicaSet')) {
|
||||
return callback(
|
||||
new MongoParseError('Text record must only set `authSource` or `replicaSet`')
|
||||
@@ -171,6 +188,7 @@ const STRING_OPTIONS = new Set(['authsource', 'replicaset']);
|
||||
// NOTE: this list exists in native already, if it is merged here we should deduplicate
|
||||
const AUTH_MECHANISMS = new Set([
|
||||
'GSSAPI',
|
||||
'MONGODB-AWS',
|
||||
'MONGODB-X509',
|
||||
'MONGODB-CR',
|
||||
'DEFAULT',
|
||||
@@ -214,7 +232,8 @@ const CASE_TRANSLATION = {
|
||||
tlscertificatekeyfile: 'tlsCertificateKeyFile',
|
||||
tlscertificatekeyfilepassword: 'tlsCertificateKeyFilePassword',
|
||||
wtimeout: 'wTimeoutMS',
|
||||
j: 'journal'
|
||||
j: 'journal',
|
||||
directconnection: 'directConnection'
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -257,7 +276,9 @@ function applyConnectionStringOption(obj, key, value, options) {
|
||||
|
||||
if (key === 'authmechanism' && !AUTH_MECHANISMS.has(value)) {
|
||||
throw new MongoParseError(
|
||||
'Value for `authMechanism` must be one of: `DEFAULT`, `GSSAPI`, `PLAIN`, `MONGODB-X509`, `SCRAM-SHA-1`, `SCRAM-SHA-256`'
|
||||
`Value for authMechanism must be one of: ${Array.from(AUTH_MECHANISMS).join(
|
||||
', '
|
||||
)}, found: ${value}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -357,6 +378,16 @@ function applyAuthExpectations(parsed) {
|
||||
parsed.auth = Object.assign({}, parsed.auth, { db: '$external' });
|
||||
}
|
||||
|
||||
if (authMechanism === 'MONGODB-AWS') {
|
||||
if (authSource != null && authSource !== '$external') {
|
||||
throw new MongoParseError(
|
||||
`Invalid source \`${authSource}\` for mechanism \`${authMechanism}\` specified.`
|
||||
);
|
||||
}
|
||||
|
||||
parsed.auth = Object.assign({}, parsed.auth, { db: '$external' });
|
||||
}
|
||||
|
||||
if (authMechanism === 'MONGODB-X509') {
|
||||
if (parsed.auth && parsed.auth.password != null) {
|
||||
throw new MongoParseError(`Password not allowed for mechanism \`${authMechanism}\``);
|
||||
@@ -406,14 +437,21 @@ function parseQueryString(query, options) {
|
||||
}
|
||||
|
||||
const normalizedKey = key.toLowerCase();
|
||||
const parsedValue = parseQueryStringItemValue(normalizedKey, value);
|
||||
if (normalizedKey === 'serverapi') {
|
||||
throw new MongoParseError(
|
||||
'URI cannot contain `serverApi`, it can only be passed to the client'
|
||||
);
|
||||
}
|
||||
const parsedValue = FILE_PATH_OPTIONS.has(normalizedKey)
|
||||
? value
|
||||
: parseQueryStringItemValue(normalizedKey, value);
|
||||
applyConnectionStringOption(result, normalizedKey, parsedValue, options);
|
||||
}
|
||||
|
||||
// special cases for known deprecated options
|
||||
if (result.wtimeout && result.wtimeoutms) {
|
||||
delete result.wtimeout;
|
||||
console.warn('Unsupported option `wtimeout` specified');
|
||||
emitWarningOnce('Unsupported option `wtimeout` specified');
|
||||
}
|
||||
|
||||
return Object.keys(result).length ? result : null;
|
||||
@@ -552,10 +590,6 @@ function parseConnectionString(uri, options, callback) {
|
||||
return callback(new MongoParseError('Invalid protocol provided'));
|
||||
}
|
||||
|
||||
if (protocol === PROTOCOL_MONGODB_SRV) {
|
||||
return parseSrvConnectionString(uri, options, callback);
|
||||
}
|
||||
|
||||
const dbAndQuery = cap[4].split('?');
|
||||
const db = dbAndQuery.length > 0 ? dbAndQuery[0] : null;
|
||||
const query = dbAndQuery.length > 1 ? dbAndQuery[1] : null;
|
||||
@@ -568,6 +602,15 @@ function parseConnectionString(uri, options, callback) {
|
||||
}
|
||||
|
||||
parsedOptions = Object.assign({}, parsedOptions, options);
|
||||
|
||||
if (Object.keys(parsedOptions).some(k => k.toLowerCase() === 'loadbalanced')) {
|
||||
return callback(new MongoParseError('Load balancer mode requires driver version 4+'));
|
||||
}
|
||||
|
||||
if (protocol === PROTOCOL_MONGODB_SRV) {
|
||||
return parseSrvConnectionString(uri, parsedOptions, callback);
|
||||
}
|
||||
|
||||
const auth = { username: null, password: null, db: db && db !== '' ? qs.unescape(db) : null };
|
||||
if (parsedOptions.auth) {
|
||||
// maintain support for legacy options passed into `MongoClient`
|
||||
@@ -661,6 +704,22 @@ function parseConnectionString(uri, options, callback) {
|
||||
return callback(new MongoParseError('No hostname or hostnames provided in connection string'));
|
||||
}
|
||||
|
||||
const directConnection = !!parsedOptions.directConnection;
|
||||
if (directConnection && hosts.length !== 1) {
|
||||
// If the option is set to true, the driver MUST validate that there is exactly one host given
|
||||
// in the host list in the URI, and fail client creation otherwise.
|
||||
return callback(new MongoParseError('directConnection option requires exactly one host'));
|
||||
}
|
||||
|
||||
// NOTE: this behavior will go away in v4.0, we will always auto discover there
|
||||
if (
|
||||
parsedOptions.directConnection == null &&
|
||||
hosts.length === 1 &&
|
||||
parsedOptions.replicaSet == null
|
||||
) {
|
||||
parsedOptions.directConnection = true;
|
||||
}
|
||||
|
||||
const result = {
|
||||
hosts: hosts,
|
||||
auth: auth.db || auth.username ? auth : null,
|
||||
|
||||
38
node_modules/mongodb/lib/core/utils.js
generated
vendored
38
node_modules/mongodb/lib/core/utils.js
generated
vendored
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
const os = require('os');
|
||||
const crypto = require('crypto');
|
||||
const requireOptional = require('require_optional');
|
||||
const requireOptional = require('optional-require')(require);
|
||||
|
||||
/**
|
||||
* Generate a UUIDv4
|
||||
@@ -27,6 +27,7 @@ function retrieveKerberos() {
|
||||
let kerberos;
|
||||
|
||||
try {
|
||||
// Ensure you always wrap an optional require in the try block NODE-3199
|
||||
kerberos = requireOptional('kerberos');
|
||||
} catch (err) {
|
||||
if (err.code === 'MODULE_NOT_FOUND') {
|
||||
@@ -46,10 +47,7 @@ const noEJSONError = function() {
|
||||
|
||||
// Facilitate loading EJSON optionally
|
||||
function retrieveEJSON() {
|
||||
let EJSON = null;
|
||||
try {
|
||||
EJSON = requireOptional('mongodb-extjson');
|
||||
} catch (error) {} // eslint-disable-line
|
||||
let EJSON = requireOptional('mongodb-extjson');
|
||||
if (!EJSON) {
|
||||
EJSON = {
|
||||
parse: noEJSONError,
|
||||
@@ -149,6 +147,35 @@ function eachAsync(arr, eachFn, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
function eachAsyncSeries(arr, eachFn, callback) {
|
||||
arr = arr || [];
|
||||
|
||||
let idx = 0;
|
||||
let awaiting = arr.length;
|
||||
if (awaiting === 0) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
function eachCallback(err) {
|
||||
idx++;
|
||||
awaiting--;
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx === arr.length && awaiting <= 0) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
eachFn(arr[idx], eachCallback);
|
||||
}
|
||||
|
||||
eachFn(arr[idx], eachCallback);
|
||||
}
|
||||
|
||||
function isUnifiedTopology(topology) {
|
||||
return topology.description != null;
|
||||
}
|
||||
@@ -257,6 +284,7 @@ module.exports = {
|
||||
maxWireVersion,
|
||||
isPromiseLike,
|
||||
eachAsync,
|
||||
eachAsyncSeries,
|
||||
isUnifiedTopology,
|
||||
arrayStrictEqual,
|
||||
tagsStrictEqual,
|
||||
|
||||
51
node_modules/mongodb/lib/core/wireprotocol/command.js
generated
vendored
51
node_modules/mongodb/lib/core/wireprotocol/command.js
generated
vendored
@@ -45,14 +45,43 @@ function _command(server, ns, cmd, options, callback) {
|
||||
const shouldUseOpMsg = supportsOpMsg(server);
|
||||
const session = options.session;
|
||||
|
||||
let clusterTime = server.clusterTime;
|
||||
const serverClusterTime = server.clusterTime;
|
||||
let clusterTime = serverClusterTime;
|
||||
let finalCmd = Object.assign({}, cmd);
|
||||
|
||||
const serverApi = options.serverApi;
|
||||
if (serverApi) {
|
||||
finalCmd.apiVersion = serverApi.version || serverApi;
|
||||
if (serverApi.strict != null) {
|
||||
finalCmd.apiStrict = serverApi.strict;
|
||||
}
|
||||
if (serverApi.deprecationErrors != null) {
|
||||
finalCmd.apiDeprecationErrors = serverApi.deprecationErrors;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSessionSupport(server) && session) {
|
||||
const sessionClusterTime = session.clusterTime;
|
||||
if (
|
||||
session.clusterTime &&
|
||||
session.clusterTime.clusterTime.greaterThan(clusterTime.clusterTime)
|
||||
serverClusterTime &&
|
||||
serverClusterTime.clusterTime &&
|
||||
sessionClusterTime &&
|
||||
sessionClusterTime.clusterTime &&
|
||||
sessionClusterTime.clusterTime.greaterThan(serverClusterTime.clusterTime)
|
||||
) {
|
||||
clusterTime = session.clusterTime;
|
||||
clusterTime = sessionClusterTime;
|
||||
}
|
||||
|
||||
// We need to unpin any read or write commands that happen outside of a pinned
|
||||
// transaction, so we check if we have a pinned transaction that is no longer
|
||||
// active, and unpin for all except start or commit.
|
||||
if (
|
||||
!session.transaction.isActive &&
|
||||
session.transaction.isPinned &&
|
||||
!finalCmd.startTransaction &&
|
||||
!finalCmd.commitTransaction
|
||||
) {
|
||||
session.transaction.unpinServer();
|
||||
}
|
||||
|
||||
const err = applySession(session, finalCmd, options);
|
||||
@@ -61,17 +90,12 @@ function _command(server, ns, cmd, options, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
// if we have a known cluster time, gossip it
|
||||
if (clusterTime) {
|
||||
// if we have a known cluster time, gossip it
|
||||
finalCmd.$clusterTime = clusterTime;
|
||||
}
|
||||
|
||||
if (
|
||||
isSharded(server) &&
|
||||
!shouldUseOpMsg &&
|
||||
readPreference &&
|
||||
readPreference.preference !== 'primary'
|
||||
) {
|
||||
if (isSharded(server) && !shouldUseOpMsg && readPreference && readPreference.mode !== 'primary') {
|
||||
finalCmd = {
|
||||
$query: finalCmd,
|
||||
$readPreference: readPreference.toJSON()
|
||||
@@ -105,10 +129,7 @@ function _command(server, ns, cmd, options, callback) {
|
||||
err instanceof MongoNetworkError &&
|
||||
!err.hasErrorLabel('TransientTransactionError')
|
||||
) {
|
||||
if (err.errorLabels == null) {
|
||||
err.errorLabels = [];
|
||||
}
|
||||
err.errorLabels.push('TransientTransactionError');
|
||||
err.addErrorLabel('TransientTransactionError');
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
4
node_modules/mongodb/lib/core/wireprotocol/constants.js
generated
vendored
4
node_modules/mongodb/lib/core/wireprotocol/constants.js
generated
vendored
@@ -1,9 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const MIN_SUPPORTED_SERVER_VERSION = '2.6';
|
||||
const MAX_SUPPORTED_SERVER_VERSION = '4.2';
|
||||
const MAX_SUPPORTED_SERVER_VERSION = '5.0';
|
||||
const MIN_SUPPORTED_WIRE_VERSION = 2;
|
||||
const MAX_SUPPORTED_WIRE_VERSION = 8;
|
||||
const MAX_SUPPORTED_WIRE_VERSION = 13;
|
||||
|
||||
module.exports = {
|
||||
MIN_SUPPORTED_SERVER_VERSION,
|
||||
|
||||
12
node_modules/mongodb/lib/core/wireprotocol/kill_cursors.js
generated
vendored
12
node_modules/mongodb/lib/core/wireprotocol/kill_cursors.js
generated
vendored
@@ -5,10 +5,16 @@ const MongoError = require('../error').MongoError;
|
||||
const MongoNetworkError = require('../error').MongoNetworkError;
|
||||
const collectionNamespace = require('./shared').collectionNamespace;
|
||||
const maxWireVersion = require('../utils').maxWireVersion;
|
||||
const emitWarning = require('../utils').emitWarning;
|
||||
const command = require('./command');
|
||||
|
||||
function killCursors(server, ns, cursorState, callback) {
|
||||
function killCursors(server, ns, cursorState, defaultOptions, callback) {
|
||||
if (typeof defaultOptions === 'function') {
|
||||
callback = defaultOptions;
|
||||
defaultOptions = {};
|
||||
}
|
||||
callback = typeof callback === 'function' ? callback : () => {};
|
||||
|
||||
const cursorId = cursorState.cursorId;
|
||||
|
||||
if (maxWireVersion(server) < 4) {
|
||||
@@ -31,7 +37,7 @@ function killCursors(server, ns, cursorState, callback) {
|
||||
if (typeof callback === 'function') {
|
||||
callback(err, null);
|
||||
} else {
|
||||
console.warn(err);
|
||||
emitWarning(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +50,7 @@ function killCursors(server, ns, cursorState, callback) {
|
||||
cursors: [cursorId]
|
||||
};
|
||||
|
||||
const options = {};
|
||||
const options = defaultOptions || {};
|
||||
if (typeof cursorState.session === 'object') options.session = cursorState.session;
|
||||
|
||||
command(server, ns, killCursorCmd, options, (err, result) => {
|
||||
|
||||
35
node_modules/mongodb/lib/core/wireprotocol/query.js
generated
vendored
35
node_modules/mongodb/lib/core/wireprotocol/query.js
generated
vendored
@@ -8,6 +8,8 @@ const isSharded = require('./shared').isSharded;
|
||||
const maxWireVersion = require('../utils').maxWireVersion;
|
||||
const applyCommonQueryOptions = require('./shared').applyCommonQueryOptions;
|
||||
const command = require('./command');
|
||||
const decorateWithExplain = require('../../utils').decorateWithExplain;
|
||||
const Explain = require('../../explain').Explain;
|
||||
|
||||
function query(server, ns, cmd, cursorState, options, callback) {
|
||||
options = options || {};
|
||||
@@ -31,7 +33,18 @@ function query(server, ns, cmd, cursorState, options, callback) {
|
||||
}
|
||||
|
||||
const readPreference = getReadPreference(cmd, options);
|
||||
const findCmd = prepareFindCommand(server, ns, cmd, cursorState, options);
|
||||
let findCmd = prepareFindCommand(server, ns, cmd, cursorState, options);
|
||||
|
||||
// If we have explain, we need to rewrite the find command
|
||||
// to wrap it in the explain command
|
||||
try {
|
||||
const explain = Explain.fromOptions(options);
|
||||
if (explain) {
|
||||
findCmd = decorateWithExplain(findCmd, explain);
|
||||
}
|
||||
} catch (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// NOTE: This actually modifies the passed in cmd, and our code _depends_ on this
|
||||
// side-effect. Change this ASAP
|
||||
@@ -59,7 +72,7 @@ function query(server, ns, cmd, cursorState, options, callback) {
|
||||
|
||||
function prepareFindCommand(server, ns, cmd, cursorState) {
|
||||
cursorState.batchSize = cmd.batchSize || cursorState.batchSize;
|
||||
let findCmd = {
|
||||
const findCmd = {
|
||||
find: collectionNamespace(ns)
|
||||
};
|
||||
|
||||
@@ -100,6 +113,10 @@ function prepareFindCommand(server, ns, cmd, cursorState) {
|
||||
sortValue = sortObject;
|
||||
}
|
||||
|
||||
if (typeof cmd.allowDiskUse === 'boolean') {
|
||||
findCmd.allowDiskUse = cmd.allowDiskUse;
|
||||
}
|
||||
|
||||
if (cmd.sort) findCmd.sort = sortValue;
|
||||
if (cmd.fields) findCmd.projection = cmd.fields;
|
||||
if (cmd.hint) findCmd.hint = cmd.hint;
|
||||
@@ -127,8 +144,8 @@ function prepareFindCommand(server, ns, cmd, cursorState) {
|
||||
if (cmd.maxTimeMS) findCmd.maxTimeMS = cmd.maxTimeMS;
|
||||
if (cmd.min) findCmd.min = cmd.min;
|
||||
if (cmd.max) findCmd.max = cmd.max;
|
||||
findCmd.returnKey = cmd.returnKey ? cmd.returnKey : false;
|
||||
findCmd.showRecordId = cmd.showDiskLoc ? cmd.showDiskLoc : false;
|
||||
if (typeof cmd.returnKey === 'boolean') findCmd.returnKey = cmd.returnKey;
|
||||
if (typeof cmd.showDiskLoc === 'boolean') findCmd.showRecordId = cmd.showDiskLoc;
|
||||
if (cmd.snapshot) findCmd.snapshot = cmd.snapshot;
|
||||
if (cmd.tailable) findCmd.tailable = cmd.tailable;
|
||||
if (cmd.oplogReplay) findCmd.oplogReplay = cmd.oplogReplay;
|
||||
@@ -139,14 +156,6 @@ function prepareFindCommand(server, ns, cmd, cursorState) {
|
||||
if (cmd.collation) findCmd.collation = cmd.collation;
|
||||
if (cmd.readConcern) findCmd.readConcern = cmd.readConcern;
|
||||
|
||||
// If we have explain, we need to rewrite the find command
|
||||
// to wrap it in the explain command
|
||||
if (cmd.explain) {
|
||||
findCmd = {
|
||||
explain: findCmd
|
||||
};
|
||||
}
|
||||
|
||||
return findCmd;
|
||||
}
|
||||
|
||||
@@ -184,7 +193,7 @@ function prepareLegacyFindQuery(server, ns, cmd, cursorState, options) {
|
||||
if (typeof cmd.showDiskLoc !== 'undefined') findCmd['$showDiskLoc'] = cmd.showDiskLoc;
|
||||
if (cmd.comment) findCmd['$comment'] = cmd.comment;
|
||||
if (cmd.maxTimeMS) findCmd['$maxTimeMS'] = cmd.maxTimeMS;
|
||||
if (cmd.explain) {
|
||||
if (options.explain !== undefined) {
|
||||
// nToReturn must be 0 (match all) or negative (match N and close cursor)
|
||||
// nToReturn > 0 will give explain results equivalent to limit(0)
|
||||
numberToReturn = -Math.abs(cmd.limit || 0);
|
||||
|
||||
1
node_modules/mongodb/lib/core/wireprotocol/shared.js
generated
vendored
1
node_modules/mongodb/lib/core/wireprotocol/shared.js
generated
vendored
@@ -57,6 +57,7 @@ function applyCommonQueryOptions(queryOptions, options) {
|
||||
promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true,
|
||||
promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true,
|
||||
promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false,
|
||||
bsonRegExp: typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : false,
|
||||
monitoring: typeof options.monitoring === 'boolean' ? options.monitoring : false,
|
||||
fullResult: typeof options.fullResult === 'boolean' ? options.fullResult : false
|
||||
});
|
||||
|
||||
11
node_modules/mongodb/lib/core/wireprotocol/write_command.js
generated
vendored
11
node_modules/mongodb/lib/core/wireprotocol/write_command.js
generated
vendored
@@ -3,6 +3,8 @@
|
||||
const MongoError = require('../error').MongoError;
|
||||
const collectionNamespace = require('./shared').collectionNamespace;
|
||||
const command = require('./command');
|
||||
const decorateWithExplain = require('../../utils').decorateWithExplain;
|
||||
const Explain = require('../../explain').Explain;
|
||||
|
||||
function writeCommand(server, type, opsField, ns, ops, options, callback) {
|
||||
if (ops.length === 0) throw new MongoError(`${type} must contain at least one document`);
|
||||
@@ -15,7 +17,7 @@ function writeCommand(server, type, opsField, ns, ops, options, callback) {
|
||||
const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
|
||||
const writeConcern = options.writeConcern;
|
||||
|
||||
const writeCommand = {};
|
||||
let writeCommand = {};
|
||||
writeCommand[type] = collectionNamespace(ns);
|
||||
writeCommand[opsField] = ops;
|
||||
writeCommand.ordered = ordered;
|
||||
@@ -36,6 +38,13 @@ function writeCommand(server, type, opsField, ns, ops, options, callback) {
|
||||
writeCommand.bypassDocumentValidation = options.bypassDocumentValidation;
|
||||
}
|
||||
|
||||
// If a command is to be explained, we need to reformat the command after
|
||||
// the other command properties are specified.
|
||||
const explain = Explain.fromOptions(options);
|
||||
if (explain) {
|
||||
writeCommand = decorateWithExplain(writeCommand, explain);
|
||||
}
|
||||
|
||||
const commandOptions = Object.assign(
|
||||
{
|
||||
checkKeys: type === 'insert',
|
||||
|
||||
47
node_modules/mongodb/lib/cursor.js
generated
vendored
47
node_modules/mongodb/lib/cursor.js
generated
vendored
@@ -12,6 +12,8 @@ const Map = require('./core').BSON.Map;
|
||||
const maybePromise = require('./utils').maybePromise;
|
||||
const executeOperation = require('./operations/execute_operation');
|
||||
const formattedOrderClause = require('./utils').formattedOrderClause;
|
||||
const Explain = require('./explain').Explain;
|
||||
const Aspect = require('./operations/operation').Aspect;
|
||||
|
||||
const each = require('./operations/cursor_ops').each;
|
||||
const CountOperation = require('./operations/count');
|
||||
@@ -81,7 +83,6 @@ const fields = ['numberOfRetries', 'tailableRetryInterval'];
|
||||
* collection.find({}).filter({a:1}) // Set query on the cursor
|
||||
* collection.find({}).comment('add a comment') // Add a comment to the query, allowing to correlate queries
|
||||
* collection.find({}).addCursorFlag('tailable', true) // Set cursor as tailable
|
||||
* collection.find({}).addCursorFlag('oplogReplay', true) // Set cursor as oplogReplay
|
||||
* collection.find({}).addCursorFlag('noCursorTimeout', true) // Set cursor as noCursorTimeout
|
||||
* collection.find({}).addCursorFlag('awaitData', true) // Set cursor as awaitData
|
||||
* collection.find({}).addCursorFlag('partial', true) // Set cursor as partial
|
||||
@@ -164,6 +165,10 @@ class Cursor extends CoreCursor {
|
||||
return this.cmd.sort;
|
||||
}
|
||||
|
||||
set session(clientSession) {
|
||||
this.cursorState.session = clientSession;
|
||||
}
|
||||
|
||||
_initializeCursor(callback) {
|
||||
if (this.operation && this.operation.session != null) {
|
||||
this.cursorState.session = this.operation.session;
|
||||
@@ -741,7 +746,12 @@ class Cursor extends CoreCursor {
|
||||
return false;
|
||||
}
|
||||
if (doc != null) {
|
||||
iterator(doc);
|
||||
try {
|
||||
iterator(doc);
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (doc == null && callback) {
|
||||
@@ -761,7 +771,12 @@ class Cursor extends CoreCursor {
|
||||
fulfill(null);
|
||||
return false;
|
||||
} else {
|
||||
iterator(doc);
|
||||
try {
|
||||
iterator(doc);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@@ -1000,25 +1015,25 @@ class Cursor extends CoreCursor {
|
||||
|
||||
/**
|
||||
* Execute the explain for the cursor
|
||||
*
|
||||
* For backwards compatibility, a verbosity of true is interpreted as "allPlansExecution"
|
||||
* and false as "queryPlanner". Prior to server version 3.6, aggregate()
|
||||
* ignores the verbosity parameter and executes in "queryPlanner".
|
||||
*
|
||||
* @method
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [verbosity=true] - An optional mode in which to run the explain.
|
||||
* @param {Cursor~resultCallback} [callback] The result callback.
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
explain(callback) {
|
||||
// NOTE: the next line includes a special case for operations which do not
|
||||
// subclass `CommandOperationV2`. To be removed asap.
|
||||
if (this.operation && this.operation.cmd == null) {
|
||||
this.operation.options.explain = true;
|
||||
this.operation.fullResponse = false;
|
||||
return executeOperation(this.topology, this.operation, callback);
|
||||
}
|
||||
explain(verbosity, callback) {
|
||||
if (typeof verbosity === 'function') (callback = verbosity), (verbosity = true);
|
||||
if (verbosity === undefined) verbosity = true;
|
||||
|
||||
this.cmd.explain = true;
|
||||
|
||||
// Do we have a readConcern
|
||||
if (this.cmd.readConcern) {
|
||||
delete this.cmd['readConcern'];
|
||||
if (!this.operation || !this.operation.hasAspect(Aspect.EXPLAINABLE)) {
|
||||
throw new MongoError('This command cannot be explained');
|
||||
}
|
||||
this.operation.explain = new Explain(verbosity);
|
||||
|
||||
return maybePromise(this, callback, cb => {
|
||||
CoreCursor.prototype._next.apply(this, [cb]);
|
||||
});
|
||||
|
||||
246
node_modules/mongodb/lib/db.js
generated
vendored
246
node_modules/mongodb/lib/db.js
generated
vendored
@@ -12,9 +12,8 @@ const MongoError = require('./core').MongoError;
|
||||
const ObjectID = require('./core').ObjectID;
|
||||
const Logger = require('./core').Logger;
|
||||
const Collection = require('./collection');
|
||||
const mergeOptionsAndWriteConcern = require('./utils').mergeOptionsAndWriteConcern;
|
||||
const conditionallyMergeWriteConcern = require('./utils').conditionallyMergeWriteConcern;
|
||||
const executeLegacyOperation = require('./utils').executeLegacyOperation;
|
||||
const resolveReadPreference = require('./utils').resolveReadPreference;
|
||||
const ChangeStream = require('./change_stream');
|
||||
const deprecate = require('util').deprecate;
|
||||
const deprecateOptions = require('./utils').deprecateOptions;
|
||||
@@ -35,8 +34,9 @@ const AggregateOperation = require('./operations/aggregate');
|
||||
const AddUserOperation = require('./operations/add_user');
|
||||
const CollectionsOperation = require('./operations/collections');
|
||||
const CommandOperation = require('./operations/command');
|
||||
const RunCommandOperation = require('./operations/run_command');
|
||||
const CreateCollectionOperation = require('./operations/create_collection');
|
||||
const CreateIndexOperation = require('./operations/create_index');
|
||||
const CreateIndexesOperation = require('./operations/create_indexes');
|
||||
const DropCollectionOperation = require('./operations/drop').DropCollectionOperation;
|
||||
const DropDatabaseOperation = require('./operations/drop').DropDatabaseOperation;
|
||||
const ExecuteDbAdminCommandOperation = require('./operations/execute_db_admin_command');
|
||||
@@ -72,6 +72,7 @@ const legalOptionNames = [
|
||||
'wtimeout',
|
||||
'fsync',
|
||||
'j',
|
||||
'writeConcern',
|
||||
'readPreference',
|
||||
'readPreferenceTags',
|
||||
'native_parser',
|
||||
@@ -82,7 +83,6 @@ const legalOptionNames = [
|
||||
'bufferMaxEntries',
|
||||
'authSource',
|
||||
'ignoreUndefined',
|
||||
'promoteLongs',
|
||||
'promiseLibrary',
|
||||
'readConcern',
|
||||
'retryMiliSeconds',
|
||||
@@ -94,6 +94,7 @@ const legalOptionNames = [
|
||||
'promoteBuffers',
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'bsonRegExp',
|
||||
'compression',
|
||||
'retryWrites'
|
||||
];
|
||||
@@ -105,9 +106,10 @@ const legalOptionNames = [
|
||||
* @param {(Server|ReplSet|Mongos)} topology The server topology for the database.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {string} [options.authSource] If the database authentication is dependent on another databaseName.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
||||
@@ -115,6 +117,7 @@ const legalOptionNames = [
|
||||
* @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
|
||||
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
||||
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
||||
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
||||
* @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited.
|
||||
* @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
|
||||
* @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys.
|
||||
@@ -211,6 +214,14 @@ function Db(databaseName, topology, options) {
|
||||
|
||||
inherits(Db, EventEmitter);
|
||||
|
||||
Db.prototype.on = deprecate(function() {
|
||||
return Db.super_.prototype.on.apply(this, arguments);
|
||||
}, 'Listening to events on the Db class has been deprecated and will be removed in the next major version.');
|
||||
|
||||
Db.prototype.once = deprecate(function() {
|
||||
return Db.super_.prototype.once.apply(this, arguments);
|
||||
}, 'Listening to events on the Db class has been deprecated and will be removed in the next major version.');
|
||||
|
||||
// Topology
|
||||
Object.defineProperty(Db.prototype, 'topology', {
|
||||
enumerable: true,
|
||||
@@ -290,7 +301,7 @@ Db.prototype.command = function(command, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = Object.assign({}, options);
|
||||
|
||||
const commandOperation = new CommandOperation(this, options, null, command);
|
||||
const commandOperation = new RunCommandOperation(this, command, options);
|
||||
|
||||
return executeOperation(this.s.topology, commandOperation, callback);
|
||||
};
|
||||
@@ -304,7 +315,7 @@ Db.prototype.command = function(command, options, callback) {
|
||||
* @param {number} [options.batchSize=1000] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
||||
* @param {object} [options.cursor] Return the query as cursor, on 2.6 > it returns as a real cursor on pre 2.6 it returns as an emulated cursor.
|
||||
* @param {number} [options.cursor.batchSize=1000] Deprecated. Use `options.batchSize`
|
||||
* @param {boolean} [options.explain=false] Explain returns the aggregation execution plan (requires mongodb 2.6 >).
|
||||
* @param {'queryPlanner'|'queryPlannerExtended'|'executionStats'|'allPlansExecution'|boolean} [options.explain] The verbosity mode for the explain output.
|
||||
* @param {boolean} [options.allowDiskUse=false] allowDiskUse lets the server know if it can use disk to store temporary results for the aggregation (requires mongodb 2.6 >).
|
||||
* @param {number} [options.maxTimeMS] maxTimeMS specifies a cumulative time limit in milliseconds for processing operations on the cursor. MongoDB interrupts the operation at the earliest following interrupt point.
|
||||
* @param {number} [options.maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a tailable cursor query.
|
||||
@@ -313,6 +324,7 @@ Db.prototype.command = function(command, options, callback) {
|
||||
* @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
|
||||
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
||||
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
||||
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
||||
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
||||
* @param {string} [options.comment] Add a comment to an aggregation command
|
||||
* @param {string|object} [options.hint] Add an index selection hint to an aggregation command
|
||||
@@ -372,7 +384,7 @@ Db.prototype.admin = function() {
|
||||
* @param {AggregationCursor} cursor The cursor if the aggregation command was executed successfully.
|
||||
*/
|
||||
|
||||
const collectionKeys = [
|
||||
const COLLECTION_OPTION_KEYS = [
|
||||
'pkFactory',
|
||||
'readPreference',
|
||||
'serializeFunctions',
|
||||
@@ -381,7 +393,8 @@ const collectionKeys = [
|
||||
'ignoreUndefined',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'promoteLongs'
|
||||
'promoteLongs',
|
||||
'bsonRegExp'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -391,92 +404,106 @@ const collectionKeys = [
|
||||
* @method
|
||||
* @param {string} name the collection name we wish to access.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
|
||||
* @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys.
|
||||
* @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.strict=false] Returns an error if the collection does not exist
|
||||
* @param {boolean} [options.strict=false] **Deprecated** Returns an error if the collection does not exist
|
||||
* @param {object} [options.readConcern] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
|
||||
* @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
|
||||
* @param {Db~collectionResultCallback} [callback] The collection result callback
|
||||
* @return {Collection} return the new Collection instance if not in strict mode
|
||||
*/
|
||||
Db.prototype.collection = function(name, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
options = Object.assign({}, options);
|
||||
Db.prototype.collection = deprecateOptions(
|
||||
{
|
||||
name: 'Db.collection',
|
||||
deprecatedOptions: ['strict'],
|
||||
optionsIndex: 1
|
||||
},
|
||||
function(name, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
options = Object.assign({}, options);
|
||||
|
||||
// Set the promise library
|
||||
options.promiseLibrary = this.s.promiseLibrary;
|
||||
// Set the promise library
|
||||
options.promiseLibrary = this.s.promiseLibrary;
|
||||
|
||||
// If we have not set a collection level readConcern set the db level one
|
||||
options.readConcern = options.readConcern
|
||||
? new ReadConcern(options.readConcern.level)
|
||||
: this.readConcern;
|
||||
// If we have not set a collection level readConcern set the db level one
|
||||
options.readConcern = options.readConcern
|
||||
? new ReadConcern(options.readConcern.level)
|
||||
: this.readConcern;
|
||||
|
||||
// Do we have ignoreUndefined set
|
||||
if (this.s.options.ignoreUndefined) {
|
||||
options.ignoreUndefined = this.s.options.ignoreUndefined;
|
||||
}
|
||||
|
||||
// Merge in all needed options and ensure correct writeConcern merging from db level
|
||||
options = mergeOptionsAndWriteConcern(options, this.s.options, collectionKeys, true);
|
||||
|
||||
// Execute
|
||||
if (options == null || !options.strict) {
|
||||
try {
|
||||
const collection = new Collection(
|
||||
this,
|
||||
this.s.topology,
|
||||
this.databaseName,
|
||||
name,
|
||||
this.s.pkFactory,
|
||||
options
|
||||
);
|
||||
if (callback) callback(null, collection);
|
||||
return collection;
|
||||
} catch (err) {
|
||||
if (err instanceof MongoError && callback) return callback(err);
|
||||
throw err;
|
||||
// Do we have ignoreUndefined set
|
||||
if (this.s.options.ignoreUndefined) {
|
||||
options.ignoreUndefined = this.s.options.ignoreUndefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Strict mode
|
||||
if (typeof callback !== 'function') {
|
||||
throw toError(`A callback is required in strict mode. While getting collection ${name}`);
|
||||
}
|
||||
|
||||
// Did the user destroy the topology
|
||||
if (this.serverConfig && this.serverConfig.isDestroyed()) {
|
||||
return callback(new MongoError('topology was destroyed'));
|
||||
}
|
||||
|
||||
const listCollectionOptions = Object.assign({}, options, { nameOnly: true });
|
||||
|
||||
// Strict mode
|
||||
this.listCollections({ name: name }, listCollectionOptions).toArray((err, collections) => {
|
||||
if (err != null) return handleCallback(callback, err, null);
|
||||
if (collections.length === 0)
|
||||
return handleCallback(
|
||||
callback,
|
||||
toError(`Collection ${name} does not exist. Currently in strict mode.`),
|
||||
null
|
||||
);
|
||||
|
||||
try {
|
||||
return handleCallback(
|
||||
callback,
|
||||
null,
|
||||
new Collection(this, this.s.topology, this.databaseName, name, this.s.pkFactory, options)
|
||||
);
|
||||
} catch (err) {
|
||||
return handleCallback(callback, err, null);
|
||||
for (const collectionOptionKey of COLLECTION_OPTION_KEYS) {
|
||||
if (!(collectionOptionKey in options) && this.s.options[collectionOptionKey] !== undefined) {
|
||||
options[collectionOptionKey] = this.s.options[collectionOptionKey];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Merge in all needed options and ensure correct writeConcern merging from db level
|
||||
options = conditionallyMergeWriteConcern(options, this.s.options);
|
||||
|
||||
// Execute
|
||||
if (options == null || !options.strict) {
|
||||
try {
|
||||
const collection = new Collection(
|
||||
this,
|
||||
this.s.topology,
|
||||
this.databaseName,
|
||||
name,
|
||||
this.s.pkFactory,
|
||||
options
|
||||
);
|
||||
if (callback) callback(null, collection);
|
||||
return collection;
|
||||
} catch (err) {
|
||||
if (err instanceof MongoError && callback) return callback(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// Strict mode
|
||||
if (typeof callback !== 'function') {
|
||||
throw toError(`A callback is required in strict mode. While getting collection ${name}`);
|
||||
}
|
||||
|
||||
// Did the user destroy the topology
|
||||
if (this.serverConfig && this.serverConfig.isDestroyed()) {
|
||||
return callback(new MongoError('topology was destroyed'));
|
||||
}
|
||||
|
||||
const listCollectionOptions = Object.assign({}, options, { nameOnly: true });
|
||||
|
||||
// Strict mode
|
||||
this.listCollections({ name: name }, listCollectionOptions).toArray((err, collections) => {
|
||||
if (err != null) return handleCallback(callback, err, null);
|
||||
if (collections.length === 0)
|
||||
return handleCallback(
|
||||
callback,
|
||||
toError(`Collection ${name} does not exist. Currently in strict mode.`),
|
||||
null
|
||||
);
|
||||
|
||||
try {
|
||||
return handleCallback(
|
||||
callback,
|
||||
null,
|
||||
new Collection(this, this.s.topology, this.databaseName, name, this.s.pkFactory, options)
|
||||
);
|
||||
} catch (err) {
|
||||
return handleCallback(callback, err, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a new collection on a server with the specified options. Use this to create capped collections.
|
||||
@@ -485,14 +512,15 @@ Db.prototype.collection = function(name, options, callback) {
|
||||
* @method
|
||||
* @param {string} name the collection name we wish to access.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
|
||||
* @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys.
|
||||
* @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
||||
* @param {boolean} [options.strict=false] Returns an error if the collection does not exist
|
||||
* @param {boolean} [options.strict=false] DEPRECATED: Returns an error if the collection does not exist
|
||||
* @param {boolean} [options.capped=false] Create a capped collection.
|
||||
* @param {boolean} [options.autoIndexId=true] DEPRECATED: Create an index on the _id field of the document, True by default on MongoDB 2.6 - 3.0
|
||||
* @param {number} [options.size] The size of the capped collection in bytes.
|
||||
@@ -513,7 +541,7 @@ Db.prototype.collection = function(name, options, callback) {
|
||||
Db.prototype.createCollection = deprecateOptions(
|
||||
{
|
||||
name: 'Db.createCollection',
|
||||
deprecatedOptions: ['autoIndexId'],
|
||||
deprecatedOptions: ['autoIndexId', 'strict', 'w', 'wtimeout', 'j'],
|
||||
optionsIndex: 1
|
||||
},
|
||||
function(name, options, callback) {
|
||||
@@ -643,10 +671,10 @@ Db.prototype.renameCollection = function(fromCollection, toCollection, options,
|
||||
* @method
|
||||
* @param {string} name Name of collection to drop
|
||||
* @param {Object} [options] Optional settings
|
||||
* @param {WriteConcern} [options.writeConcern] A full WriteConcern object
|
||||
* @param {(number|string)} [options.w] The write concern
|
||||
* @param {number} [options.wtimeout] The write concern timeout
|
||||
* @param {boolean} [options.j] The journal write concern
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Db~resultCallback} [callback] The results callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
@@ -709,7 +737,7 @@ Db.prototype.collections = function(options, callback) {
|
||||
Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
options.readPreference = resolveReadPreference(this, options);
|
||||
options.readPreference = ReadPreference.resolve(this, options);
|
||||
|
||||
const executeDbAdminCommandOperation = new ExecuteDbAdminCommandOperation(
|
||||
this,
|
||||
@@ -726,9 +754,10 @@ Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
|
||||
* @param {string} name Name of the collection to create the index on.
|
||||
* @param {(string|object)} fieldOrSpec Defines the index.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.unique=false] Creates an unique index.
|
||||
* @param {boolean} [options.sparse=false] Creates a sparse index.
|
||||
* @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
|
||||
@@ -740,6 +769,7 @@ Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
|
||||
* @param {string} [options.name] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
|
||||
* @param {object} [options.partialFilterExpression] Creates a partial index based on the given filter object (MongoDB 3.2 or higher)
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {(number|string)} [options.commitQuorum] (MongoDB 4.4. or higher) Specifies how many data-bearing members of a replica set, including the primary, must complete the index builds successfully before the primary marks the indexes as ready. This option accepts the same values for the "w" field in a write concern plus "votingMembers", which indicates all voting data-bearing nodes.
|
||||
* @param {Db~resultCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
@@ -747,9 +777,9 @@ Db.prototype.createIndex = function(name, fieldOrSpec, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options ? Object.assign({}, options) : {};
|
||||
|
||||
const createIndexOperation = new CreateIndexOperation(this, name, fieldOrSpec, options);
|
||||
const createIndexesOperation = new CreateIndexesOperation(this, name, fieldOrSpec, options);
|
||||
|
||||
return executeOperation(this.s.topology, createIndexOperation, callback);
|
||||
return executeOperation(this.s.topology, createIndexesOperation, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -759,9 +789,10 @@ Db.prototype.createIndex = function(name, fieldOrSpec, options, callback) {
|
||||
* @param {string} name The index name
|
||||
* @param {(string|object)} fieldOrSpec Defines the index.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.unique=false] Creates an unique index.
|
||||
* @param {boolean} [options.sparse=false] Creates a sparse index.
|
||||
* @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
|
||||
@@ -799,9 +830,10 @@ Db.prototype.addChild = function(db) {
|
||||
* @param {string} username The username.
|
||||
* @param {string} password The password.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {object} [options.customData] Custom data associated with the user (only Mongodb 2.6 or higher)
|
||||
* @param {object[]} [options.roles] Roles associated with the created user (only Mongodb 2.6 or higher)
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
@@ -828,9 +860,10 @@ Db.prototype.addUser = function(username, password, options, callback) {
|
||||
* @method
|
||||
* @param {string} username The username.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {ClientSession} [options.session] optional session to use for this operation
|
||||
* @param {Db~resultCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
@@ -918,6 +951,7 @@ Db.prototype.indexInformation = function(name, options, callback) {
|
||||
/**
|
||||
* Unref all sockets
|
||||
* @method
|
||||
* @deprecated This function is deprecated and will be removed in the next major version.
|
||||
*/
|
||||
Db.prototype.unref = function() {
|
||||
this.s.topology.unref();
|
||||
|
||||
42
node_modules/mongodb/lib/error.js
generated
vendored
42
node_modules/mongodb/lib/error.js
generated
vendored
@@ -1,26 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
const MongoNetworkError = require('./core').MongoNetworkError;
|
||||
const MONGODB_ERROR_CODES = require('./error_codes').MONGODB_ERROR_CODES;
|
||||
|
||||
// From spec@https://github.com/mongodb/specifications/blob/f93d78191f3db2898a59013a7ed5650352ef6da8/source/change-streams/change-streams.rst#resumable-error
|
||||
const GET_MORE_RESUMABLE_CODES = new Set([
|
||||
6, // HostUnreachable
|
||||
7, // HostNotFound
|
||||
89, // NetworkTimeout
|
||||
91, // ShutdownInProgress
|
||||
189, // PrimarySteppedDown
|
||||
262, // ExceededTimeLimit
|
||||
9001, // SocketException
|
||||
10107, // NotMaster
|
||||
11600, // InterruptedAtShutdown
|
||||
11602, // InterruptedDueToReplStateChange
|
||||
13435, // NotMasterNoSlaveOk
|
||||
13436, // NotMasterOrSecondary
|
||||
63, // StaleShardVersion
|
||||
150, // StaleEpoch
|
||||
13388, // StaleConfig
|
||||
234, // RetryChangeStream
|
||||
133 // FailedToSatisfyReadPreference
|
||||
MONGODB_ERROR_CODES.HostUnreachable,
|
||||
MONGODB_ERROR_CODES.HostNotFound,
|
||||
MONGODB_ERROR_CODES.NetworkTimeout,
|
||||
MONGODB_ERROR_CODES.ShutdownInProgress,
|
||||
MONGODB_ERROR_CODES.PrimarySteppedDown,
|
||||
MONGODB_ERROR_CODES.ExceededTimeLimit,
|
||||
MONGODB_ERROR_CODES.SocketException,
|
||||
MONGODB_ERROR_CODES.NotMaster,
|
||||
MONGODB_ERROR_CODES.InterruptedAtShutdown,
|
||||
MONGODB_ERROR_CODES.InterruptedDueToReplStateChange,
|
||||
MONGODB_ERROR_CODES.NotMasterNoSlaveOk,
|
||||
MONGODB_ERROR_CODES.NotMasterOrSecondary,
|
||||
MONGODB_ERROR_CODES.StaleShardVersion,
|
||||
MONGODB_ERROR_CODES.StaleEpoch,
|
||||
MONGODB_ERROR_CODES.StaleConfig,
|
||||
MONGODB_ERROR_CODES.RetryChangeStream,
|
||||
MONGODB_ERROR_CODES.FailedToSatisfyReadPreference,
|
||||
MONGODB_ERROR_CODES.CursorNotFound
|
||||
]);
|
||||
|
||||
function isResumableError(error, wireVersion) {
|
||||
@@ -29,10 +31,14 @@ function isResumableError(error, wireVersion) {
|
||||
}
|
||||
|
||||
if (wireVersion >= 9) {
|
||||
// DRIVERS-1308: For 4.4 drivers running against 4.4 servers, drivers will add a special case to treat the CursorNotFound error code as resumable
|
||||
if (error.code === MONGODB_ERROR_CODES.CursorNotFound) {
|
||||
return true;
|
||||
}
|
||||
return error.hasErrorLabel('ResumableChangeStreamError');
|
||||
}
|
||||
|
||||
return GET_MORE_RESUMABLE_CODES.has(error.code);
|
||||
}
|
||||
|
||||
module.exports = { GET_MORE_RESUMABLE_CODES, isResumableError };
|
||||
module.exports = { GET_MORE_RESUMABLE_CODES, isResumableError, MONGODB_ERROR_CODES };
|
||||
|
||||
15
node_modules/mongodb/lib/gridfs-stream/download.js
generated
vendored
15
node_modules/mongodb/lib/gridfs-stream/download.js
generated
vendored
@@ -278,6 +278,7 @@ function init(self) {
|
||||
if (error) {
|
||||
return __handleError(self, error);
|
||||
}
|
||||
|
||||
if (!doc) {
|
||||
var identifier = self.s.filter._id ? self.s.filter._id.toString() : self.s.filter.filename;
|
||||
var errmsg = 'FileNotFound: file ' + identifier + ' was not found';
|
||||
@@ -301,7 +302,11 @@ function init(self) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.s.bytesToSkip = handleStartOption(self, doc, self.s.options);
|
||||
try {
|
||||
self.s.bytesToSkip = handleStartOption(self, doc, self.s.options);
|
||||
} catch (error) {
|
||||
return __handleError(self, error);
|
||||
}
|
||||
|
||||
var filter = { files_id: doc._id };
|
||||
|
||||
@@ -322,7 +327,13 @@ function init(self) {
|
||||
|
||||
self.s.expectedEnd = Math.ceil(doc.length / doc.chunkSize);
|
||||
self.s.file = doc;
|
||||
self.s.bytesToTrim = handleEndOption(self, doc, self.s.cursor, self.s.options);
|
||||
|
||||
try {
|
||||
self.s.bytesToTrim = handleEndOption(self, doc, self.s.cursor, self.s.options);
|
||||
} catch (error) {
|
||||
return __handleError(self, error);
|
||||
}
|
||||
|
||||
self.emit('file', doc);
|
||||
});
|
||||
}
|
||||
|
||||
67
node_modules/mongodb/lib/gridfs-stream/index.js
generated
vendored
67
node_modules/mongodb/lib/gridfs-stream/index.js
generated
vendored
@@ -7,6 +7,7 @@ var shallowClone = require('../utils').shallowClone;
|
||||
var toError = require('../utils').toError;
|
||||
var util = require('util');
|
||||
var executeLegacyOperation = require('../utils').executeLegacyOperation;
|
||||
const deprecateOptions = require('../utils').deprecateOptions;
|
||||
|
||||
var DEFAULT_GRIDFS_BUCKET_OPTIONS = {
|
||||
bucketName: 'fs',
|
||||
@@ -79,21 +80,28 @@ util.inherits(GridFSBucket, Emitter);
|
||||
* @param {object} [options.metadata] Optional object to store in the file document's `metadata` field
|
||||
* @param {string} [options.contentType] Optional string to store in the file document's `contentType` field
|
||||
* @param {array} [options.aliases] Optional array of strings to store in the file document's `aliases` field
|
||||
* @param {boolean} [options.disableMD5=false] If true, disables adding an md5 field to file data
|
||||
* @param {boolean} [options.disableMD5=false] **Deprecated** If true, disables adding an md5 field to file data
|
||||
* @return {GridFSBucketWriteStream}
|
||||
*/
|
||||
|
||||
GridFSBucket.prototype.openUploadStream = function(filename, options) {
|
||||
if (options) {
|
||||
options = shallowClone(options);
|
||||
} else {
|
||||
options = {};
|
||||
GridFSBucket.prototype.openUploadStream = deprecateOptions(
|
||||
{
|
||||
name: 'GridFSBucket.openUploadStream',
|
||||
deprecatedOptions: ['disableMD5'],
|
||||
optionsIndex: 1
|
||||
},
|
||||
function(filename, options) {
|
||||
if (options) {
|
||||
options = shallowClone(options);
|
||||
} else {
|
||||
options = {};
|
||||
}
|
||||
if (!options.chunkSizeBytes) {
|
||||
options.chunkSizeBytes = this.s.options.chunkSizeBytes;
|
||||
}
|
||||
return new GridFSBucketWriteStream(this, filename, options);
|
||||
}
|
||||
if (!options.chunkSizeBytes) {
|
||||
options.chunkSizeBytes = this.s.options.chunkSizeBytes;
|
||||
}
|
||||
return new GridFSBucketWriteStream(this, filename, options);
|
||||
};
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns a writable stream (GridFSBucketWriteStream) for writing
|
||||
@@ -107,25 +115,32 @@ GridFSBucket.prototype.openUploadStream = function(filename, options) {
|
||||
* @param {object} [options.metadata] Optional object to store in the file document's `metadata` field
|
||||
* @param {string} [options.contentType] Optional string to store in the file document's `contentType` field
|
||||
* @param {array} [options.aliases] Optional array of strings to store in the file document's `aliases` field
|
||||
* @param {boolean} [options.disableMD5=false] If true, disables adding an md5 field to file data
|
||||
* @param {boolean} [options.disableMD5=false] **Deprecated** If true, disables adding an md5 field to file data
|
||||
* @return {GridFSBucketWriteStream}
|
||||
*/
|
||||
|
||||
GridFSBucket.prototype.openUploadStreamWithId = function(id, filename, options) {
|
||||
if (options) {
|
||||
options = shallowClone(options);
|
||||
} else {
|
||||
options = {};
|
||||
GridFSBucket.prototype.openUploadStreamWithId = deprecateOptions(
|
||||
{
|
||||
name: 'GridFSBucket.openUploadStreamWithId',
|
||||
deprecatedOptions: ['disableMD5'],
|
||||
optionsIndex: 2
|
||||
},
|
||||
function(id, filename, options) {
|
||||
if (options) {
|
||||
options = shallowClone(options);
|
||||
} else {
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (!options.chunkSizeBytes) {
|
||||
options.chunkSizeBytes = this.s.options.chunkSizeBytes;
|
||||
}
|
||||
|
||||
options.id = id;
|
||||
|
||||
return new GridFSBucketWriteStream(this, filename, options);
|
||||
}
|
||||
|
||||
if (!options.chunkSizeBytes) {
|
||||
options.chunkSizeBytes = this.s.options.chunkSizeBytes;
|
||||
}
|
||||
|
||||
options.id = id;
|
||||
|
||||
return new GridFSBucketWriteStream(this, filename, options);
|
||||
};
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns a readable stream (GridFSBucketReadStream) for streaming file
|
||||
|
||||
100
node_modules/mongodb/lib/gridfs-stream/upload.js
generated
vendored
100
node_modules/mongodb/lib/gridfs-stream/upload.js
generated
vendored
@@ -1,14 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
var core = require('../core');
|
||||
var crypto = require('crypto');
|
||||
var stream = require('stream');
|
||||
var util = require('util');
|
||||
var Buffer = require('safe-buffer').Buffer;
|
||||
|
||||
var ERROR_NAMESPACE_NOT_FOUND = 26;
|
||||
|
||||
module.exports = GridFSBucketWriteStream;
|
||||
const MONGODB_ERROR_CODES = require('../error_codes').MONGODB_ERROR_CODES;
|
||||
const core = require('../core');
|
||||
const crypto = require('crypto');
|
||||
const stream = require('stream');
|
||||
const util = require('util');
|
||||
const Buffer = require('safe-buffer').Buffer;
|
||||
const deprecateOptions = require('../utils').deprecateOptions;
|
||||
|
||||
/**
|
||||
* A writable stream that enables you to write buffers to GridFS.
|
||||
@@ -22,49 +20,58 @@ module.exports = GridFSBucketWriteStream;
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {string|number|object} [options.id] Custom file id for the GridFS file.
|
||||
* @param {number} [options.chunkSizeBytes] The chunk size to use, in bytes
|
||||
* @param {number} [options.w] The write concern
|
||||
* @param {number} [options.wtimeout] The write concern timeout
|
||||
* @param {number} [options.j] The journal write concern
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {boolean} [options.disableMD5=false] If true, disables adding an md5 field to file data
|
||||
* @fires GridFSBucketWriteStream#error
|
||||
* @fires GridFSBucketWriteStream#finish
|
||||
*/
|
||||
|
||||
function GridFSBucketWriteStream(bucket, filename, options) {
|
||||
options = options || {};
|
||||
this.bucket = bucket;
|
||||
this.chunks = bucket.s._chunksCollection;
|
||||
this.filename = filename;
|
||||
this.files = bucket.s._filesCollection;
|
||||
this.options = options;
|
||||
// Signals the write is all done
|
||||
this.done = false;
|
||||
const GridFSBucketWriteStream = deprecateOptions(
|
||||
{
|
||||
name: 'GridFSBucketWriteStream',
|
||||
deprecatedOptions: ['disableMD5'],
|
||||
optionsIndex: 2
|
||||
},
|
||||
function(bucket, filename, options) {
|
||||
options = options || {};
|
||||
stream.Writable.call(this, options);
|
||||
this.bucket = bucket;
|
||||
this.chunks = bucket.s._chunksCollection;
|
||||
this.filename = filename;
|
||||
this.files = bucket.s._filesCollection;
|
||||
this.options = options;
|
||||
// Signals the write is all done
|
||||
this.done = false;
|
||||
|
||||
this.id = options.id ? options.id : core.BSON.ObjectId();
|
||||
this.chunkSizeBytes = this.options.chunkSizeBytes;
|
||||
this.bufToStore = Buffer.alloc(this.chunkSizeBytes);
|
||||
this.length = 0;
|
||||
this.md5 = !options.disableMD5 && crypto.createHash('md5');
|
||||
this.n = 0;
|
||||
this.pos = 0;
|
||||
this.state = {
|
||||
streamEnd: false,
|
||||
outstandingRequests: 0,
|
||||
errored: false,
|
||||
aborted: false,
|
||||
promiseLibrary: this.bucket.s.promiseLibrary
|
||||
};
|
||||
this.id = options.id ? options.id : core.BSON.ObjectId();
|
||||
this.chunkSizeBytes = this.options.chunkSizeBytes;
|
||||
this.bufToStore = Buffer.alloc(this.chunkSizeBytes);
|
||||
this.length = 0;
|
||||
this.md5 = !options.disableMD5 && crypto.createHash('md5');
|
||||
this.n = 0;
|
||||
this.pos = 0;
|
||||
this.state = {
|
||||
streamEnd: false,
|
||||
outstandingRequests: 0,
|
||||
errored: false,
|
||||
aborted: false,
|
||||
promiseLibrary: this.bucket.s.promiseLibrary
|
||||
};
|
||||
|
||||
if (!this.bucket.s.calledOpenUploadStream) {
|
||||
this.bucket.s.calledOpenUploadStream = true;
|
||||
if (!this.bucket.s.calledOpenUploadStream) {
|
||||
this.bucket.s.calledOpenUploadStream = true;
|
||||
|
||||
var _this = this;
|
||||
checkIndexes(this, function() {
|
||||
_this.bucket.s.checkedIndexes = true;
|
||||
_this.bucket.emit('index');
|
||||
});
|
||||
var _this = this;
|
||||
checkIndexes(this, function() {
|
||||
_this.bucket.s.checkedIndexes = true;
|
||||
_this.bucket.emit('index');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
util.inherits(GridFSBucketWriteStream, stream.Writable);
|
||||
|
||||
@@ -208,7 +215,7 @@ function checkChunksIndex(_this, callback) {
|
||||
_this.chunks.listIndexes().toArray(function(error, indexes) {
|
||||
if (error) {
|
||||
// Collection doesn't exist so create index
|
||||
if (error.code === ERROR_NAMESPACE_NOT_FOUND) {
|
||||
if (error.code === MONGODB_ERROR_CODES.NamespaceNotFound) {
|
||||
var index = { files_id: 1, n: 1 };
|
||||
_this.chunks.createIndex(index, { background: false, unique: true }, function(error) {
|
||||
if (error) {
|
||||
@@ -282,6 +289,7 @@ function checkDone(_this, callback) {
|
||||
return __handleError(_this, error, callback);
|
||||
}
|
||||
_this.emit('finish', filesDoc);
|
||||
_this.emit('close');
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -306,7 +314,7 @@ function checkIndexes(_this, callback) {
|
||||
_this.files.listIndexes().toArray(function(error, indexes) {
|
||||
if (error) {
|
||||
// Collection doesn't exist so create index
|
||||
if (error.code === ERROR_NAMESPACE_NOT_FOUND) {
|
||||
if (error.code === MONGODB_ERROR_CODES.NamespaceNotFound) {
|
||||
var index = { filename: 1, uploadDate: 1 };
|
||||
_this.files.createIndex(index, { background: false }, function(error) {
|
||||
if (error) {
|
||||
@@ -536,3 +544,5 @@ function checkAborted(_this, callback) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = GridFSBucketWriteStream;
|
||||
|
||||
23
node_modules/mongodb/lib/gridfs/grid_store.js
generated
vendored
23
node_modules/mongodb/lib/gridfs/grid_store.js
generated
vendored
@@ -73,10 +73,11 @@ const deprecationFn = deprecate(() => {},
|
||||
* @param {string} [filename] optional filename for this file, no unique constrain on the field
|
||||
* @param {string} mode set the mode for this file.
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {(number|string)} [options.w] The write concern.
|
||||
* @param {number} [options.wtimeout] The write concern timeout.
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern.
|
||||
* @param {boolean} [options.fsync=false] Specify a file sync write concern.
|
||||
* @param {(number|string)} [options.w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @param {number} [options.wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @param {boolean} [options.j=false] **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @param {boolean} [options.fsync=false] **Deprecated** Specify a file sync write concern. Use writeConcern instead.
|
||||
* @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
|
||||
* @param {string} [options.root] Root collection to use. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**.
|
||||
* @param {string} [options.content_type] MIME type of the file. Defaults to **{GridStore.DEFAULT_CONTENT_TYPE}**.
|
||||
* @param {number} [options.chunk_size=261120] Size for the chunk. Defaults to **{Chunk.DEFAULT_CHUNK_SIZE}**.
|
||||
@@ -153,6 +154,7 @@ var GridStore = function GridStore(db, id, filename, mode, options) {
|
||||
},
|
||||
set: function(value) {
|
||||
if (!(this.mode[0] === 'w' && this.position === 0 && this.uploadDate == null)) {
|
||||
// eslint-disable-next-line no-self-assign
|
||||
this.internalChunkSize = this.internalChunkSize;
|
||||
} else {
|
||||
this.internalChunkSize = value;
|
||||
@@ -1571,12 +1573,13 @@ var _writeNormal = function(self, data, close, options, callback) {
|
||||
* @ignore
|
||||
*/
|
||||
var _setWriteConcernHash = function(options) {
|
||||
const baseOptions = Object.assign(options, options.writeConcern);
|
||||
var finalOptions = {};
|
||||
if (options.w != null) finalOptions.w = options.w;
|
||||
if (options.journal === true) finalOptions.j = options.journal;
|
||||
if (options.j === true) finalOptions.j = options.j;
|
||||
if (options.fsync === true) finalOptions.fsync = options.fsync;
|
||||
if (options.wtimeout != null) finalOptions.wtimeout = options.wtimeout;
|
||||
if (baseOptions.w != null) finalOptions.w = baseOptions.w;
|
||||
if (baseOptions.journal === true) finalOptions.j = baseOptions.journal;
|
||||
if (baseOptions.j === true) finalOptions.j = baseOptions.j;
|
||||
if (baseOptions.fsync === true) finalOptions.fsync = baseOptions.fsync;
|
||||
if (baseOptions.wtimeout != null) finalOptions.wtimeout = baseOptions.wtimeout;
|
||||
return finalOptions;
|
||||
};
|
||||
|
||||
@@ -1590,6 +1593,7 @@ var _getWriteConcern = function(self, options) {
|
||||
|
||||
// Local options verification
|
||||
if (
|
||||
options.writeConcern != null ||
|
||||
options.w != null ||
|
||||
typeof options.j === 'boolean' ||
|
||||
typeof options.journal === 'boolean' ||
|
||||
@@ -1601,6 +1605,7 @@ var _getWriteConcern = function(self, options) {
|
||||
} else if (typeof options.safe === 'boolean') {
|
||||
finalOptions = { w: options.safe ? 1 : 0 };
|
||||
} else if (
|
||||
self.options.writeConcern != null ||
|
||||
self.options.w != null ||
|
||||
typeof self.options.j === 'boolean' ||
|
||||
typeof self.options.journal === 'boolean' ||
|
||||
|
||||
328
node_modules/mongodb/lib/mongo_client.js
generated
vendored
328
node_modules/mongodb/lib/mongo_client.js
generated
vendored
@@ -5,6 +5,7 @@ const Db = require('./db');
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
const inherits = require('util').inherits;
|
||||
const MongoError = require('./core').MongoError;
|
||||
const ValidServerApiVersions = require('./core').ValidServerApiVersions;
|
||||
const deprecate = require('util').deprecate;
|
||||
const WriteConcern = require('./write_concern');
|
||||
const MongoDBNamespace = require('./utils').MongoDBNamespace;
|
||||
@@ -71,103 +72,164 @@ const validOptions = require('./operations/connect').validOptions;
|
||||
* @property {string} [platform] Optional platform information
|
||||
*/
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @typedef AutoEncryptionOptions
|
||||
* @property {MongoClient} [keyVaultClient] A `MongoClient` used to fetch keys from a key vault
|
||||
* @property {string} [keyVaultNamespace] The namespace where keys are stored in the key vault
|
||||
* @property {object} [kmsProviders] Configuration options that are used by specific KMS providers during key generation, encryption, and decryption.
|
||||
* @property {object} [schemaMap] A map of namespaces to a local JSON schema for encryption
|
||||
*
|
||||
* > **NOTE**: Supplying options.schemaMap provides more security than relying on JSON Schemas obtained from the server.
|
||||
* > It protects against a malicious server advertising a false JSON Schema, which could trick the client into sending decrypted data that should be encrypted.
|
||||
* > Schemas supplied in the schemaMap only apply to configuring automatic encryption for client side encryption.
|
||||
* > Other validation rules in the JSON schema will not be enforced by the driver and will result in an error.
|
||||
*
|
||||
* @property {object} [options] An optional hook to catch logging messages from the underlying encryption engine
|
||||
* @property {object} [extraOptions]
|
||||
* @property {boolean} [bypassAutoEncryption]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} MongoClientOptions
|
||||
* @property {number} [poolSize] (**default**: 5) The maximum size of the individual server pool
|
||||
* @property {boolean} [ssl] (**default**: false) Enable SSL connection. *deprecated* use `tls` variants
|
||||
* @property {boolean} [sslValidate] (**default**: false) Validate mongod server certificate against Certificate Authority
|
||||
* @property {buffer} [sslCA] (**default**: undefined) SSL Certificate store binary buffer *deprecated* use `tls` variants
|
||||
* @property {buffer} [sslCert] (**default**: undefined) SSL Certificate binary buffer *deprecated* use `tls` variants
|
||||
* @property {buffer} [sslKey] (**default**: undefined) SSL Key file binary buffer *deprecated* use `tls` variants
|
||||
* @property {string} [sslPass] (**default**: undefined) SSL Certificate pass phrase *deprecated* use `tls` variants
|
||||
* @property {buffer} [sslCRL] (**default**: undefined) SSL Certificate revocation list binary buffer *deprecated* use `tls` variants
|
||||
* @property {boolean|function} [checkServerIdentity] (**default**: true) Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function. *deprecated* use `tls` variants
|
||||
* @property {boolean} [tls] (**default**: false) Enable TLS connections
|
||||
* @property {boolean} [tlsInsecure] (**default**: false) Relax TLS constraints, disabling validation
|
||||
* @property {string} [tlsCAFile] A path to file with either a single or bundle of certificate authorities to be considered trusted when making a TLS connection
|
||||
* @property {string} [tlsCertificateKeyFile] A path to the client certificate file or the client private key file; in the case that they both are needed, the files should be concatenated
|
||||
* @property {string} [tlsCertificateKeyFilePassword] The password to decrypt the client private key to be used for TLS connections
|
||||
* @property {boolean} [tlsAllowInvalidCertificates] Specifies whether or not the driver should error when the server’s TLS certificate is invalid
|
||||
* @property {boolean} [tlsAllowInvalidHostnames] Specifies whether or not the driver should error when there is a mismatch between the server’s hostname and the hostname specified by the TLS certificate
|
||||
* @property {boolean} [autoReconnect] (**default**: true) Enable autoReconnect for single server instances
|
||||
* @property {boolean} [noDelay] (**default**: true) TCP Connection no delay
|
||||
* @property {boolean} [keepAlive] (**default**: true) TCP Connection keep alive enabled
|
||||
* @property {number} [keepAliveInitialDelay] (**default**: 120000) The number of milliseconds to wait before initiating keepAlive on the TCP socket
|
||||
* @property {number} [connectTimeoutMS] (**default**: 10000) How long to wait for a connection to be established before timing out
|
||||
* @property {number} [socketTimeoutMS] (**default**: 0) How long a send or receive on a socket can take before timing out
|
||||
* @property {number} [family] Version of IP stack. Can be 4, 6 or null (default). If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
|
||||
* @property {number} [reconnectTries] (**default**: 30) Server attempt to reconnect #times
|
||||
* @property {number} [reconnectInterval] (**default**: 1000) Server will wait # milliseconds between retries
|
||||
* @property {boolean} [ha] (**default**: true) Control if high availability monitoring runs for Replicaset or Mongos proxies
|
||||
* @property {number} [haInterval] (**default**: 10000) The High availability period for replicaset inquiry
|
||||
* @property {string} [replicaSet] (**default**: undefined) The Replicaset set name
|
||||
* @property {number} [secondaryAcceptableLatencyMS] (**default**: 15) Cutoff latency point in MS for Replicaset member selection
|
||||
* @property {number} [acceptableLatencyMS] (**default**: 15) Cutoff latency point in MS for Mongos proxies selection
|
||||
* @property {boolean} [connectWithNoPrimary] (**default**: false) Sets if the driver should connect even if no primary is available
|
||||
* @property {string} [authSource] (**default**: undefined) Define the database to authenticate against
|
||||
* @property {(number|string)} [w] **Deprecated** The write concern. Use writeConcern instead.
|
||||
* @property {number} [wtimeout] **Deprecated** The write concern timeout. Use writeConcern instead.
|
||||
* @property {boolean} [j] (**default**: false) **Deprecated** Specify a journal write concern. Use writeConcern instead.
|
||||
* @property {boolean} [fsync] (**default**: false) **Deprecated** Specify a file sync write concern. Use writeConcern instead.
|
||||
* @property {object|WriteConcern} [writeConcern] Specify write concern settings.
|
||||
* @property {boolean} [forceServerObjectId] (**default**: false) Force server to assign _id values instead of driver
|
||||
* @property {boolean} [serializeFunctions] (**default**: false) Serialize functions on any object
|
||||
* @property {Boolean} [ignoreUndefined] (**default**: false) Specify if the BSON serializer should ignore undefined fields
|
||||
* @property {boolean} [raw] (**default**: false) Return document results as raw BSON buffers
|
||||
* @property {number} [bufferMaxEntries] (**default**: -1) Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited
|
||||
* @property {(ReadPreference|string)} [readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
|
||||
* @property {object} [pkFactory] A primary key factory object for generation of custom _id keys
|
||||
* @property {object} [promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
|
||||
* @property {object} [readConcern] Specify a read concern for the collection (only MongoDB 3.2 or higher supported)
|
||||
* @property {ReadConcernLevel} [readConcern.level] (**default**: {Level: 'local'}) Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
|
||||
* @property {number} [maxStalenessSeconds] (**default**: undefined) The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
|
||||
* @property {string} [loggerLevel] (**default**: undefined) The logging level (error/warn/info/debug)
|
||||
* @property {object} [logger] (**default**: undefined) Custom logger object
|
||||
* @property {boolean} [promoteValues] (**default**: true) Promotes BSON values to native types where possible, set to false to only receive wrapper types
|
||||
* @property {boolean} [promoteBuffers] (**default**: false) Promotes Binary BSON values to native Node Buffers
|
||||
* @property {boolean} [promoteLongs] (**default**: true) Promotes long values to number if they fit inside the 53 bits resolution
|
||||
* * @param {boolean} [bsonRegExp] (**default**: false) By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
||||
* @property {boolean} [domainsEnabled] (**default**: false) Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit
|
||||
* @property {object} [validateOptions] (**default**: false) Validate MongoClient passed in options for correctness
|
||||
* @property {string} [appname] (**default**: undefined) The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections
|
||||
* @property {string} [options.auth.user] (**default**: undefined) The username for auth
|
||||
* @property {string} [options.auth.password] (**default**: undefined) The password for auth
|
||||
* @property {string} [authMechanism] An authentication mechanism to use for connection authentication, see the {@link https://docs.mongodb.com/manual/reference/connection-string/#urioption.authMechanism|authMechanism} reference for supported options.
|
||||
* @property {object} [compression] Type of compression to use: snappy or zlib
|
||||
* @property {array} [readPreferenceTags] Read preference tags
|
||||
* @property {number} [numberOfRetries] (**default**: 5) The number of retries for a tailable cursor
|
||||
* @property {boolean} [auto_reconnect] (**default**: true) Enable auto reconnecting for single server instances
|
||||
* @property {boolean} [monitorCommands] (**default**: false) Enable command monitoring for this client
|
||||
* @property {string|ServerApi} [serverApi] (**default**: undefined) The server API version
|
||||
* @property {number} [minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
|
||||
* @property {boolean} [useNewUrlParser] (**default**: true) Determines whether or not to use the new url parser. Enables the new, spec-compliant, url parser shipped in the core driver. This url parser fixes a number of problems with the original parser, and aims to outright replace that parser in the near future. Defaults to true, and must be explicitly set to false to use the legacy url parser.
|
||||
* @property {boolean} [useUnifiedTopology] Enables the new unified topology layer
|
||||
* @property {number} [localThresholdMS] (**default**: 15) **Only applies to the unified topology** The size of the latency window for selecting among multiple suitable servers
|
||||
* @property {number} [serverSelectionTimeoutMS] (**default**: 30000) **Only applies to the unified topology** How long to block for server selection before throwing an error
|
||||
* @property {number} [heartbeatFrequencyMS] (**default**: 10000) **Only applies to the unified topology** The frequency with which topology updates are scheduled
|
||||
* @property {number} [maxPoolSize] (**default**: 10) **Only applies to the unified topology** The maximum number of connections that may be associated with a pool at a given time. This includes in use and available connections.
|
||||
* @property {number} [minPoolSize] (**default**: 0) **Only applies to the unified topology** The minimum number of connections that MUST exist at any moment in a single connection pool.
|
||||
* @property {number} [maxIdleTimeMS] **Only applies to the unified topology** The maximum amount of time a connection should remain idle in the connection pool before being marked idle. The default is infinity.
|
||||
* @property {number} [waitQueueTimeoutMS] (**default**: 0) **Only applies to the unified topology** The maximum amount of time operation execution should wait for a connection to become available. The default is 0 which means there is no limit.
|
||||
* @property {AutoEncryptionOptions} [autoEncryption] Optionally enable client side auto encryption.
|
||||
*
|
||||
* > Automatic encryption is an enterprise only feature that only applies to operations on a collection. Automatic encryption is not supported for operations on a database or view, and operations that are not bypassed will result in error
|
||||
* > (see [libmongocrypt: Auto Encryption Allow-List](https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#libmongocrypt-auto-encryption-allow-list)). To bypass automatic encryption for all operations, set bypassAutoEncryption=true in AutoEncryptionOpts.
|
||||
* >
|
||||
* > Automatic encryption requires the authenticated user to have the [listCollections privilege action](https://docs.mongodb.com/manual/reference/command/listCollections/#dbcmd.listCollections).
|
||||
* >
|
||||
* > If a MongoClient with a limited connection pool size (i.e a non-zero maxPoolSize) is configured with AutoEncryptionOptions, a separate internal MongoClient is created if any of the following are true:
|
||||
* > - AutoEncryptionOptions.keyVaultClient is not passed.
|
||||
* > - AutoEncryptionOptions.bypassAutomaticEncryption is false.
|
||||
* > If an internal MongoClient is created, it is configured with the same options as the parent MongoClient except minPoolSize is set to 0 and AutoEncryptionOptions is omitted.
|
||||
*
|
||||
* @property {DriverInfoOptions} [driverInfo] Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver
|
||||
* @property {boolean} [directConnection] (**default**: false) Enable directConnection
|
||||
* @property {function} [callback] The command result callback
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new MongoClient instance
|
||||
* @class
|
||||
* @constructor
|
||||
* @extends {EventEmitter}
|
||||
* @param {string} url The connection URI string
|
||||
* @param {object} [options] Optional settings
|
||||
* @param {number} [options.poolSize=5] The maximum size of the individual server pool
|
||||
* @param {boolean} [options.ssl=false] Enable SSL connection. *deprecated* use `tls` variants
|
||||
* @param {boolean} [options.sslValidate=false] Validate mongod server certificate against Certificate Authority
|
||||
* @param {buffer} [options.sslCA=undefined] SSL Certificate store binary buffer *deprecated* use `tls` variants
|
||||
* @param {buffer} [options.sslCert=undefined] SSL Certificate binary buffer *deprecated* use `tls` variants
|
||||
* @param {buffer} [options.sslKey=undefined] SSL Key file binary buffer *deprecated* use `tls` variants
|
||||
* @param {string} [options.sslPass=undefined] SSL Certificate pass phrase *deprecated* use `tls` variants
|
||||
* @param {buffer} [options.sslCRL=undefined] SSL Certificate revocation list binary buffer *deprecated* use `tls` variants
|
||||
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function. *deprecated* use `tls` variants
|
||||
* @param {boolean} [options.tls=false] Enable TLS connections
|
||||
* @param {boolean} [options.tlsInsecure=false] Relax TLS constraints, disabling validation
|
||||
* @param {string} [options.tlsCAFile] A path to file with either a single or bundle of certificate authorities to be considered trusted when making a TLS connection
|
||||
* @param {string} [options.tlsCertificateKeyFile] A path to the client certificate file or the client private key file; in the case that they both are needed, the files should be concatenated
|
||||
* @param {string} [options.tlsCertificateKeyFilePassword] The password to decrypt the client private key to be used for TLS connections
|
||||
* @param {boolean} [options.tlsAllowInvalidCertificates] Specifies whether or not the driver should error when the server’s TLS certificate is invalid
|
||||
* @param {boolean} [options.tlsAllowInvalidHostnames] Specifies whether or not the driver should error when there is a mismatch between the server’s hostname and the hostname specified by the TLS certificate
|
||||
* @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
|
||||
* @param {boolean} [options.noDelay=true] TCP Connection no delay
|
||||
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
|
||||
* @param {number} [options.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
|
||||
* @param {number} [options.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
|
||||
* @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
|
||||
* If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
|
||||
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
|
||||
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
|
||||
* @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies
|
||||
* @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
|
||||
* @param {string} [options.replicaSet=undefined] The Replicaset set name
|
||||
* @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
|
||||
* @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection
|
||||
* @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
|
||||
* @param {string} [options.authSource=undefined] Define the database to authenticate against
|
||||
* @param {(number|string)} [options.w] The write concern
|
||||
* @param {number} [options.wtimeout] The write concern timeout
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern
|
||||
* @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object
|
||||
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
|
||||
* @param {boolean} [options.raw=false] Return document results as raw BSON buffers
|
||||
* @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited
|
||||
* @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
|
||||
* @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys
|
||||
* @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
|
||||
* @param {object} [options.readConcern] Specify a read concern for the collection (only MongoDB 3.2 or higher supported)
|
||||
* @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
|
||||
* @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
|
||||
* @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
|
||||
* @param {object} [options.logger=undefined] Custom logger object
|
||||
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types
|
||||
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers
|
||||
* @param {boolean} [options.promoteLongs=true] Promotes long values to number if they fit inside the 53 bits resolution
|
||||
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit
|
||||
* @param {object} [options.validateOptions=false] Validate MongoClient passed in options for correctness
|
||||
* @param {string} [options.appname=undefined] The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections
|
||||
* @param {string} [options.auth.user=undefined] The username for auth
|
||||
* @param {string} [options.auth.password=undefined] The password for auth
|
||||
* @param {string} [options.authMechanism=undefined] Mechanism for authentication: MDEFAULT, GSSAPI, PLAIN, MONGODB-X509, or SCRAM-SHA-1
|
||||
* @param {object} [options.compression] Type of compression to use: snappy or zlib
|
||||
* @param {boolean} [options.fsync=false] Specify a file sync write concern
|
||||
* @param {array} [options.readPreferenceTags] Read preference tags
|
||||
* @param {number} [options.numberOfRetries=5] The number of retries for a tailable cursor
|
||||
* @param {boolean} [options.auto_reconnect=true] Enable auto reconnecting for single server instances
|
||||
* @param {boolean} [options.monitorCommands=false] Enable command monitoring for this client
|
||||
* @param {number} [options.minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
|
||||
* @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.
|
||||
* @param {boolean} [options.useUnifiedTopology] Enables the new unified topology layer
|
||||
* @param {Number} [options.localThresholdMS=15] **Only applies to the unified topology** The size of the latency window for selecting among multiple suitable servers
|
||||
* @param {Number} [options.serverSelectionTimeoutMS=30000] **Only applies to the unified topology** How long to block for server selection before throwing an error
|
||||
* @param {Number} [options.heartbeatFrequencyMS=10000] **Only applies to the unified topology** The frequency with which topology updates are scheduled
|
||||
* @param {number} [options.maxPoolSize=10] **Only applies to the unified topology** The maximum number of connections that may be associated with a pool at a given time. This includes in use and available connections.
|
||||
* @param {number} [options.minPoolSize=0] **Only applies to the unified topology** The minimum number of connections that MUST exist at any moment in a single connection pool.
|
||||
* @param {number} [options.maxIdleTimeMS] **Only applies to the unified topology** The maximum amount of time a connection should remain idle in the connection pool before being marked idle. The default is infinity.
|
||||
* @param {number} [options.waitQueueTimeoutMS=0] **Only applies to the unified topology** The maximum amount of time operation execution should wait for a connection to become available. The default is 0 which means there is no limit.
|
||||
* @param {AutoEncrypter~AutoEncryptionOptions} [options.autoEncryption] Optionally enable client side auto encryption
|
||||
* @param {DriverInfoOptions} [options.driverInfo] Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver
|
||||
* @param {MongoClient~connectCallback} [callback] The command result callback
|
||||
* @return {MongoClient} a MongoClient instance
|
||||
* @param {MongoClientOptions} [options] Optional settings
|
||||
*/
|
||||
function MongoClient(url, options) {
|
||||
options = options || {};
|
||||
if (!(this instanceof MongoClient)) return new MongoClient(url, options);
|
||||
// Set up event emitter
|
||||
EventEmitter.call(this);
|
||||
|
||||
if (options.autoEncryption) require('./encrypter'); // Does CSFLE lib check
|
||||
|
||||
if (options.serverApi) {
|
||||
const serverApiToValidate =
|
||||
typeof options.serverApi === 'string' ? { version: options.serverApi } : options.serverApi;
|
||||
const versionToValidate = serverApiToValidate && serverApiToValidate.version;
|
||||
if (!versionToValidate) {
|
||||
throw new MongoError(
|
||||
`Invalid \`serverApi\` property; must specify a version from the following enum: ["${ValidServerApiVersions.join(
|
||||
'", "'
|
||||
)}"]`
|
||||
);
|
||||
}
|
||||
if (!ValidServerApiVersions.some(v => v === versionToValidate)) {
|
||||
throw new MongoError(
|
||||
`Invalid server API version=${versionToValidate}; must be in the following enum: ["${ValidServerApiVersions.join(
|
||||
'", "'
|
||||
)}"]`
|
||||
);
|
||||
}
|
||||
options.serverApi = serverApiToValidate;
|
||||
}
|
||||
|
||||
// The internal state
|
||||
this.s = {
|
||||
url: url,
|
||||
options: options || {},
|
||||
url,
|
||||
options,
|
||||
promiseLibrary: (options && options.promiseLibrary) || Promise,
|
||||
dbCache: new Map(),
|
||||
sessions: new Set(),
|
||||
writeConcern: WriteConcern.fromOptions(options),
|
||||
readPreference: ReadPreference.fromOptions(options) || ReadPreference.primary,
|
||||
namespace: new MongoDBNamespace('admin')
|
||||
};
|
||||
}
|
||||
@@ -187,7 +249,7 @@ Object.defineProperty(MongoClient.prototype, 'writeConcern', {
|
||||
Object.defineProperty(MongoClient.prototype, 'readPreference', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return ReadPreference.primary;
|
||||
return this.s.readPreference;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -265,13 +327,13 @@ MongoClient.prototype.close = function(force, callback) {
|
||||
}
|
||||
|
||||
client.topology.close(force, err => {
|
||||
const autoEncrypter = client.topology.s.options.autoEncrypter;
|
||||
if (!autoEncrypter) {
|
||||
completeClose(err);
|
||||
return;
|
||||
const encrypter = client.topology.s.options.encrypter;
|
||||
if (encrypter) {
|
||||
return encrypter.close(client, force, err2 => {
|
||||
completeClose(err || err2);
|
||||
});
|
||||
}
|
||||
|
||||
autoEncrypter.teardown(force, err2 => completeClose(err || err2));
|
||||
completeClose(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -326,17 +388,18 @@ MongoClient.prototype.db = function(dbName, options) {
|
||||
* Check if MongoClient is connected
|
||||
*
|
||||
* @method
|
||||
* @deprecated
|
||||
* @param {object} [options] Optional settings.
|
||||
* @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
|
||||
* @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
|
||||
* @return {boolean}
|
||||
*/
|
||||
MongoClient.prototype.isConnected = function(options) {
|
||||
MongoClient.prototype.isConnected = deprecate(function(options) {
|
||||
options = options || {};
|
||||
|
||||
if (!this.topology) return false;
|
||||
return this.topology.isConnected(options);
|
||||
};
|
||||
}, 'isConnected is deprecated and will be removed in the next major version');
|
||||
|
||||
/**
|
||||
* Connect to MongoDB using a url as documented at
|
||||
@@ -348,84 +411,7 @@ MongoClient.prototype.isConnected = function(options) {
|
||||
* @method
|
||||
* @static
|
||||
* @param {string} url The connection URI string
|
||||
* @param {object} [options] Optional settings
|
||||
* @param {number} [options.poolSize=5] The maximum size of the individual server pool
|
||||
* @param {boolean} [options.ssl=false] Enable SSL connection. *deprecated* use `tls` variants
|
||||
* @param {boolean} [options.sslValidate=false] Validate mongod server certificate against Certificate Authority
|
||||
* @param {buffer} [options.sslCA=undefined] SSL Certificate store binary buffer *deprecated* use `tls` variants
|
||||
* @param {buffer} [options.sslCert=undefined] SSL Certificate binary buffer *deprecated* use `tls` variants
|
||||
* @param {buffer} [options.sslKey=undefined] SSL Key file binary buffer *deprecated* use `tls` variants
|
||||
* @param {string} [options.sslPass=undefined] SSL Certificate pass phrase *deprecated* use `tls` variants
|
||||
* @param {buffer} [options.sslCRL=undefined] SSL Certificate revocation list binary buffer *deprecated* use `tls` variants
|
||||
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function. *deprecated* use `tls` variants
|
||||
* @param {boolean} [options.tls=false] Enable TLS connections
|
||||
* @param {boolean} [options.tlsInsecure=false] Relax TLS constraints, disabling validation
|
||||
* @param {string} [options.tlsCAFile] A path to file with either a single or bundle of certificate authorities to be considered trusted when making a TLS connection
|
||||
* @param {string} [options.tlsCertificateKeyFile] A path to the client certificate file or the client private key file; in the case that they both are needed, the files should be concatenated
|
||||
* @param {string} [options.tlsCertificateKeyFilePassword] The password to decrypt the client private key to be used for TLS connections
|
||||
* @param {boolean} [options.tlsAllowInvalidCertificates] Specifies whether or not the driver should error when the server’s TLS certificate is invalid
|
||||
* @param {boolean} [options.tlsAllowInvalidHostnames] Specifies whether or not the driver should error when there is a mismatch between the server’s hostname and the hostname specified by the TLS certificate
|
||||
* @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
|
||||
* @param {boolean} [options.noDelay=true] TCP Connection no delay
|
||||
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
|
||||
* @param {number} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
|
||||
* @param {number} [options.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
|
||||
* @param {number} [options.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
|
||||
* @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
|
||||
* If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
|
||||
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
|
||||
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
|
||||
* @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies
|
||||
* @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
|
||||
* @param {string} [options.replicaSet=undefined] The Replicaset set name
|
||||
* @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
|
||||
* @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection
|
||||
* @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
|
||||
* @param {string} [options.authSource=undefined] Define the database to authenticate against
|
||||
* @param {(number|string)} [options.w] The write concern
|
||||
* @param {number} [options.wtimeout] The write concern timeout
|
||||
* @param {boolean} [options.j=false] Specify a journal write concern
|
||||
* @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver
|
||||
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object
|
||||
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
|
||||
* @param {boolean} [options.raw=false] Return document results as raw BSON buffers
|
||||
* @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited
|
||||
* @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
|
||||
* @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys
|
||||
* @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
|
||||
* @param {object} [options.readConcern] Specify a read concern for the collection (only MongoDB 3.2 or higher supported)
|
||||
* @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
|
||||
* @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
|
||||
* @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
|
||||
* @param {object} [options.logger=undefined] Custom logger object
|
||||
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types
|
||||
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers
|
||||
* @param {boolean} [options.promoteLongs=true] Promotes long values to number if they fit inside the 53 bits resolution
|
||||
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit
|
||||
* @param {object} [options.validateOptions=false] Validate MongoClient passed in options for correctness
|
||||
* @param {string} [options.appname=undefined] The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections
|
||||
* @param {string} [options.auth.user=undefined] The username for auth
|
||||
* @param {string} [options.auth.password=undefined] The password for auth
|
||||
* @param {string} [options.authMechanism=undefined] Mechanism for authentication: MDEFAULT, GSSAPI, PLAIN, MONGODB-X509, or SCRAM-SHA-1
|
||||
* @param {object} [options.compression] Type of compression to use: snappy or zlib
|
||||
* @param {boolean} [options.fsync=false] Specify a file sync write concern
|
||||
* @param {array} [options.readPreferenceTags] Read preference tags
|
||||
* @param {number} [options.numberOfRetries=5] The number of retries for a tailable cursor
|
||||
* @param {boolean} [options.auto_reconnect=true] Enable auto reconnecting for single server instances
|
||||
* @param {boolean} [options.monitorCommands=false] Enable command monitoring for this client
|
||||
* @param {number} [options.minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
|
||||
* @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.
|
||||
* @param {boolean} [options.useUnifiedTopology] Enables the new unified topology layer
|
||||
* @param {Number} [options.localThresholdMS=15] **Only applies to the unified topology** The size of the latency window for selecting among multiple suitable servers
|
||||
* @param {Number} [options.serverSelectionTimeoutMS=30000] **Only applies to the unified topology** How long to block for server selection before throwing an error
|
||||
* @param {Number} [options.heartbeatFrequencyMS=10000] **Only applies to the unified topology** The frequency with which topology updates are scheduled
|
||||
* @param {number} [options.maxPoolSize=10] **Only applies to the unified topology** The maximum number of connections that may be associated with a pool at a given time. This includes in use and available connections.
|
||||
* @param {number} [options.minPoolSize=0] **Only applies to the unified topology** The minimum number of connections that MUST exist at any moment in a single connection pool.
|
||||
* @param {number} [options.maxIdleTimeMS] **Only applies to the unified topology** The maximum amount of time a connection should remain idle in the connection pool before being marked idle. The default is infinity.
|
||||
* @param {number} [options.waitQueueTimeoutMS=0] **Only applies to the unified topology** The maximum amount of time operation execution should wait for a connection to become available. The default is 0 which means there is no limit.
|
||||
* @param {AutoEncrypter~AutoEncryptionOptions} [options.autoEncryption] Optionally enable client side auto encryption
|
||||
* @param {DriverInfoOptions} [options.driverInfo] Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver
|
||||
* @param {MongoClient~connectCallback} [callback] The command result callback
|
||||
* @param {MongoClientOptions} [options] Optional settings
|
||||
* @return {Promise<MongoClient>} returns Promise if no callback passed
|
||||
*/
|
||||
MongoClient.connect = function(url, options, callback) {
|
||||
@@ -452,10 +438,6 @@ MongoClient.prototype.startSession = function(options) {
|
||||
throw new MongoError('Must connect to a server before calling this method');
|
||||
}
|
||||
|
||||
if (!this.topology.hasSessionSupport()) {
|
||||
throw new MongoError('Current topology does not support sessions');
|
||||
}
|
||||
|
||||
return this.topology.startSession(options, this.s.options);
|
||||
};
|
||||
|
||||
|
||||
7
node_modules/mongodb/lib/operations/add_user.js
generated
vendored
7
node_modules/mongodb/lib/operations/add_user.js
generated
vendored
@@ -6,6 +6,7 @@ const defineAspects = require('./operation').defineAspects;
|
||||
const crypto = require('crypto');
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const toError = require('../utils').toError;
|
||||
const emitWarning = require('../utils').emitWarning;
|
||||
|
||||
class AddUserOperation extends CommandOperation {
|
||||
constructor(db, username, password, options) {
|
||||
@@ -22,12 +23,14 @@ class AddUserOperation extends CommandOperation {
|
||||
const options = this.options;
|
||||
|
||||
// Get additional values
|
||||
let roles = Array.isArray(options.roles) ? options.roles : [];
|
||||
let roles = [];
|
||||
if (Array.isArray(options.roles)) roles = options.roles;
|
||||
if (typeof options.roles === 'string') roles = [options.roles];
|
||||
|
||||
// If not roles defined print deprecated message
|
||||
// TODO: handle deprecation properly
|
||||
if (roles.length === 0) {
|
||||
console.log('Creating a user without roles is deprecated in MongoDB >= 2.6');
|
||||
emitWarning('Creating a user without roles is deprecated in MongoDB >= 2.6');
|
||||
}
|
||||
|
||||
// Check the db name and add roles if needed
|
||||
|
||||
2
node_modules/mongodb/lib/operations/admin_ops.js
generated
vendored
2
node_modules/mongodb/lib/operations/admin_ops.js
generated
vendored
@@ -39,7 +39,7 @@ function validateCollection(admin, collectionName, options, callback) {
|
||||
|
||||
// Decorate command with extra options
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (options.hasOwnProperty(keys[i]) && keys[i] !== 'session') {
|
||||
if (Object.prototype.hasOwnProperty.call(options, keys[i]) && keys[i] !== 'session') {
|
||||
command[keys[i]] = options[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
12
node_modules/mongodb/lib/operations/aggregate.js
generated
vendored
12
node_modules/mongodb/lib/operations/aggregate.js
generated
vendored
@@ -37,10 +37,8 @@ class AggregateOperation extends CommandOperationV2 {
|
||||
this.readPreference = ReadPreference.primary;
|
||||
}
|
||||
|
||||
if (options.explain && (this.readConcern || this.writeConcern)) {
|
||||
throw new MongoError(
|
||||
'"explain" cannot be used on an aggregate call with readConcern/writeConcern'
|
||||
);
|
||||
if (this.explain && this.writeConcern) {
|
||||
throw new MongoError('"explain" cannot be used on an aggregate call with writeConcern');
|
||||
}
|
||||
|
||||
if (options.cursor != null && typeof options.cursor !== 'object') {
|
||||
@@ -83,9 +81,8 @@ class AggregateOperation extends CommandOperationV2 {
|
||||
command.hint = options.hint;
|
||||
}
|
||||
|
||||
if (options.explain) {
|
||||
if (this.explain) {
|
||||
options.full = false;
|
||||
command.explain = options.explain;
|
||||
}
|
||||
|
||||
command.cursor = options.cursor || {};
|
||||
@@ -100,7 +97,8 @@ class AggregateOperation extends CommandOperationV2 {
|
||||
defineAspects(AggregateOperation, [
|
||||
Aspect.READ_OPERATION,
|
||||
Aspect.RETRYABLE,
|
||||
Aspect.EXECUTE_WITH_SELECTION
|
||||
Aspect.EXECUTE_WITH_SELECTION,
|
||||
Aspect.EXPLAINABLE
|
||||
]);
|
||||
|
||||
module.exports = AggregateOperation;
|
||||
|
||||
25
node_modules/mongodb/lib/operations/bulk_write.js
generated
vendored
25
node_modules/mongodb/lib/operations/bulk_write.js
generated
vendored
@@ -70,31 +70,6 @@ class BulkWriteOperation extends OperationBase {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
r.insertedCount = r.nInserted;
|
||||
r.matchedCount = r.nMatched;
|
||||
r.modifiedCount = r.nModified || 0;
|
||||
r.deletedCount = r.nRemoved;
|
||||
r.upsertedCount = r.getUpsertedIds().length;
|
||||
r.upsertedIds = {};
|
||||
r.insertedIds = {};
|
||||
|
||||
// Update the n
|
||||
r.n = r.insertedCount;
|
||||
|
||||
// Inserted documents
|
||||
const inserted = r.getInsertedIds();
|
||||
// Map inserted ids
|
||||
for (let i = 0; i < inserted.length; i++) {
|
||||
r.insertedIds[inserted[i].index] = inserted[i]._id;
|
||||
}
|
||||
|
||||
// Upserted documents
|
||||
const upserted = r.getUpsertedIds();
|
||||
// Map upserted ids
|
||||
for (let i = 0; i < upserted.length; i++) {
|
||||
r.upsertedIds[upserted[i].index] = upserted[i]._id;
|
||||
}
|
||||
|
||||
// Return the results
|
||||
callback(null, r);
|
||||
});
|
||||
|
||||
23
node_modules/mongodb/lib/operations/collection_ops.js
generated
vendored
23
node_modules/mongodb/lib/operations/collection_ops.js
generated
vendored
@@ -8,13 +8,11 @@ const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
|
||||
const ensureIndexDb = require('./db_ops').ensureIndex;
|
||||
const evaluate = require('./db_ops').evaluate;
|
||||
const executeCommand = require('./db_ops').executeCommand;
|
||||
const resolveReadPreference = require('../utils').resolveReadPreference;
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const indexInformationDb = require('./db_ops').indexInformation;
|
||||
const Long = require('../core').BSON.Long;
|
||||
const MongoError = require('../core').MongoError;
|
||||
const ReadPreference = require('../core').ReadPreference;
|
||||
const toError = require('../utils').toError;
|
||||
const insertDocuments = require('./common_functions').insertDocuments;
|
||||
const updateDocuments = require('./common_functions').updateDocuments;
|
||||
|
||||
@@ -52,24 +50,6 @@ const updateDocuments = require('./common_functions').updateDocuments;
|
||||
const groupFunction =
|
||||
'function () {\nvar c = db[ns].find(condition);\nvar map = new Map();\nvar reduce_function = reduce;\n\nwhile (c.hasNext()) {\nvar obj = c.next();\nvar key = {};\n\nfor (var i = 0, len = keys.length; i < len; ++i) {\nvar k = keys[i];\nkey[k] = obj[k];\n}\n\nvar aggObj = map.get(key);\n\nif (aggObj == null) {\nvar newObj = Object.extend({}, key);\naggObj = Object.extend(newObj, initial);\nmap.put(key, aggObj);\n}\n\nreduce_function(obj, aggObj);\n}\n\nreturn { "result": map.values() };\n}';
|
||||
|
||||
// Check the update operation to ensure it has atomic operators.
|
||||
function checkForAtomicOperators(update) {
|
||||
if (Array.isArray(update)) {
|
||||
return update.reduce((err, u) => err || checkForAtomicOperators(u), null);
|
||||
}
|
||||
|
||||
const keys = Object.keys(update);
|
||||
|
||||
// same errors as the server would give for update doc lacking atomic operators
|
||||
if (keys.length === 0) {
|
||||
return toError('The update operation document must contain at least one atomic operator.');
|
||||
}
|
||||
|
||||
if (keys[0][0] !== '$') {
|
||||
return toError('the update operation document must contain atomic operators.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an index on the db and collection.
|
||||
*
|
||||
@@ -188,7 +168,7 @@ function group(coll, keys, condition, initial, reduce, finalize, command, option
|
||||
|
||||
options = Object.assign({}, options);
|
||||
// Ensure we have the right read preference inheritance
|
||||
options.readPreference = resolveReadPreference(coll, options);
|
||||
options.readPreference = ReadPreference.resolve(coll, options);
|
||||
|
||||
// Do we have a readConcern specified
|
||||
decorateWithReadConcern(selector, coll, options);
|
||||
@@ -361,7 +341,6 @@ function save(coll, doc, options, callback) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkForAtomicOperators,
|
||||
createIndex,
|
||||
createIndexes,
|
||||
ensureIndex,
|
||||
|
||||
10
node_modules/mongodb/lib/operations/command.js
generated
vendored
10
node_modules/mongodb/lib/operations/command.js
generated
vendored
@@ -7,8 +7,8 @@ const debugOptions = require('../utils').debugOptions;
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const MongoError = require('../core').MongoError;
|
||||
const ReadPreference = require('../core').ReadPreference;
|
||||
const resolveReadPreference = require('../utils').resolveReadPreference;
|
||||
const MongoDBNamespace = require('../utils').MongoDBNamespace;
|
||||
const extractCommand = require('../command_utils').extractCommand;
|
||||
|
||||
const debugFields = [
|
||||
'authSource',
|
||||
@@ -22,6 +22,7 @@ const debugFields = [
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'bsonRegExp',
|
||||
'bufferMaxEntries',
|
||||
'numberOfRetries',
|
||||
'retryMiliSeconds',
|
||||
@@ -38,9 +39,9 @@ class CommandOperation extends OperationBase {
|
||||
|
||||
if (!this.hasAspect(Aspect.WRITE_OPERATION)) {
|
||||
if (collection != null) {
|
||||
this.options.readPreference = resolveReadPreference(collection, options);
|
||||
this.options.readPreference = ReadPreference.resolve(collection, options);
|
||||
} else {
|
||||
this.options.readPreference = resolveReadPreference(db, options);
|
||||
this.options.readPreference = ReadPreference.resolve(db, options);
|
||||
}
|
||||
} else {
|
||||
if (collection != null) {
|
||||
@@ -96,9 +97,10 @@ class CommandOperation extends OperationBase {
|
||||
|
||||
// Debug information
|
||||
if (db.s.logger.isDebug()) {
|
||||
const extractedCommand = extractCommand(command);
|
||||
db.s.logger.debug(
|
||||
`executing command ${JSON.stringify(
|
||||
command
|
||||
extractedCommand.shouldRedact ? `${extractedCommand.name} details REDACTED` : command
|
||||
)} against ${dbName}.$cmd with options [${JSON.stringify(
|
||||
debugOptions(debugFields, options)
|
||||
)}]`
|
||||
|
||||
36
node_modules/mongodb/lib/operations/command_v2.js
generated
vendored
36
node_modules/mongodb/lib/operations/command_v2.js
generated
vendored
@@ -2,12 +2,14 @@
|
||||
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const OperationBase = require('./operation').OperationBase;
|
||||
const resolveReadPreference = require('../utils').resolveReadPreference;
|
||||
const ReadPreference = require('../core').ReadPreference;
|
||||
const ReadConcern = require('../read_concern');
|
||||
const WriteConcern = require('../write_concern');
|
||||
const maxWireVersion = require('../core/utils').maxWireVersion;
|
||||
const decorateWithExplain = require('../utils').decorateWithExplain;
|
||||
const commandSupportsReadConcern = require('../core/sessions').commandSupportsReadConcern;
|
||||
const MongoError = require('../error').MongoError;
|
||||
const MongoError = require('../core/error').MongoError;
|
||||
const extractCommand = require('../command_utils').extractCommand;
|
||||
|
||||
const SUPPORTS_WRITE_CONCERN_AND_COLLATION = 5;
|
||||
|
||||
@@ -16,10 +18,12 @@ class CommandOperationV2 extends OperationBase {
|
||||
super(options);
|
||||
|
||||
this.ns = parent.s.namespace.withCollection('$cmd');
|
||||
this.readPreference = resolveReadPreference(parent, this.options);
|
||||
this.readConcern = resolveReadConcern(parent, this.options);
|
||||
this.writeConcern = resolveWriteConcern(parent, this.options);
|
||||
this.explain = false;
|
||||
const propertyProvider = this.hasAspect(Aspect.NO_INHERIT_OPTIONS) ? undefined : parent;
|
||||
this.readPreference = this.hasAspect(Aspect.WRITE_OPERATION)
|
||||
? ReadPreference.primary
|
||||
: ReadPreference.resolve(propertyProvider, this.options);
|
||||
this.readConcern = resolveReadConcern(propertyProvider, this.options);
|
||||
this.writeConcern = resolveWriteConcern(propertyProvider, this.options);
|
||||
|
||||
if (operationOptions && typeof operationOptions.fullResponse === 'boolean') {
|
||||
this.fullResponse = true;
|
||||
@@ -76,8 +80,22 @@ class CommandOperationV2 extends OperationBase {
|
||||
cmd.comment = options.comment;
|
||||
}
|
||||
|
||||
if (this.hasAspect(Aspect.EXPLAINABLE) && this.explain) {
|
||||
if (serverWireVersion < 6 && cmd.aggregate) {
|
||||
// Prior to 3.6, with aggregate, verbosity is ignored, and we must pass in "explain: true"
|
||||
cmd.explain = true;
|
||||
} else {
|
||||
cmd = decorateWithExplain(cmd, this.explain);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.logger && this.logger.isDebug()) {
|
||||
this.logger.debug(`executing command ${JSON.stringify(cmd)} against ${this.ns}`);
|
||||
const extractedCommand = extractCommand(cmd);
|
||||
this.logger.debug(
|
||||
`executing command ${JSON.stringify(
|
||||
extractedCommand.shouldRedact ? `${extractedCommand.name} details REDACTED` : cmd
|
||||
)} against ${this.ns}`
|
||||
);
|
||||
}
|
||||
|
||||
server.command(this.ns.toString(), cmd, this.options, (err, result) => {
|
||||
@@ -97,11 +115,11 @@ class CommandOperationV2 extends OperationBase {
|
||||
}
|
||||
|
||||
function resolveWriteConcern(parent, options) {
|
||||
return WriteConcern.fromOptions(options) || parent.writeConcern;
|
||||
return WriteConcern.fromOptions(options) || (parent && parent.writeConcern);
|
||||
}
|
||||
|
||||
function resolveReadConcern(parent, options) {
|
||||
return ReadConcern.fromOptions(options) || parent.readConcern;
|
||||
return ReadConcern.fromOptions(options) || (parent && parent.readConcern);
|
||||
}
|
||||
|
||||
module.exports = CommandOperationV2;
|
||||
|
||||
44
node_modules/mongodb/lib/operations/common_functions.js
generated
vendored
44
node_modules/mongodb/lib/operations/common_functions.js
generated
vendored
@@ -11,6 +11,7 @@ const MongoError = require('../core').MongoError;
|
||||
const ReadPreference = require('../core').ReadPreference;
|
||||
const toError = require('../utils').toError;
|
||||
const CursorState = require('../core/cursor').CursorState;
|
||||
const maxWireVersion = require('../core/utils').maxWireVersion;
|
||||
|
||||
/**
|
||||
* Build the count command.
|
||||
@@ -57,14 +58,6 @@ function buildCountCommand(collectionOrCursor, query, options) {
|
||||
return cmd;
|
||||
}
|
||||
|
||||
function deleteCallback(err, r, callback) {
|
||||
if (callback == null) return;
|
||||
if (err && callback) return callback(err);
|
||||
if (r == null) return callback(null, { result: { ok: 1 } });
|
||||
r.deletedCount = r.result.n;
|
||||
if (callback) callback(null, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and update a document.
|
||||
*
|
||||
@@ -297,6 +290,9 @@ function removeDocuments(coll, selector, options, callback) {
|
||||
} else if (finalOptions.retryWrites) {
|
||||
finalOptions.retryWrites = false;
|
||||
}
|
||||
if (options.hint) {
|
||||
op.hint = options.hint;
|
||||
}
|
||||
|
||||
// Have we specified collation
|
||||
try {
|
||||
@@ -305,6 +301,12 @@ function removeDocuments(coll, selector, options, callback) {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
if (options.explain !== undefined && maxWireVersion(coll.s.topology) < 3) {
|
||||
return callback
|
||||
? callback(new MongoError(`server does not support explain on remove`))
|
||||
: undefined;
|
||||
}
|
||||
|
||||
// Execute the remove
|
||||
coll.s.topology.remove(coll.s.namespace, [op], finalOptions, (err, result) => {
|
||||
if (callback == null) return;
|
||||
@@ -366,6 +368,12 @@ function updateDocuments(coll, selector, document, options, callback) {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
if (options.explain !== undefined && maxWireVersion(coll.s.topology) < 3) {
|
||||
return callback
|
||||
? callback(new MongoError(`server does not support explain on update`))
|
||||
: undefined;
|
||||
}
|
||||
|
||||
// Update options
|
||||
coll.s.topology.update(coll.s.namespace, [op], finalOptions, (err, result) => {
|
||||
if (callback == null) return;
|
||||
@@ -379,31 +387,13 @@ function updateDocuments(coll, selector, document, options, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
function updateCallback(err, r, callback) {
|
||||
if (callback == null) return;
|
||||
if (err) return callback(err);
|
||||
if (r == null) return callback(null, { result: { ok: 1 } });
|
||||
r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
|
||||
r.upsertedId =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length > 0
|
||||
? r.result.upserted[0] // FIXME(major): should be `r.result.upserted[0]._id`
|
||||
: null;
|
||||
r.upsertedCount =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
|
||||
r.matchedCount =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
|
||||
callback(null, r);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildCountCommand,
|
||||
deleteCallback,
|
||||
findAndModify,
|
||||
indexInformation,
|
||||
nextObject,
|
||||
prepareDocs,
|
||||
insertDocuments,
|
||||
removeDocuments,
|
||||
updateDocuments,
|
||||
updateCallback
|
||||
updateDocuments
|
||||
};
|
||||
|
||||
141
node_modules/mongodb/lib/operations/connect.js
generated
vendored
141
node_modules/mongodb/lib/operations/connect.js
generated
vendored
@@ -13,8 +13,9 @@ const ReplSet = require('../topologies/replset');
|
||||
const Server = require('../topologies/server');
|
||||
const ServerSessionPool = require('../core').Sessions.ServerSessionPool;
|
||||
const emitDeprecationWarning = require('../utils').emitDeprecationWarning;
|
||||
const emitWarningOnce = require('../utils').emitWarningOnce;
|
||||
const fs = require('fs');
|
||||
const BSON = require('../core/connection/utils').retrieveBSON();
|
||||
const WriteConcern = require('../write_concern');
|
||||
const CMAP_EVENT_NAMES = require('../cmap/events').CMAP_EVENT_NAMES;
|
||||
|
||||
let client;
|
||||
@@ -33,9 +34,11 @@ const legacyParse = deprecate(
|
||||
|
||||
const AUTH_MECHANISM_INTERNAL_MAP = {
|
||||
DEFAULT: 'default',
|
||||
'MONGODB-CR': 'mongocr',
|
||||
PLAIN: 'plain',
|
||||
GSSAPI: 'gssapi',
|
||||
'MONGODB-CR': 'mongocr',
|
||||
'MONGODB-X509': 'x509',
|
||||
'MONGODB-AWS': 'mongodb-aws',
|
||||
'SCRAM-SHA-1': 'scram-sha-1',
|
||||
'SCRAM-SHA-256': 'scram-sha-256'
|
||||
};
|
||||
@@ -66,12 +69,13 @@ const monitoringEvents = [
|
||||
|
||||
const VALID_AUTH_MECHANISMS = new Set([
|
||||
'DEFAULT',
|
||||
'MONGODB-CR',
|
||||
'PLAIN',
|
||||
'GSSAPI',
|
||||
'MONGODB-CR',
|
||||
'MONGODB-X509',
|
||||
'MONGODB-AWS',
|
||||
'SCRAM-SHA-1',
|
||||
'SCRAM-SHA-256',
|
||||
'GSSAPI'
|
||||
'SCRAM-SHA-256'
|
||||
]);
|
||||
|
||||
const validOptionNames = [
|
||||
@@ -102,6 +106,7 @@ const validOptionNames = [
|
||||
'w',
|
||||
'wtimeout',
|
||||
'j',
|
||||
'writeConcern',
|
||||
'forceServerObjectId',
|
||||
'serializeFunctions',
|
||||
'ignoreUndefined',
|
||||
@@ -117,6 +122,7 @@ const validOptionNames = [
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'promoteLongs',
|
||||
'bsonRegExp',
|
||||
'domainsEnabled',
|
||||
'checkServerIdentity',
|
||||
'validateOptions',
|
||||
@@ -132,6 +138,7 @@ const validOptionNames = [
|
||||
'auto_reconnect',
|
||||
'minSize',
|
||||
'monitorCommands',
|
||||
'serverApi',
|
||||
'retryWrites',
|
||||
'retryReads',
|
||||
'useNewUrlParser',
|
||||
@@ -151,6 +158,8 @@ const validOptionNames = [
|
||||
'tlsCertificateKeyFilePassword',
|
||||
'minHeartbeatFrequencyMS',
|
||||
'heartbeatFrequencyMS',
|
||||
'directConnection',
|
||||
'appName',
|
||||
|
||||
// CMAP options
|
||||
'maxPoolSize',
|
||||
@@ -175,12 +184,12 @@ function validOptions(options) {
|
||||
if (options.validateOptions) {
|
||||
return new MongoError(`option ${name} is not supported`);
|
||||
} else {
|
||||
console.warn(`the options [${name}] is not supported`);
|
||||
emitWarningOnce(`the options [${name}] is not supported`);
|
||||
}
|
||||
}
|
||||
|
||||
if (legacyOptionNames.indexOf(name) !== -1) {
|
||||
console.warn(
|
||||
emitWarningOnce(
|
||||
`the server/replset/mongos/db options are deprecated, ` +
|
||||
`all their options are supported at the top level of the options object [${validOptionNames}]`
|
||||
);
|
||||
@@ -250,9 +259,6 @@ function resolveTLSOptions(options) {
|
||||
});
|
||||
}
|
||||
|
||||
const emitDeprecationForNonUnifiedTopology = deprecate(() => {},
|
||||
'current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. ' + 'To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.');
|
||||
|
||||
function connect(mongoClient, url, options, callback) {
|
||||
options = Object.assign({}, options);
|
||||
|
||||
@@ -285,7 +291,7 @@ function connect(mongoClient, url, options, callback) {
|
||||
const _finalOptions = createUnifiedOptions(object, options);
|
||||
|
||||
// Check if we have connection and socket timeout set
|
||||
if (_finalOptions.socketTimeoutMS == null) _finalOptions.socketTimeoutMS = 360000;
|
||||
if (_finalOptions.socketTimeoutMS == null) _finalOptions.socketTimeoutMS = 0;
|
||||
if (_finalOptions.connectTimeoutMS == null) _finalOptions.connectTimeoutMS = 10000;
|
||||
if (_finalOptions.retryWrites == null) _finalOptions.retryWrites = true;
|
||||
if (_finalOptions.useRecoveryToken == null) _finalOptions.useRecoveryToken = true;
|
||||
@@ -295,18 +301,16 @@ function connect(mongoClient, url, options, callback) {
|
||||
delete _finalOptions.db_options.auth;
|
||||
}
|
||||
|
||||
// `journal` should be translated to `j` for the driver
|
||||
if (_finalOptions.journal != null) {
|
||||
_finalOptions.j = _finalOptions.journal;
|
||||
_finalOptions.journal = undefined;
|
||||
}
|
||||
|
||||
// resolve tls options if needed
|
||||
resolveTLSOptions(_finalOptions);
|
||||
|
||||
// Store the merged options object
|
||||
mongoClient.s.options = _finalOptions;
|
||||
|
||||
// Apply read and write concern from parsed url
|
||||
mongoClient.s.readPreference = ReadPreference.fromOptions(_finalOptions);
|
||||
mongoClient.s.writeConcern = WriteConcern.fromOptions(_finalOptions);
|
||||
|
||||
// Failure modes
|
||||
if (object.servers.length === 0) {
|
||||
return callback(new Error('connection string must contain at least one seed host'));
|
||||
@@ -330,7 +334,9 @@ function connect(mongoClient, url, options, callback) {
|
||||
return createTopology(mongoClient, 'unified', _finalOptions, connectCallback);
|
||||
}
|
||||
|
||||
emitDeprecationForNonUnifiedTopology();
|
||||
emitWarningOnce(
|
||||
'Current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.'
|
||||
);
|
||||
|
||||
// Do we have a replicaset then skip discovery and go straight to connectivity
|
||||
if (_finalOptions.replicaSet || _finalOptions.rs_name) {
|
||||
@@ -491,58 +497,9 @@ function createTopology(mongoClient, topologyType, options, callback) {
|
||||
|
||||
// determine CSFLE support
|
||||
if (options.autoEncryption != null) {
|
||||
let AutoEncrypter;
|
||||
try {
|
||||
require.resolve('mongodb-client-encryption');
|
||||
} catch (err) {
|
||||
callback(
|
||||
new MongoError(
|
||||
'Auto-encryption requested, but the module is not installed. Please add `mongodb-client-encryption` as a dependency of your project'
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let mongodbClientEncryption = require('mongodb-client-encryption');
|
||||
if (typeof mongodbClientEncryption.extension !== 'function') {
|
||||
callback(
|
||||
new MongoError(
|
||||
'loaded version of `mongodb-client-encryption` does not have property `extension`. Please make sure you are loading the correct version of `mongodb-client-encryption`'
|
||||
)
|
||||
);
|
||||
}
|
||||
AutoEncrypter = mongodbClientEncryption.extension(require('../../index')).AutoEncrypter;
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const mongoCryptOptions = Object.assign(
|
||||
{
|
||||
bson:
|
||||
options.bson ||
|
||||
new BSON([
|
||||
BSON.Binary,
|
||||
BSON.Code,
|
||||
BSON.DBRef,
|
||||
BSON.Decimal128,
|
||||
BSON.Double,
|
||||
BSON.Int32,
|
||||
BSON.Long,
|
||||
BSON.Map,
|
||||
BSON.MaxKey,
|
||||
BSON.MinKey,
|
||||
BSON.ObjectId,
|
||||
BSON.BSONRegExp,
|
||||
BSON.Symbol,
|
||||
BSON.Timestamp
|
||||
])
|
||||
},
|
||||
options.autoEncryption
|
||||
);
|
||||
|
||||
options.autoEncrypter = new AutoEncrypter(mongoClient, mongoCryptOptions);
|
||||
const Encrypter = require('../encrypter').Encrypter;
|
||||
options.encrypter = new Encrypter(mongoClient, options);
|
||||
options.autoEncrypter = options.encrypter.autoEncrypter;
|
||||
}
|
||||
|
||||
// Create the topology
|
||||
@@ -580,7 +537,10 @@ function createTopology(mongoClient, topologyType, options, callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback(undefined, topology);
|
||||
options.encrypter.connectInternalClient(error => {
|
||||
if (error) return callback(error);
|
||||
callback(undefined, topology);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -611,9 +571,12 @@ function createUnifiedOptions(finalOptions, options) {
|
||||
'mongos_options'
|
||||
];
|
||||
const noMerge = ['readconcern', 'compression', 'autoencryption'];
|
||||
const skip = ['w', 'wtimeout', 'j', 'journal', 'fsync', 'writeconcern'];
|
||||
|
||||
for (const name in options) {
|
||||
if (noMerge.indexOf(name.toLowerCase()) !== -1) {
|
||||
if (skip.indexOf(name.toLowerCase()) !== -1) {
|
||||
continue;
|
||||
} else if (noMerge.indexOf(name.toLowerCase()) !== -1) {
|
||||
finalOptions[name] = options[name];
|
||||
} else if (childOptions.indexOf(name.toLowerCase()) !== -1) {
|
||||
finalOptions = mergeOptions(finalOptions, options[name], false);
|
||||
@@ -631,6 +594,14 @@ function createUnifiedOptions(finalOptions, options) {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle write concern keys separately, since `options` may have the keys at the top level or
|
||||
// under `options.writeConcern`. The final merged keys will be under `finalOptions.writeConcern`.
|
||||
// This way, `fromOptions` will warn once if `options` is using deprecated write concern options
|
||||
const optionsWriteConcern = WriteConcern.fromOptions(options);
|
||||
if (optionsWriteConcern) {
|
||||
finalOptions.writeConcern = Object.assign({}, finalOptions.writeConcern, optionsWriteConcern);
|
||||
}
|
||||
|
||||
return finalOptions;
|
||||
}
|
||||
|
||||
@@ -644,6 +615,7 @@ function generateCredentials(client, username, password, options) {
|
||||
// authMechanism
|
||||
const authMechanismRaw = options.authMechanism || 'DEFAULT';
|
||||
const authMechanism = authMechanismRaw.toUpperCase();
|
||||
const mechanismProperties = options.authMechanismProperties;
|
||||
|
||||
if (!VALID_AUTH_MECHANISMS.has(authMechanism)) {
|
||||
throw MongoError.create({
|
||||
@@ -652,18 +624,9 @@ function generateCredentials(client, username, password, options) {
|
||||
});
|
||||
}
|
||||
|
||||
if (authMechanism === 'GSSAPI') {
|
||||
return new MongoCredentials({
|
||||
mechanism: process.platform === 'win32' ? 'sspi' : 'gssapi',
|
||||
mechanismProperties: options,
|
||||
source,
|
||||
username,
|
||||
password
|
||||
});
|
||||
}
|
||||
|
||||
return new MongoCredentials({
|
||||
mechanism: AUTH_MECHANISM_INTERNAL_MAP[authMechanism],
|
||||
mechanismProperties,
|
||||
source,
|
||||
username,
|
||||
password
|
||||
@@ -763,12 +726,24 @@ function transformUrlOptions(_object) {
|
||||
|
||||
if (object.wTimeoutMS) {
|
||||
object.wtimeout = object.wTimeoutMS;
|
||||
object.wTimeoutMS = undefined;
|
||||
}
|
||||
|
||||
if (_object.srvHost) {
|
||||
object.srvHost = _object.srvHost;
|
||||
}
|
||||
|
||||
// Any write concern options from the URL will be top-level, so we manually
|
||||
// move them options under `object.writeConcern` to avoid warnings later
|
||||
const wcKeys = ['w', 'wtimeout', 'j', 'journal', 'fsync'];
|
||||
for (const key of wcKeys) {
|
||||
if (object[key] !== undefined) {
|
||||
if (object.writeConcern === undefined) object.writeConcern = {};
|
||||
object.writeConcern[key] = object[key];
|
||||
object[key] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@@ -791,7 +766,7 @@ function translateOptions(options, translationOptions) {
|
||||
}
|
||||
|
||||
// Set the socket and connection timeouts
|
||||
if (options.socketTimeoutMS == null) options.socketTimeoutMS = 360000;
|
||||
if (options.socketTimeoutMS == null) options.socketTimeoutMS = 0;
|
||||
if (options.connectTimeoutMS == null) options.connectTimeoutMS = 10000;
|
||||
|
||||
if (!translationOptions.createServers) {
|
||||
|
||||
93
node_modules/mongodb/lib/operations/create_collection.js
generated
vendored
93
node_modules/mongodb/lib/operations/create_collection.js
generated
vendored
@@ -4,13 +4,11 @@ const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
const CommandOperation = require('./command');
|
||||
const applyWriteConcern = require('../utils').applyWriteConcern;
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const loadCollection = require('../dynamic_loaders').loadCollection;
|
||||
const MongoError = require('../core').MongoError;
|
||||
const ReadPreference = require('../core').ReadPreference;
|
||||
|
||||
// Filter out any write concern options
|
||||
const illegalCommandFields = [
|
||||
const ILLEGAL_COMMAND_FIELDS = new Set([
|
||||
'w',
|
||||
'wtimeout',
|
||||
'j',
|
||||
@@ -24,12 +22,11 @@ const illegalCommandFields = [
|
||||
'session',
|
||||
'readConcern',
|
||||
'writeConcern'
|
||||
];
|
||||
]);
|
||||
|
||||
class CreateCollectionOperation extends CommandOperation {
|
||||
constructor(db, name, options) {
|
||||
super(db, options);
|
||||
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@@ -37,14 +34,12 @@ class CreateCollectionOperation extends CommandOperation {
|
||||
const name = this.name;
|
||||
const options = this.options;
|
||||
|
||||
// Create collection command
|
||||
const cmd = { create: name };
|
||||
// Add all optional parameters
|
||||
for (let n in options) {
|
||||
if (
|
||||
options[n] != null &&
|
||||
typeof options[n] !== 'function' &&
|
||||
illegalCommandFields.indexOf(n) === -1
|
||||
!ILLEGAL_COMMAND_FIELDS.has(n)
|
||||
) {
|
||||
cmd[n] = options[n];
|
||||
}
|
||||
@@ -57,61 +52,51 @@ class CreateCollectionOperation extends CommandOperation {
|
||||
const db = this.db;
|
||||
const name = this.name;
|
||||
const options = this.options;
|
||||
const Collection = loadCollection();
|
||||
|
||||
let Collection = loadCollection();
|
||||
|
||||
// Did the user destroy the topology
|
||||
if (db.serverConfig && db.serverConfig.isDestroyed()) {
|
||||
return callback(new MongoError('topology was destroyed'));
|
||||
}
|
||||
|
||||
let listCollectionOptions = Object.assign({}, options, { nameOnly: true });
|
||||
let listCollectionOptions = Object.assign({ nameOnly: true, strict: false }, options);
|
||||
listCollectionOptions = applyWriteConcern(listCollectionOptions, { db }, listCollectionOptions);
|
||||
|
||||
// Check if we have the name
|
||||
db.listCollections({ name }, listCollectionOptions)
|
||||
.setReadPreference(ReadPreference.PRIMARY)
|
||||
.toArray((err, collections) => {
|
||||
if (err != null) return handleCallback(callback, err, null);
|
||||
if (collections.length > 0 && listCollectionOptions.strict) {
|
||||
return handleCallback(
|
||||
callback,
|
||||
MongoError.create({
|
||||
message: `Collection ${name} already exists. Currently in strict mode.`,
|
||||
driver: true
|
||||
}),
|
||||
null
|
||||
);
|
||||
} else if (collections.length > 0) {
|
||||
try {
|
||||
return handleCallback(
|
||||
callback,
|
||||
null,
|
||||
new Collection(db, db.s.topology, db.databaseName, name, db.s.pkFactory, options)
|
||||
);
|
||||
} catch (err) {
|
||||
return handleCallback(callback, err);
|
||||
}
|
||||
}
|
||||
function done(err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// Execute command
|
||||
super.execute(err => {
|
||||
if (err) return handleCallback(callback, err);
|
||||
try {
|
||||
callback(
|
||||
null,
|
||||
new Collection(db, db.s.topology, db.databaseName, name, db.s.pkFactory, options)
|
||||
);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return handleCallback(
|
||||
callback,
|
||||
null,
|
||||
new Collection(db, db.s.topology, db.databaseName, name, db.s.pkFactory, options)
|
||||
);
|
||||
} catch (err) {
|
||||
return handleCallback(callback, err);
|
||||
const strictMode = listCollectionOptions.strict;
|
||||
if (strictMode) {
|
||||
db.listCollections({ name }, listCollectionOptions)
|
||||
.setReadPreference(ReadPreference.PRIMARY)
|
||||
.toArray((err, collections) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (collections.length > 0) {
|
||||
return callback(
|
||||
new MongoError(`Collection ${name} already exists. Currently in strict mode.`)
|
||||
);
|
||||
}
|
||||
|
||||
super.execute(done);
|
||||
});
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise just execute the command
|
||||
super.execute(done);
|
||||
}
|
||||
}
|
||||
|
||||
defineAspects(CreateCollectionOperation, Aspect.WRITE_OPERATION);
|
||||
|
||||
module.exports = CreateCollectionOperation;
|
||||
|
||||
92
node_modules/mongodb/lib/operations/create_index.js
generated
vendored
92
node_modules/mongodb/lib/operations/create_index.js
generated
vendored
@@ -1,92 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const CommandOperation = require('./command');
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const MongoError = require('../core').MongoError;
|
||||
const parseIndexOptions = require('../utils').parseIndexOptions;
|
||||
|
||||
const keysToOmit = new Set([
|
||||
'name',
|
||||
'key',
|
||||
'writeConcern',
|
||||
'w',
|
||||
'wtimeout',
|
||||
'j',
|
||||
'fsync',
|
||||
'readPreference',
|
||||
'session'
|
||||
]);
|
||||
|
||||
class CreateIndexOperation extends CommandOperation {
|
||||
constructor(db, name, fieldOrSpec, options) {
|
||||
super(db, options);
|
||||
|
||||
// Build the index
|
||||
const indexParameters = parseIndexOptions(fieldOrSpec);
|
||||
// Generate the index name
|
||||
const indexName = typeof options.name === 'string' ? options.name : indexParameters.name;
|
||||
// Set up the index
|
||||
const indexesObject = { name: indexName, key: indexParameters.fieldHash };
|
||||
|
||||
this.name = name;
|
||||
this.fieldOrSpec = fieldOrSpec;
|
||||
this.indexes = indexesObject;
|
||||
}
|
||||
|
||||
_buildCommand() {
|
||||
const options = this.options;
|
||||
const name = this.name;
|
||||
const indexes = this.indexes;
|
||||
|
||||
// merge all the options
|
||||
for (let optionName in options) {
|
||||
if (!keysToOmit.has(optionName)) {
|
||||
indexes[optionName] = options[optionName];
|
||||
}
|
||||
}
|
||||
|
||||
// Create command, apply write concern to command
|
||||
const cmd = { createIndexes: name, indexes: [indexes] };
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
execute(callback) {
|
||||
const db = this.db;
|
||||
const options = this.options;
|
||||
const indexes = this.indexes;
|
||||
|
||||
// Get capabilities
|
||||
const capabilities = db.s.topology.capabilities();
|
||||
|
||||
// Did the user pass in a collation, check if our write server supports it
|
||||
if (options.collation && capabilities && !capabilities.commandsTakeCollation) {
|
||||
// Create a new error
|
||||
const error = new MongoError('server/primary/mongos does not support collation');
|
||||
error.code = 67;
|
||||
// Return the error
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
// Ensure we have a callback
|
||||
if (options.writeConcern && typeof callback !== 'function') {
|
||||
throw MongoError.create({
|
||||
message: 'Cannot use a writeConcern without a provided callback',
|
||||
driver: true
|
||||
});
|
||||
}
|
||||
|
||||
// Attempt to run using createIndexes command
|
||||
super.execute((err, result) => {
|
||||
if (err == null) return handleCallback(callback, err, indexes.name);
|
||||
|
||||
return handleCallback(callback, err, result);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
defineAspects(CreateIndexOperation, Aspect.WRITE_OPERATION);
|
||||
|
||||
module.exports = CreateIndexOperation;
|
||||
144
node_modules/mongodb/lib/operations/create_indexes.js
generated
vendored
144
node_modules/mongodb/lib/operations/create_indexes.js
generated
vendored
@@ -2,60 +2,136 @@
|
||||
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
const OperationBase = require('./operation').OperationBase;
|
||||
const executeCommand = require('./db_ops').executeCommand;
|
||||
const CommandOperationV2 = require('./command_v2');
|
||||
const MongoError = require('../core').MongoError;
|
||||
const ReadPreference = require('../core').ReadPreference;
|
||||
const parseIndexOptions = require('../utils').parseIndexOptions;
|
||||
const maxWireVersion = require('../core/utils').maxWireVersion;
|
||||
|
||||
class CreateIndexesOperation extends OperationBase {
|
||||
constructor(collection, indexSpecs, options) {
|
||||
super(options);
|
||||
const VALID_INDEX_OPTIONS = new Set([
|
||||
'background',
|
||||
'unique',
|
||||
'name',
|
||||
'partialFilterExpression',
|
||||
'sparse',
|
||||
'expireAfterSeconds',
|
||||
'storageEngine',
|
||||
'collation',
|
||||
|
||||
// text indexes
|
||||
'weights',
|
||||
'default_language',
|
||||
'language_override',
|
||||
'textIndexVersion',
|
||||
|
||||
// 2d-sphere indexes
|
||||
'2dsphereIndexVersion',
|
||||
|
||||
// 2d indexes
|
||||
'bits',
|
||||
'min',
|
||||
'max',
|
||||
|
||||
// geoHaystack Indexes
|
||||
'bucketSize',
|
||||
|
||||
// wildcard indexes
|
||||
'wildcardProjection'
|
||||
]);
|
||||
|
||||
class CreateIndexesOperation extends CommandOperationV2 {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
constructor(parent, collection, indexes, options) {
|
||||
super(parent, options);
|
||||
this.collection = collection;
|
||||
this.indexSpecs = indexSpecs;
|
||||
|
||||
// createIndex can be called with a variety of styles:
|
||||
// coll.createIndex('a');
|
||||
// coll.createIndex({ a: 1 });
|
||||
// coll.createIndex([['a', 1]]);
|
||||
// createIndexes is always called with an array of index spec objects
|
||||
if (!Array.isArray(indexes) || Array.isArray(indexes[0])) {
|
||||
this.onlyReturnNameOfCreatedIndex = true;
|
||||
// TODO: remove in v4 (breaking change); make createIndex return full response as createIndexes does
|
||||
|
||||
const indexParameters = parseIndexOptions(indexes);
|
||||
// Generate the index name
|
||||
const name = typeof options.name === 'string' ? options.name : indexParameters.name;
|
||||
// Set up the index
|
||||
const indexSpec = { name, key: indexParameters.fieldHash };
|
||||
// merge valid index options into the index spec
|
||||
for (let optionName in options) {
|
||||
if (VALID_INDEX_OPTIONS.has(optionName)) {
|
||||
indexSpec[optionName] = options[optionName];
|
||||
}
|
||||
}
|
||||
this.indexes = [indexSpec];
|
||||
return;
|
||||
}
|
||||
|
||||
this.indexes = indexes;
|
||||
}
|
||||
|
||||
execute(callback) {
|
||||
const coll = this.collection;
|
||||
const indexSpecs = this.indexSpecs;
|
||||
let options = this.options;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
execute(server, callback) {
|
||||
const options = this.options;
|
||||
const indexes = this.indexes;
|
||||
|
||||
const capabilities = coll.s.topology.capabilities();
|
||||
const serverWireVersion = maxWireVersion(server);
|
||||
|
||||
// Ensure we generate the correct name if the parameter is not set
|
||||
for (let i = 0; i < indexSpecs.length; i++) {
|
||||
if (indexSpecs[i].name == null) {
|
||||
for (let i = 0; i < indexes.length; i++) {
|
||||
// Did the user pass in a collation, check if our write server supports it
|
||||
if (indexes[i].collation && serverWireVersion < 5) {
|
||||
callback(
|
||||
new MongoError(
|
||||
`Server ${server.name}, which reports wire version ${serverWireVersion}, does not support collation`
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (indexes[i].name == null) {
|
||||
const keys = [];
|
||||
|
||||
// Did the user pass in a collation, check if our write server supports it
|
||||
if (indexSpecs[i].collation && capabilities && !capabilities.commandsTakeCollation) {
|
||||
return callback(new MongoError('server/primary/mongos does not support collation'));
|
||||
}
|
||||
|
||||
for (let name in indexSpecs[i].key) {
|
||||
keys.push(`${name}_${indexSpecs[i].key[name]}`);
|
||||
for (let name in indexes[i].key) {
|
||||
keys.push(`${name}_${indexes[i].key[name]}`);
|
||||
}
|
||||
|
||||
// Set the name
|
||||
indexSpecs[i].name = keys.join('_');
|
||||
indexes[i].name = keys.join('_');
|
||||
}
|
||||
}
|
||||
|
||||
options = Object.assign({}, options, { readPreference: ReadPreference.PRIMARY });
|
||||
const cmd = { createIndexes: this.collection, indexes };
|
||||
|
||||
// Execute the index
|
||||
executeCommand(
|
||||
coll.s.db,
|
||||
{
|
||||
createIndexes: coll.collectionName,
|
||||
indexes: indexSpecs
|
||||
},
|
||||
options,
|
||||
callback
|
||||
);
|
||||
if (options.commitQuorum != null) {
|
||||
if (serverWireVersion < 9) {
|
||||
callback(
|
||||
new MongoError('`commitQuorum` option for `createIndexes` not supported on servers < 4.4')
|
||||
);
|
||||
return;
|
||||
}
|
||||
cmd.commitQuorum = options.commitQuorum;
|
||||
}
|
||||
|
||||
// collation is set on each index, it should not be defined at the root
|
||||
this.options.collation = undefined;
|
||||
|
||||
super.executeCommand(server, cmd, (err, result) => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null, this.onlyReturnNameOfCreatedIndex ? indexes[0].name : result);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
defineAspects(CreateIndexesOperation, Aspect.WRITE_OPERATION);
|
||||
defineAspects(CreateIndexesOperation, [Aspect.WRITE_OPERATION, Aspect.EXECUTE_WITH_SELECTION]);
|
||||
|
||||
module.exports = CreateIndexesOperation;
|
||||
|
||||
28
node_modules/mongodb/lib/operations/db_ops.js
generated
vendored
28
node_modules/mongodb/lib/operations/db_ops.js
generated
vendored
@@ -1,14 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
const MONGODB_ERROR_CODES = require('../error_codes').MONGODB_ERROR_CODES;
|
||||
const applyWriteConcern = require('../utils').applyWriteConcern;
|
||||
const Code = require('../core').BSON.Code;
|
||||
const resolveReadPreference = require('../utils').resolveReadPreference;
|
||||
const debugOptions = require('../utils').debugOptions;
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const MongoError = require('../core').MongoError;
|
||||
const parseIndexOptions = require('../utils').parseIndexOptions;
|
||||
const ReadPreference = require('../core').ReadPreference;
|
||||
const toError = require('../utils').toError;
|
||||
const extractCommand = require('../command_utils').extractCommand;
|
||||
const CONSTANTS = require('../constants');
|
||||
const MongoDBNamespace = require('../utils').MongoDBNamespace;
|
||||
|
||||
@@ -24,6 +25,7 @@ const debugFields = [
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'bsonRegExp',
|
||||
'bufferMaxEntries',
|
||||
'numberOfRetries',
|
||||
'retryMiliSeconds',
|
||||
@@ -74,12 +76,12 @@ function createIndex(db, name, fieldOrSpec, options, callback) {
|
||||
* 197 = 'InvalidIndexSpecificationOption' (`_id` with `background: true`)
|
||||
*/
|
||||
if (
|
||||
err.code === 67 ||
|
||||
err.code === 11000 ||
|
||||
err.code === 85 ||
|
||||
err.code === 86 ||
|
||||
err.code === 11600 ||
|
||||
err.code === 197
|
||||
err.code === MONGODB_ERROR_CODES.CannotCreateIndex ||
|
||||
err.code === MONGODB_ERROR_CODES.DuplicateKey ||
|
||||
err.code === MONGODB_ERROR_CODES.IndexOptionsConflict ||
|
||||
err.code === MONGODB_ERROR_CODES.IndexKeySpecsConflict ||
|
||||
err.code === MONGODB_ERROR_CODES.InterruptedAtShutdown ||
|
||||
err.code === MONGODB_ERROR_CODES.InvalidIndexSpecificationOption
|
||||
) {
|
||||
return handleCallback(callback, err, result);
|
||||
}
|
||||
@@ -146,7 +148,9 @@ function ensureIndex(db, name, fieldOrSpec, options, callback) {
|
||||
|
||||
// Check if the index already exists
|
||||
indexInformation(db, name, finalOptions, (err, indexInformation) => {
|
||||
if (err != null && err.code !== 26) return handleCallback(callback, err, null);
|
||||
if (err != null && err.code !== MONGODB_ERROR_CODES.NamespaceNotFound) {
|
||||
return handleCallback(callback, err, null);
|
||||
}
|
||||
// If the index does not exist, create it
|
||||
if (indexInformation == null || !indexInformation[index_name]) {
|
||||
createIndex(db, name, fieldOrSpec, options, callback);
|
||||
@@ -225,17 +229,19 @@ function executeCommand(db, command, options, callback) {
|
||||
const dbName = options.dbName || options.authdb || db.databaseName;
|
||||
|
||||
// Convert the readPreference if its not a write
|
||||
options.readPreference = resolveReadPreference(db, options);
|
||||
options.readPreference = ReadPreference.resolve(db, options);
|
||||
|
||||
// Debug information
|
||||
if (db.s.logger.isDebug())
|
||||
if (db.s.logger.isDebug()) {
|
||||
const extractedCommand = extractCommand(command);
|
||||
db.s.logger.debug(
|
||||
`executing command ${JSON.stringify(
|
||||
command
|
||||
extractedCommand.shouldRedact ? `${extractedCommand.name} details REDACTED` : command
|
||||
)} against ${dbName}.$cmd with options [${JSON.stringify(
|
||||
debugOptions(debugFields, options)
|
||||
)}]`
|
||||
);
|
||||
}
|
||||
|
||||
// Execute command
|
||||
db.s.topology.command(db.s.namespace.withCollection('$cmd'), command, options, (err, result) => {
|
||||
|
||||
17
node_modules/mongodb/lib/operations/delete_many.js
generated
vendored
17
node_modules/mongodb/lib/operations/delete_many.js
generated
vendored
@@ -1,8 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const OperationBase = require('./operation').OperationBase;
|
||||
const deleteCallback = require('./common_functions').deleteCallback;
|
||||
const removeDocuments = require('./common_functions').removeDocuments;
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
|
||||
class DeleteManyOperation extends OperationBase {
|
||||
constructor(collection, filter, options) {
|
||||
@@ -18,8 +19,20 @@ class DeleteManyOperation extends OperationBase {
|
||||
const options = this.options;
|
||||
|
||||
options.single = false;
|
||||
removeDocuments(coll, filter, options, (err, r) => deleteCallback(err, r, callback));
|
||||
removeDocuments(coll, filter, options, (err, r) => {
|
||||
if (callback == null) return;
|
||||
if (err && callback) return callback(err);
|
||||
if (r == null) return callback(null, { result: { ok: 1 } });
|
||||
|
||||
// If an explain operation was executed, don't process the server results
|
||||
if (this.explain) return callback(undefined, r.result);
|
||||
|
||||
r.deletedCount = r.result.n;
|
||||
callback(null, r);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
defineAspects(DeleteManyOperation, [Aspect.EXPLAINABLE]);
|
||||
|
||||
module.exports = DeleteManyOperation;
|
||||
|
||||
17
node_modules/mongodb/lib/operations/delete_one.js
generated
vendored
17
node_modules/mongodb/lib/operations/delete_one.js
generated
vendored
@@ -1,8 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const OperationBase = require('./operation').OperationBase;
|
||||
const deleteCallback = require('./common_functions').deleteCallback;
|
||||
const removeDocuments = require('./common_functions').removeDocuments;
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
|
||||
class DeleteOneOperation extends OperationBase {
|
||||
constructor(collection, filter, options) {
|
||||
@@ -18,8 +19,20 @@ class DeleteOneOperation extends OperationBase {
|
||||
const options = this.options;
|
||||
|
||||
options.single = true;
|
||||
removeDocuments(coll, filter, options, (err, r) => deleteCallback(err, r, callback));
|
||||
removeDocuments(coll, filter, options, (err, r) => {
|
||||
if (callback == null) return;
|
||||
if (err && callback) return callback(err);
|
||||
if (r == null) return callback(null, { result: { ok: 1 } });
|
||||
|
||||
// If an explain operation was executed, don't process the server results
|
||||
if (this.explain) return callback(undefined, r.result);
|
||||
|
||||
r.deletedCount = r.result.n;
|
||||
callback(null, r);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
defineAspects(DeleteOneOperation, [Aspect.EXPLAINABLE]);
|
||||
|
||||
module.exports = DeleteOneOperation;
|
||||
|
||||
12
node_modules/mongodb/lib/operations/distinct.js
generated
vendored
12
node_modules/mongodb/lib/operations/distinct.js
generated
vendored
@@ -5,6 +5,8 @@ const defineAspects = require('./operation').defineAspects;
|
||||
const CommandOperationV2 = require('./command_v2');
|
||||
const decorateWithCollation = require('../utils').decorateWithCollation;
|
||||
const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
|
||||
const maxWireVersion = require('../core/utils').maxWireVersion;
|
||||
const MongoError = require('../error').MongoError;
|
||||
|
||||
/**
|
||||
* Return a list of distinct values for the given key across a collection.
|
||||
@@ -65,13 +67,18 @@ class DistinctOperation extends CommandOperationV2 {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
if (this.explain && maxWireVersion(server) < 4) {
|
||||
callback(new MongoError(`server does not support explain on distinct`));
|
||||
return;
|
||||
}
|
||||
|
||||
super.executeCommand(server, cmd, (err, result) => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null, this.options.full ? result : result.values);
|
||||
callback(null, this.options.full || this.explain ? result : result.values);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -79,7 +86,8 @@ class DistinctOperation extends CommandOperationV2 {
|
||||
defineAspects(DistinctOperation, [
|
||||
Aspect.READ_OPERATION,
|
||||
Aspect.RETRYABLE,
|
||||
Aspect.EXECUTE_WITH_SELECTION
|
||||
Aspect.EXECUTE_WITH_SELECTION,
|
||||
Aspect.EXPLAINABLE
|
||||
]);
|
||||
|
||||
module.exports = DistinctOperation;
|
||||
|
||||
65
node_modules/mongodb/lib/operations/estimated_document_count.js
generated
vendored
65
node_modules/mongodb/lib/operations/estimated_document_count.js
generated
vendored
@@ -1,43 +1,72 @@
|
||||
'use strict';
|
||||
|
||||
const MONGODB_ERROR_CODES = require('../error_codes').MONGODB_ERROR_CODES;
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
const CommandOperationV2 = require('./command_v2');
|
||||
const maxWireVersion = require('../core/utils').maxWireVersion;
|
||||
const CountDocumentsOperation = require('./count_documents');
|
||||
|
||||
class EstimatedDocumentCountOperation extends CommandOperationV2 {
|
||||
constructor(collection, query, options) {
|
||||
if (typeof options === 'undefined') {
|
||||
options = query;
|
||||
query = undefined;
|
||||
}
|
||||
|
||||
constructor(collection, options) {
|
||||
super(collection, options);
|
||||
this.collection = collection;
|
||||
this.collectionName = collection.s.namespace.collection;
|
||||
if (query) {
|
||||
this.query = query;
|
||||
}
|
||||
}
|
||||
|
||||
execute(server, callback) {
|
||||
const options = this.options;
|
||||
const cmd = { count: this.collectionName };
|
||||
if (maxWireVersion(server) < 12) {
|
||||
return this.executeLegacy(server, callback);
|
||||
}
|
||||
// if the user specifies a filter, use a CountDocumentsOperation instead
|
||||
if (this.options.query) {
|
||||
const op = new CountDocumentsOperation(this.collection, this.options.query, this.options);
|
||||
return op.execute(server, callback);
|
||||
}
|
||||
const pipeline = [{ $collStats: { count: {} } }, { $group: { _id: 1, n: { $sum: '$count' } } }];
|
||||
const cmd = { aggregate: this.collectionName, pipeline, cursor: {} };
|
||||
|
||||
if (this.query) {
|
||||
cmd.query = this.query;
|
||||
if (typeof this.options.maxTimeMS === 'number') {
|
||||
cmd.maxTimeMS = this.options.maxTimeMS;
|
||||
}
|
||||
|
||||
super.executeCommand(server, cmd, (err, response) => {
|
||||
if (err && err.code !== MONGODB_ERROR_CODES.NamespaceNotFound) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(
|
||||
undefined,
|
||||
(response &&
|
||||
response.cursor &&
|
||||
response.cursor.firstBatch &&
|
||||
response.cursor.firstBatch[0].n) ||
|
||||
0
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
executeLegacy(server, callback) {
|
||||
const cmd = { count: this.collectionName };
|
||||
|
||||
const options = this.options;
|
||||
if (options.query) {
|
||||
cmd.query = options.query;
|
||||
}
|
||||
if (options.hint) {
|
||||
cmd.hint = options.hint;
|
||||
}
|
||||
if (typeof options.maxTimeMS === 'number') {
|
||||
cmd.maxTimeMS = options.maxTimeMS;
|
||||
}
|
||||
if (typeof options.skip === 'number') {
|
||||
cmd.skip = options.skip;
|
||||
}
|
||||
|
||||
if (typeof options.limit === 'number') {
|
||||
cmd.limit = options.limit;
|
||||
}
|
||||
|
||||
if (options.hint) {
|
||||
cmd.hint = options.hint;
|
||||
}
|
||||
|
||||
super.executeCommand(server, cmd, (err, response) => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
|
||||
116
node_modules/mongodb/lib/operations/execute_operation.js
generated
vendored
116
node_modules/mongodb/lib/operations/execute_operation.js
generated
vendored
@@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const maybePromise = require('../utils').maybePromise;
|
||||
const MongoError = require('../core/error').MongoError;
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const OperationBase = require('./operation').OperationBase;
|
||||
@@ -21,7 +22,7 @@ const isUnifiedTopology = require('../core/utils').isUnifiedTopology;
|
||||
* @param {Operation} operation The operation to execute
|
||||
* @param {function} callback The command result callback
|
||||
*/
|
||||
function executeOperation(topology, operation, callback) {
|
||||
function executeOperation(topology, operation, cb) {
|
||||
if (topology == null) {
|
||||
throw new TypeError('This method requires a valid topology instance');
|
||||
}
|
||||
@@ -30,64 +31,57 @@ function executeOperation(topology, operation, callback) {
|
||||
throw new TypeError('This method requires a valid operation instance');
|
||||
}
|
||||
|
||||
if (isUnifiedTopology(topology) && topology.shouldCheckForSessionSupport()) {
|
||||
return selectServerForSessionSupport(topology, operation, callback);
|
||||
}
|
||||
|
||||
const Promise = topology.s.promiseLibrary;
|
||||
|
||||
// The driver sessions spec mandates that we implicitly create sessions for operations
|
||||
// that are not explicitly provided with a session.
|
||||
let session, owner;
|
||||
if (topology.hasSessionSupport()) {
|
||||
if (operation.session == null) {
|
||||
owner = Symbol();
|
||||
session = topology.startSession({ owner });
|
||||
operation.session = session;
|
||||
} else if (operation.session.hasEnded) {
|
||||
throw new MongoError('Use of expired sessions is not permitted');
|
||||
return maybePromise(topology, cb, callback => {
|
||||
if (isUnifiedTopology(topology) && topology.shouldCheckForSessionSupport()) {
|
||||
// Recursive call to executeOperation after a server selection
|
||||
return selectServerForSessionSupport(topology, operation, callback);
|
||||
}
|
||||
}
|
||||
|
||||
let result;
|
||||
if (typeof callback !== 'function') {
|
||||
result = new Promise((resolve, reject) => {
|
||||
callback = (err, res) => {
|
||||
if (err) return reject(err);
|
||||
resolve(res);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function executeCallback(err, result) {
|
||||
if (session && session.owner === owner) {
|
||||
session.endSession();
|
||||
if (operation.session === session) {
|
||||
operation.clearSession();
|
||||
// The driver sessions spec mandates that we implicitly create sessions for operations
|
||||
// that are not explicitly provided with a session.
|
||||
let session, owner;
|
||||
if (topology.hasSessionSupport()) {
|
||||
if (operation.session == null) {
|
||||
owner = Symbol();
|
||||
session = topology.startSession({ owner });
|
||||
operation.session = session;
|
||||
} else if (operation.session.hasEnded) {
|
||||
return callback(new MongoError('Use of expired sessions is not permitted'));
|
||||
}
|
||||
} else if (operation.session) {
|
||||
// If the user passed an explicit session and we are still, after server selection,
|
||||
// trying to run against a topology that doesn't support sessions we error out.
|
||||
return callback(new MongoError('Current topology does not support sessions'));
|
||||
}
|
||||
|
||||
callback(err, result);
|
||||
}
|
||||
|
||||
try {
|
||||
if (operation.hasAspect(Aspect.EXECUTE_WITH_SELECTION)) {
|
||||
executeWithServerSelection(topology, operation, executeCallback);
|
||||
} else {
|
||||
operation.execute(executeCallback);
|
||||
}
|
||||
} catch (e) {
|
||||
if (session && session.owner === owner) {
|
||||
session.endSession();
|
||||
if (operation.session === session) {
|
||||
operation.clearSession();
|
||||
function executeCallback(err, result) {
|
||||
if (session && session.owner === owner) {
|
||||
session.endSession();
|
||||
if (operation.session === session) {
|
||||
operation.clearSession();
|
||||
}
|
||||
}
|
||||
|
||||
callback(err, result);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
try {
|
||||
if (operation.hasAspect(Aspect.EXECUTE_WITH_SELECTION)) {
|
||||
executeWithServerSelection(topology, operation, executeCallback);
|
||||
} else {
|
||||
operation.execute(executeCallback);
|
||||
}
|
||||
} catch (error) {
|
||||
if (session && session.owner === owner) {
|
||||
session.endSession();
|
||||
if (operation.session === session) {
|
||||
operation.clearSession();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
callback(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function supportsRetryableReads(server) {
|
||||
@@ -139,7 +133,6 @@ function executeWithServerSelection(topology, operation, callback) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
|
||||
const shouldRetryReads =
|
||||
topology.s.options.retryReads !== false &&
|
||||
operation.session &&
|
||||
@@ -156,31 +149,16 @@ function executeWithServerSelection(topology, operation, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: This is only supported for unified topology, it should go away once
|
||||
// we remove support for legacy topology types.
|
||||
// The Unified Topology runs serverSelection before executing every operation
|
||||
// Session support is determined by the result of a monitoring check triggered by this selection
|
||||
function selectServerForSessionSupport(topology, operation, callback) {
|
||||
const Promise = topology.s.promiseLibrary;
|
||||
|
||||
let result;
|
||||
if (typeof callback !== 'function') {
|
||||
result = new Promise((resolve, reject) => {
|
||||
callback = (err, result) => {
|
||||
if (err) return reject(err);
|
||||
resolve(result);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
topology.selectServer(ReadPreference.primaryPreferred, err => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
executeOperation(topology, operation, callback);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = executeOperation;
|
||||
|
||||
23
node_modules/mongodb/lib/operations/find.js
generated
vendored
23
node_modules/mongodb/lib/operations/find.js
generated
vendored
@@ -3,7 +3,9 @@
|
||||
const OperationBase = require('./operation').OperationBase;
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
const resolveReadPreference = require('../utils').resolveReadPreference;
|
||||
const ReadPreference = require('../core').ReadPreference;
|
||||
const maxWireVersion = require('../core/utils').maxWireVersion;
|
||||
const MongoError = require('../core/error').MongoError;
|
||||
|
||||
class FindOperation extends OperationBase {
|
||||
constructor(collection, ns, command, options) {
|
||||
@@ -11,16 +13,28 @@ class FindOperation extends OperationBase {
|
||||
|
||||
this.ns = ns;
|
||||
this.cmd = command;
|
||||
this.readPreference = resolveReadPreference(collection, this.options);
|
||||
this.readPreference = ReadPreference.resolve(collection, this.options);
|
||||
}
|
||||
|
||||
execute(server, callback) {
|
||||
// copied from `CommandOperationV2`, to be subclassed in the future
|
||||
this.server = server;
|
||||
|
||||
const cursorState = this.cursorState || {};
|
||||
// updates readPreference if setReadPreference was called on the cursor
|
||||
this.readPreference = ReadPreference.resolve(this, this.options);
|
||||
|
||||
if (typeof this.cmd.allowDiskUse !== 'undefined' && maxWireVersion(server) < 4) {
|
||||
callback(new MongoError('The `allowDiskUse` option is not supported on MongoDB < 3.2'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.explain) {
|
||||
// We need to manually ensure explain is in the options.
|
||||
this.options.explain = this.explain.verbosity;
|
||||
}
|
||||
|
||||
// TOOD: use `MongoDBNamespace` through and through
|
||||
const cursorState = this.cursorState || {};
|
||||
server.query(this.ns.toString(), this.cmd, cursorState, this.options, callback);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +42,8 @@ class FindOperation extends OperationBase {
|
||||
defineAspects(FindOperation, [
|
||||
Aspect.READ_OPERATION,
|
||||
Aspect.RETRYABLE,
|
||||
Aspect.EXECUTE_WITH_SELECTION
|
||||
Aspect.EXECUTE_WITH_SELECTION,
|
||||
Aspect.EXPLAINABLE
|
||||
]);
|
||||
|
||||
module.exports = FindOperation;
|
||||
|
||||
32
node_modules/mongodb/lib/operations/find_and_modify.js
generated
vendored
32
node_modules/mongodb/lib/operations/find_and_modify.js
generated
vendored
@@ -8,6 +8,11 @@ const executeCommand = require('./db_ops').executeCommand;
|
||||
const formattedOrderClause = require('../utils').formattedOrderClause;
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const ReadPreference = require('../core').ReadPreference;
|
||||
const maxWireVersion = require('../core/utils').maxWireVersion;
|
||||
const MongoError = require('../error').MongoError;
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
const decorateWithExplain = require('../utils').decorateWithExplain;
|
||||
|
||||
class FindAndModifyOperation extends OperationBase {
|
||||
constructor(collection, query, sort, doc, options) {
|
||||
@@ -27,7 +32,7 @@ class FindAndModifyOperation extends OperationBase {
|
||||
let options = this.options;
|
||||
|
||||
// Create findAndModify command object
|
||||
const queryObject = {
|
||||
let queryObject = {
|
||||
findAndModify: coll.collectionName,
|
||||
query: query
|
||||
};
|
||||
@@ -86,6 +91,29 @@ class FindAndModifyOperation extends OperationBase {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
if (options.hint) {
|
||||
// TODO: once this method becomes a CommandOperationV2 we will have the server
|
||||
// in place to check.
|
||||
const unacknowledgedWrite = options.writeConcern && options.writeConcern.w === 0;
|
||||
if (unacknowledgedWrite || maxWireVersion(coll.s.topology) < 8) {
|
||||
callback(
|
||||
new MongoError('The current topology does not support a hint on findAndModify commands')
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
queryObject.hint = options.hint;
|
||||
}
|
||||
|
||||
if (this.explain) {
|
||||
if (maxWireVersion(coll.s.topology) < 4) {
|
||||
callback(new MongoError(`server does not support explain on findAndModify`));
|
||||
return;
|
||||
}
|
||||
queryObject = decorateWithExplain(queryObject, this.explain);
|
||||
}
|
||||
|
||||
// Execute the command
|
||||
executeCommand(coll.s.db, queryObject, options, (err, result) => {
|
||||
if (err) return handleCallback(callback, err, null);
|
||||
@@ -95,4 +123,6 @@ class FindAndModifyOperation extends OperationBase {
|
||||
}
|
||||
}
|
||||
|
||||
defineAspects(FindAndModifyOperation, [Aspect.EXPLAINABLE]);
|
||||
|
||||
module.exports = FindAndModifyOperation;
|
||||
|
||||
4
node_modules/mongodb/lib/operations/find_one.js
generated
vendored
4
node_modules/mongodb/lib/operations/find_one.js
generated
vendored
@@ -3,6 +3,8 @@
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const OperationBase = require('./operation').OperationBase;
|
||||
const toError = require('../utils').toError;
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
|
||||
class FindOneOperation extends OperationBase {
|
||||
constructor(collection, query, options) {
|
||||
@@ -34,4 +36,6 @@ class FindOneOperation extends OperationBase {
|
||||
}
|
||||
}
|
||||
|
||||
defineAspects(FindOneOperation, [Aspect.EXPLAINABLE]);
|
||||
|
||||
module.exports = FindOneOperation;
|
||||
|
||||
5
node_modules/mongodb/lib/operations/find_one_and_delete.js
generated
vendored
5
node_modules/mongodb/lib/operations/find_one_and_delete.js
generated
vendored
@@ -9,6 +9,11 @@ class FindOneAndDeleteOperation extends FindAndModifyOperation {
|
||||
finalOptions.fields = options.projection;
|
||||
finalOptions.remove = true;
|
||||
|
||||
// Basic validation
|
||||
if (filter == null || typeof filter !== 'object') {
|
||||
throw new TypeError('Filter parameter must be an object');
|
||||
}
|
||||
|
||||
super(collection, filter, finalOptions.sort, null, finalOptions);
|
||||
}
|
||||
}
|
||||
|
||||
23
node_modules/mongodb/lib/operations/find_one_and_replace.js
generated
vendored
23
node_modules/mongodb/lib/operations/find_one_and_replace.js
generated
vendored
@@ -1,15 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
const MongoError = require('../core').MongoError;
|
||||
const FindAndModifyOperation = require('./find_and_modify');
|
||||
const hasAtomicOperators = require('../utils').hasAtomicOperators;
|
||||
|
||||
class FindOneAndReplaceOperation extends FindAndModifyOperation {
|
||||
constructor(collection, filter, replacement, options) {
|
||||
if ('returnDocument' in options && 'returnOriginal' in options) {
|
||||
throw new MongoError(
|
||||
'findOneAndReplace option returnOriginal is deprecated in favor of returnDocument and cannot be combined'
|
||||
);
|
||||
}
|
||||
// Final options
|
||||
const finalOptions = Object.assign({}, options);
|
||||
finalOptions.fields = options.projection;
|
||||
finalOptions.update = true;
|
||||
finalOptions.new = options.returnOriginal !== void 0 ? !options.returnOriginal : false;
|
||||
finalOptions.upsert = options.upsert !== void 0 ? !!options.upsert : false;
|
||||
finalOptions.new = options.returnDocument === 'after' || options.returnOriginal === false;
|
||||
finalOptions.upsert = options.upsert === true;
|
||||
|
||||
if (filter == null || typeof filter !== 'object') {
|
||||
throw new TypeError('Filter parameter must be an object');
|
||||
}
|
||||
|
||||
if (replacement == null || typeof replacement !== 'object') {
|
||||
throw new TypeError('Replacement parameter must be an object');
|
||||
}
|
||||
|
||||
if (hasAtomicOperators(replacement)) {
|
||||
throw new TypeError('Replacement document must not contain atomic operators');
|
||||
}
|
||||
|
||||
super(collection, filter, finalOptions.sort, replacement, finalOptions);
|
||||
}
|
||||
|
||||
24
node_modules/mongodb/lib/operations/find_one_and_update.js
generated
vendored
24
node_modules/mongodb/lib/operations/find_one_and_update.js
generated
vendored
@@ -1,16 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
const MongoError = require('../core').MongoError;
|
||||
const FindAndModifyOperation = require('./find_and_modify');
|
||||
const hasAtomicOperators = require('../utils').hasAtomicOperators;
|
||||
|
||||
class FindOneAndUpdateOperation extends FindAndModifyOperation {
|
||||
constructor(collection, filter, update, options) {
|
||||
if ('returnDocument' in options && 'returnOriginal' in options) {
|
||||
throw new MongoError(
|
||||
'findOneAndUpdate option returnOriginal is deprecated in favor of returnDocument and cannot be combined'
|
||||
);
|
||||
}
|
||||
// Final options
|
||||
const finalOptions = Object.assign({}, options);
|
||||
finalOptions.fields = options.projection;
|
||||
finalOptions.update = true;
|
||||
finalOptions.new =
|
||||
typeof options.returnOriginal === 'boolean' ? !options.returnOriginal : false;
|
||||
finalOptions.upsert = typeof options.upsert === 'boolean' ? options.upsert : false;
|
||||
finalOptions.new = options.returnDocument === 'after' || options.returnOriginal === false;
|
||||
finalOptions.upsert = options.upsert === true;
|
||||
|
||||
if (filter == null || typeof filter !== 'object') {
|
||||
throw new TypeError('Filter parameter must be an object');
|
||||
}
|
||||
|
||||
if (update == null || typeof update !== 'object') {
|
||||
throw new TypeError('Update parameter must be an object');
|
||||
}
|
||||
|
||||
if (!hasAtomicOperators(update)) {
|
||||
throw new TypeError('Update document requires atomic operators');
|
||||
}
|
||||
|
||||
super(collection, filter, finalOptions.sort, update, finalOptions);
|
||||
}
|
||||
|
||||
4
node_modules/mongodb/lib/operations/geo_haystack_search.js
generated
vendored
4
node_modules/mongodb/lib/operations/geo_haystack_search.js
generated
vendored
@@ -7,7 +7,7 @@ const decorateCommand = require('../utils').decorateCommand;
|
||||
const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
|
||||
const executeCommand = require('./db_ops').executeCommand;
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const resolveReadPreference = require('../utils').resolveReadPreference;
|
||||
const ReadPreference = require('../core').ReadPreference;
|
||||
const toError = require('../utils').toError;
|
||||
|
||||
/**
|
||||
@@ -58,7 +58,7 @@ class GeoHaystackSearchOperation extends OperationBase {
|
||||
|
||||
options = Object.assign({}, options);
|
||||
// Ensure we have the right read preference inheritance
|
||||
options.readPreference = resolveReadPreference(coll, options);
|
||||
options.readPreference = ReadPreference.resolve(coll, options);
|
||||
|
||||
// Do we have a readConcern specified
|
||||
decorateWithReadConcern(commandObject, coll, options);
|
||||
|
||||
6
node_modules/mongodb/lib/operations/insert_many.js
generated
vendored
6
node_modules/mongodb/lib/operations/insert_many.js
generated
vendored
@@ -30,11 +30,7 @@ class InsertManyOperation extends OperationBase {
|
||||
docs = prepareDocs(coll, docs, options);
|
||||
|
||||
// Generate the bulk write operations
|
||||
const operations = [
|
||||
{
|
||||
insertMany: docs
|
||||
}
|
||||
];
|
||||
const operations = docs.map(document => ({ insertOne: { document } }));
|
||||
|
||||
const bulkWriteOperation = new BulkWriteOperation(coll, operations, options);
|
||||
|
||||
|
||||
27
node_modules/mongodb/lib/operations/map_reduce.js
generated
vendored
27
node_modules/mongodb/lib/operations/map_reduce.js
generated
vendored
@@ -9,10 +9,16 @@ const handleCallback = require('../utils').handleCallback;
|
||||
const isObject = require('../utils').isObject;
|
||||
const loadDb = require('../dynamic_loaders').loadDb;
|
||||
const OperationBase = require('./operation').OperationBase;
|
||||
const resolveReadPreference = require('../utils').resolveReadPreference;
|
||||
const ReadPreference = require('../core').ReadPreference;
|
||||
const toError = require('../utils').toError;
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
const decorateWithExplain = require('../utils').decorateWithExplain;
|
||||
const maxWireVersion = require('../core/utils').maxWireVersion;
|
||||
const MongoError = require('../error').MongoError;
|
||||
|
||||
const exclusionList = [
|
||||
'explain',
|
||||
'readPreference',
|
||||
'session',
|
||||
'bypassDocumentValidation',
|
||||
@@ -59,8 +65,8 @@ class MapReduceOperation extends OperationBase {
|
||||
const reduce = this.reduce;
|
||||
let options = this.options;
|
||||
|
||||
const mapCommandHash = {
|
||||
mapreduce: coll.collectionName,
|
||||
let mapCommandHash = {
|
||||
mapReduce: coll.collectionName,
|
||||
map: map,
|
||||
reduce: reduce
|
||||
};
|
||||
@@ -80,7 +86,7 @@ class MapReduceOperation extends OperationBase {
|
||||
options = Object.assign({}, options);
|
||||
|
||||
// Ensure we have the right read preference inheritance
|
||||
options.readPreference = resolveReadPreference(coll, options);
|
||||
options.readPreference = ReadPreference.resolve(coll, options);
|
||||
|
||||
// If we have a read preference and inline is not set as output fail hard
|
||||
if (
|
||||
@@ -110,6 +116,14 @@ class MapReduceOperation extends OperationBase {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
if (this.explain) {
|
||||
if (maxWireVersion(coll.s.topology) < 9) {
|
||||
callback(new MongoError(`server does not support explain on mapReduce`));
|
||||
return;
|
||||
}
|
||||
mapCommandHash = decorateWithExplain(mapCommandHash, this.explain);
|
||||
}
|
||||
|
||||
// Execute command
|
||||
executeCommand(coll.s.db, mapCommandHash, options, (err, result) => {
|
||||
if (err) return handleCallback(callback, err);
|
||||
@@ -118,6 +132,9 @@ class MapReduceOperation extends OperationBase {
|
||||
return handleCallback(callback, toError(result));
|
||||
}
|
||||
|
||||
// If an explain operation was executed, don't process the server results
|
||||
if (this.explain) return callback(undefined, result);
|
||||
|
||||
// Create statistics value
|
||||
const stats = {};
|
||||
if (result.timeMillis) stats['processtime'] = result.timeMillis;
|
||||
@@ -187,4 +204,6 @@ function processScope(scope) {
|
||||
return new_scope;
|
||||
}
|
||||
|
||||
defineAspects(MapReduceOperation, [Aspect.EXPLAINABLE]);
|
||||
|
||||
module.exports = MapReduceOperation;
|
||||
|
||||
13
node_modules/mongodb/lib/operations/operation.js
generated
vendored
13
node_modules/mongodb/lib/operations/operation.js
generated
vendored
@@ -1,10 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
const Explain = require('../explain').Explain;
|
||||
const MongoError = require('../core/error').MongoError;
|
||||
|
||||
const Aspect = {
|
||||
READ_OPERATION: Symbol('READ_OPERATION'),
|
||||
WRITE_OPERATION: Symbol('WRITE_OPERATION'),
|
||||
RETRYABLE: Symbol('RETRYABLE'),
|
||||
EXECUTE_WITH_SELECTION: Symbol('EXECUTE_WITH_SELECTION')
|
||||
EXECUTE_WITH_SELECTION: Symbol('EXECUTE_WITH_SELECTION'),
|
||||
NO_INHERIT_OPTIONS: Symbol('NO_INHERIT_OPTIONS'),
|
||||
EXPLAINABLE: Symbol('EXPLAINABLE')
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -16,6 +21,12 @@ const Aspect = {
|
||||
class OperationBase {
|
||||
constructor(options) {
|
||||
this.options = Object.assign({}, options);
|
||||
|
||||
if (this.hasAspect(Aspect.EXPLAINABLE)) {
|
||||
this.explain = Explain.fromOptions(options);
|
||||
} else if (this.options.explain !== undefined) {
|
||||
throw new MongoError(`explain is not supported on this command`);
|
||||
}
|
||||
}
|
||||
|
||||
hasAspect(aspect) {
|
||||
|
||||
39
node_modules/mongodb/lib/operations/re_index.js
generated
vendored
39
node_modules/mongodb/lib/operations/re_index.js
generated
vendored
@@ -1,28 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
const CommandOperation = require('./command');
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
const CommandOperationV2 = require('./command_v2');
|
||||
const serverType = require('../core/sdam/common').serverType;
|
||||
const ServerType = require('../core/sdam/common').ServerType;
|
||||
const MongoError = require('../core').MongoError;
|
||||
|
||||
class ReIndexOperation extends CommandOperation {
|
||||
class ReIndexOperation extends CommandOperationV2 {
|
||||
constructor(collection, options) {
|
||||
super(collection.s.db, options, collection);
|
||||
super(collection, options);
|
||||
this.collectionName = collection.collectionName;
|
||||
}
|
||||
|
||||
_buildCommand() {
|
||||
const collection = this.collection;
|
||||
|
||||
const cmd = { reIndex: collection.collectionName };
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
execute(callback) {
|
||||
super.execute((err, result) => {
|
||||
if (callback == null) return;
|
||||
if (err) return handleCallback(callback, err, null);
|
||||
handleCallback(callback, null, result.ok ? true : false);
|
||||
execute(server, callback) {
|
||||
if (serverType(server) !== ServerType.Standalone) {
|
||||
callback(new MongoError(`reIndex can only be executed on standalone servers.`));
|
||||
return;
|
||||
}
|
||||
super.executeCommand(server, { reIndex: this.collectionName }, (err, result) => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
callback(null, !!result.ok);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
defineAspects(ReIndexOperation, [Aspect.EXECUTE_WITH_SELECTION]);
|
||||
|
||||
module.exports = ReIndexOperation;
|
||||
|
||||
15
node_modules/mongodb/lib/operations/replace_one.js
generated
vendored
15
node_modules/mongodb/lib/operations/replace_one.js
generated
vendored
@@ -2,27 +2,34 @@
|
||||
|
||||
const OperationBase = require('./operation').OperationBase;
|
||||
const updateDocuments = require('./common_functions').updateDocuments;
|
||||
const hasAtomicOperators = require('../utils').hasAtomicOperators;
|
||||
|
||||
class ReplaceOneOperation extends OperationBase {
|
||||
constructor(collection, filter, doc, options) {
|
||||
constructor(collection, filter, replacement, options) {
|
||||
super(options);
|
||||
|
||||
if (hasAtomicOperators(replacement)) {
|
||||
throw new TypeError('Replacement document must not contain atomic operators');
|
||||
}
|
||||
|
||||
this.collection = collection;
|
||||
this.filter = filter;
|
||||
this.doc = doc;
|
||||
this.replacement = replacement;
|
||||
}
|
||||
|
||||
execute(callback) {
|
||||
const coll = this.collection;
|
||||
const filter = this.filter;
|
||||
const doc = this.doc;
|
||||
const replacement = this.replacement;
|
||||
const options = this.options;
|
||||
|
||||
// Set single document update
|
||||
options.multi = false;
|
||||
|
||||
// Execute update
|
||||
updateDocuments(coll, filter, doc, options, (err, r) => replaceCallback(err, r, doc, callback));
|
||||
updateDocuments(coll, filter, replacement, options, (err, r) =>
|
||||
replaceCallback(err, r, replacement, callback)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
30
node_modules/mongodb/lib/operations/update_many.js
generated
vendored
30
node_modules/mongodb/lib/operations/update_many.js
generated
vendored
@@ -1,13 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
const OperationBase = require('./operation').OperationBase;
|
||||
const updateCallback = require('./common_functions').updateCallback;
|
||||
const updateDocuments = require('./common_functions').updateDocuments;
|
||||
const hasAtomicOperators = require('../utils').hasAtomicOperators;
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
|
||||
class UpdateManyOperation extends OperationBase {
|
||||
constructor(collection, filter, update, options) {
|
||||
super(options);
|
||||
|
||||
if (!hasAtomicOperators(update)) {
|
||||
throw new TypeError('Update document requires atomic operators');
|
||||
}
|
||||
|
||||
this.collection = collection;
|
||||
this.filter = filter;
|
||||
this.update = update;
|
||||
@@ -22,8 +28,28 @@ class UpdateManyOperation extends OperationBase {
|
||||
// Set single document update
|
||||
options.multi = true;
|
||||
// Execute update
|
||||
updateDocuments(coll, filter, update, options, (err, r) => updateCallback(err, r, callback));
|
||||
updateDocuments(coll, filter, update, options, (err, r) => {
|
||||
if (callback == null) return;
|
||||
if (err) return callback(err);
|
||||
if (r == null) return callback(null, { result: { ok: 1 } });
|
||||
|
||||
// If an explain operation was executed, don't process the server results
|
||||
if (this.explain) return callback(undefined, r.result);
|
||||
|
||||
r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
|
||||
r.upsertedId =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length > 0
|
||||
? r.result.upserted[0] // FIXME(major): should be `r.result.upserted[0]._id`
|
||||
: null;
|
||||
r.upsertedCount =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
|
||||
r.matchedCount =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
|
||||
callback(null, r);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
defineAspects(UpdateManyOperation, [Aspect.EXPLAINABLE]);
|
||||
|
||||
module.exports = UpdateManyOperation;
|
||||
|
||||
43
node_modules/mongodb/lib/operations/update_one.js
generated
vendored
43
node_modules/mongodb/lib/operations/update_one.js
generated
vendored
@@ -2,11 +2,18 @@
|
||||
|
||||
const OperationBase = require('./operation').OperationBase;
|
||||
const updateDocuments = require('./common_functions').updateDocuments;
|
||||
const hasAtomicOperators = require('../utils').hasAtomicOperators;
|
||||
const Aspect = require('./operation').Aspect;
|
||||
const defineAspects = require('./operation').defineAspects;
|
||||
|
||||
class UpdateOneOperation extends OperationBase {
|
||||
constructor(collection, filter, update, options) {
|
||||
super(options);
|
||||
|
||||
if (!hasAtomicOperators(update)) {
|
||||
throw new TypeError('Update document requires atomic operators');
|
||||
}
|
||||
|
||||
this.collection = collection;
|
||||
this.filter = filter;
|
||||
this.update = update;
|
||||
@@ -21,24 +28,28 @@ class UpdateOneOperation extends OperationBase {
|
||||
// Set single document update
|
||||
options.multi = false;
|
||||
// Execute update
|
||||
updateDocuments(coll, filter, update, options, (err, r) => updateCallback(err, r, callback));
|
||||
updateDocuments(coll, filter, update, options, (err, r) => {
|
||||
if (callback == null) return;
|
||||
if (err) return callback(err);
|
||||
if (r == null) return callback(null, { result: { ok: 1 } });
|
||||
|
||||
// If an explain operation was executed, don't process the server results
|
||||
if (this.explain) return callback(undefined, r.result);
|
||||
|
||||
r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
|
||||
r.upsertedId =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length > 0
|
||||
? r.result.upserted[0] // FIXME(major): should be `r.result.upserted[0]._id`
|
||||
: null;
|
||||
r.upsertedCount =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
|
||||
r.matchedCount =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
|
||||
callback(null, r);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateCallback(err, r, callback) {
|
||||
if (callback == null) return;
|
||||
if (err) return callback(err);
|
||||
if (r == null) return callback(null, { result: { ok: 1 } });
|
||||
r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
|
||||
r.upsertedId =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length > 0
|
||||
? r.result.upserted[0] // FIXME(major): should be `r.result.upserted[0]._id`
|
||||
: null;
|
||||
r.upsertedCount =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
|
||||
r.matchedCount =
|
||||
Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
|
||||
callback(null, r);
|
||||
}
|
||||
defineAspects(UpdateOneOperation, [Aspect.EXPLAINABLE]);
|
||||
|
||||
module.exports = UpdateOneOperation;
|
||||
|
||||
5
node_modules/mongodb/lib/operations/validate_collection.js
generated
vendored
5
node_modules/mongodb/lib/operations/validate_collection.js
generated
vendored
@@ -8,14 +8,13 @@ class ValidateCollectionOperation extends CommandOperation {
|
||||
let command = { validate: collectionName };
|
||||
const keys = Object.keys(options);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (options.hasOwnProperty(keys[i]) && keys[i] !== 'session') {
|
||||
if (Object.prototype.hasOwnProperty.call(options, keys[i]) && keys[i] !== 'session') {
|
||||
command[keys[i]] = options[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
super(admin.s.db, options, null, command);
|
||||
|
||||
this.collectionName;
|
||||
this.collectionName = collectionName;
|
||||
}
|
||||
|
||||
execute(callback) {
|
||||
|
||||
5
node_modules/mongodb/lib/topologies/mongos.js
generated
vendored
5
node_modules/mongodb/lib/topologies/mongos.js
generated
vendored
@@ -54,6 +54,7 @@ var legalOptionNames = [
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'bsonRegExp',
|
||||
'promiseLibrary',
|
||||
'monitorCommands'
|
||||
];
|
||||
@@ -82,9 +83,9 @@ var legalOptionNames = [
|
||||
* @param {object} [options.socketOptions] Socket options
|
||||
* @param {boolean} [options.socketOptions.noDelay=true] TCP Socket NoDelay option.
|
||||
* @param {boolean} [options.socketOptions.keepAlive=true] TCP Connection keep alive enabled
|
||||
* @param {number} [options.socketOptions.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
|
||||
* @param {number} [options.socketOptions.keepAliveInitialDelay=120000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
|
||||
* @param {number} [options.socketOptions.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
|
||||
* @param {number} [options.socketOptions.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
|
||||
* @param {number} [options.socketOptions.socketTimeoutMS=0] How long a send or receive on a socket can take before timing out
|
||||
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
|
||||
* @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
|
||||
* @fires Mongos#connect
|
||||
|
||||
4
node_modules/mongodb/lib/topologies/native_topology.js
generated
vendored
4
node_modules/mongodb/lib/topologies/native_topology.js
generated
vendored
@@ -44,6 +44,10 @@ class NativeTopology extends Topology {
|
||||
// Translate all the options to the core types
|
||||
clonedOptions = translateOptions(clonedOptions, socketOptions);
|
||||
|
||||
clonedOptions.serverApi = options.serverApi;
|
||||
|
||||
clonedOptions.useUnifiedTopology = options.useUnifiedTopology;
|
||||
|
||||
super(servers, clonedOptions);
|
||||
}
|
||||
|
||||
|
||||
3
node_modules/mongodb/lib/topologies/replset.js
generated
vendored
3
node_modules/mongodb/lib/topologies/replset.js
generated
vendored
@@ -60,6 +60,7 @@ var legalOptionNames = [
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'bsonRegExp',
|
||||
'maxStalenessSeconds',
|
||||
'promiseLibrary',
|
||||
'minSize',
|
||||
@@ -92,7 +93,7 @@ var legalOptionNames = [
|
||||
* @param {object} [options.socketOptions] Socket options
|
||||
* @param {boolean} [options.socketOptions.noDelay=true] TCP Socket NoDelay option.
|
||||
* @param {boolean} [options.socketOptions.keepAlive=true] TCP Connection keep alive enabled
|
||||
* @param {number} [options.socketOptions.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
|
||||
* @param {number} [options.socketOptions.keepAliveInitialDelay=120000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
|
||||
* @param {number} [options.socketOptions.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
|
||||
* @param {number} [options.socketOptions.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
|
||||
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
|
||||
|
||||
5
node_modules/mongodb/lib/topologies/server.js
generated
vendored
5
node_modules/mongodb/lib/topologies/server.js
generated
vendored
@@ -56,6 +56,7 @@ var legalOptionNames = [
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'bsonRegExp',
|
||||
'compression',
|
||||
'promiseLibrary',
|
||||
'monitorCommands'
|
||||
@@ -84,9 +85,9 @@ var legalOptionNames = [
|
||||
* @param {boolean} [options.socketOptions.autoReconnect=true] Reconnect on error.
|
||||
* @param {boolean} [options.socketOptions.noDelay=true] TCP Socket NoDelay option.
|
||||
* @param {boolean} [options.socketOptions.keepAlive=true] TCP Connection keep alive enabled
|
||||
* @param {number} [options.socketOptions.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
|
||||
* @param {number} [options.socketOptions.keepAliveInitialDelay=120000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
|
||||
* @param {number} [options.socketOptions.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
|
||||
* @param {number} [options.socketOptions.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
|
||||
* @param {number} [options.socketOptions.socketTimeoutMS=0] How long a send or receive on a socket can take before timing out
|
||||
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
|
||||
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
|
||||
* @param {boolean} [options.monitoring=true] Triggers the server instance to call ismaster
|
||||
|
||||
8
node_modules/mongodb/lib/topologies/topology_base.js
generated
vendored
8
node_modules/mongodb/lib/topologies/topology_base.js
generated
vendored
@@ -3,7 +3,7 @@
|
||||
const EventEmitter = require('events'),
|
||||
MongoError = require('../core').MongoError,
|
||||
f = require('util').format,
|
||||
translateReadPreference = require('../utils').translateReadPreference,
|
||||
ReadPreference = require('../core').ReadPreference,
|
||||
ClientSession = require('../core').Sessions.ClientSession;
|
||||
|
||||
// The store of ops
|
||||
@@ -293,7 +293,7 @@ class TopologyBase extends EventEmitter {
|
||||
|
||||
// Command
|
||||
command(ns, cmd, options, callback) {
|
||||
this.s.coreTopology.command(ns.toString(), cmd, translateReadPreference(options), callback);
|
||||
this.s.coreTopology.command(ns.toString(), cmd, ReadPreference.translate(options), callback);
|
||||
}
|
||||
|
||||
// Insert
|
||||
@@ -314,7 +314,7 @@ class TopologyBase extends EventEmitter {
|
||||
// IsConnected
|
||||
isConnected(options) {
|
||||
options = options || {};
|
||||
options = translateReadPreference(options);
|
||||
options = ReadPreference.translate(options);
|
||||
|
||||
return this.s.coreTopology.isConnected(options);
|
||||
}
|
||||
@@ -327,7 +327,7 @@ class TopologyBase extends EventEmitter {
|
||||
// Cursor
|
||||
cursor(ns, cmd, options) {
|
||||
options = options || {};
|
||||
options = translateReadPreference(options);
|
||||
options = ReadPreference.translate(options);
|
||||
options.disconnectHandler = this.s.store;
|
||||
options.topology = this;
|
||||
|
||||
|
||||
44
node_modules/mongodb/lib/url_parser.js
generated
vendored
44
node_modules/mongodb/lib/url_parser.js
generated
vendored
@@ -1,11 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const ReadPreference = require('./core').ReadPreference,
|
||||
parser = require('url'),
|
||||
f = require('util').format,
|
||||
Logger = require('./core').Logger,
|
||||
dns = require('dns');
|
||||
const ReadPreference = require('./core').ReadPreference;
|
||||
const parser = require('url');
|
||||
const f = require('util').format;
|
||||
const Logger = require('./core').Logger;
|
||||
const dns = require('dns');
|
||||
const ReadConcern = require('./read_concern');
|
||||
const qs = require('querystring');
|
||||
const MongoParseError = require('./core/error').MongoParseError;
|
||||
|
||||
module.exports = function(url, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
@@ -33,7 +35,8 @@ module.exports = function(url, options, callback) {
|
||||
|
||||
result.domainLength = result.hostname.split('.').length;
|
||||
|
||||
if (result.pathname && result.pathname.match(',')) {
|
||||
const hostname = url.substring('mongodb+srv://'.length).split('/')[0];
|
||||
if (hostname.match(',')) {
|
||||
return callback(new Error('Invalid URI, cannot contain multiple hostnames'));
|
||||
}
|
||||
|
||||
@@ -87,23 +90,29 @@ module.exports = function(url, options, callback) {
|
||||
}
|
||||
|
||||
dns.resolveTxt(result.host, function(err, record) {
|
||||
if (err && err.code !== 'ENODATA') return callback(err);
|
||||
if (err && err.code !== 'ENODATA' && err.code !== 'ENOTFOUND') return callback(err);
|
||||
if (err && err.code === 'ENODATA') record = null;
|
||||
|
||||
if (record) {
|
||||
if (record.length > 1) {
|
||||
return callback(new Error('Multiple text records not allowed'));
|
||||
return callback(new MongoParseError('Multiple text records not allowed'));
|
||||
}
|
||||
|
||||
record = record[0];
|
||||
if (record.length > 1) record = record.join('');
|
||||
else record = record[0];
|
||||
|
||||
if (!record.includes('authSource') && !record.includes('replicaSet')) {
|
||||
return callback(new Error('Text record must only set `authSource` or `replicaSet`'));
|
||||
record = record[0].join('');
|
||||
const parsedRecord = qs.parse(record);
|
||||
const items = Object.keys(parsedRecord);
|
||||
if (Object.keys(items).some(k => k.toLowerCase() === 'loadbalanced')) {
|
||||
return callback(new MongoParseError('Load balancer mode requires driver version 4+'));
|
||||
}
|
||||
if (items.some(item => item !== 'authSource' && item !== 'replicaSet')) {
|
||||
return callback(
|
||||
new MongoParseError('Text record must only set `authSource` or `replicaSet`')
|
||||
);
|
||||
}
|
||||
|
||||
connectionStringOptions.push(record);
|
||||
if (items.length > 0) {
|
||||
connectionStringOptions.push(record);
|
||||
}
|
||||
}
|
||||
|
||||
// Add any options to the connection string
|
||||
@@ -372,6 +381,11 @@ function parseConnectionString(url, options) {
|
||||
object.dbName = dbName || 'admin';
|
||||
// Split up all the options
|
||||
urlOptions = (query_string_part || '').split(/[&;]/);
|
||||
|
||||
if (urlOptions.some(k => k.toLowerCase() === 'loadbalanced')) {
|
||||
throw new MongoParseError('Load balancer mode requires driver version 4+');
|
||||
}
|
||||
|
||||
// Ugh, we have to figure out which options go to which constructor manually.
|
||||
urlOptions.forEach(function(opt) {
|
||||
if (!opt) return;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user