mirror of
https://github.com/bvanroll/rpiRadio.git
synced 2025-08-30 20:42:44 +00:00
Initial Commit
This commit is contained in:
328
ProjectNow/NodeServer/node_modules/mongodb/lib/admin.js
generated
vendored
Normal file
328
ProjectNow/NodeServer/node_modules/mongodb/lib/admin.js
generated
vendored
Normal file
@@ -0,0 +1,328 @@
|
||||
'use strict';
|
||||
|
||||
const toError = require('./utils').toError;
|
||||
const shallowClone = require('./utils').shallowClone;
|
||||
const executeOperation = require('./utils').executeOperation;
|
||||
const applyWriteConcern = require('./utils').applyWriteConcern;
|
||||
|
||||
/**
|
||||
* @fileOverview The **Admin** class is an internal class that allows convenient access to
|
||||
* the admin functionality and commands for MongoDB.
|
||||
*
|
||||
* **ADMIN Cannot directly be instantiated**
|
||||
* @example
|
||||
* const MongoClient = require('mongodb').MongoClient;
|
||||
* const test = require('assert');
|
||||
* // Connection url
|
||||
* const url = 'mongodb://localhost:27017';
|
||||
* // Database Name
|
||||
* const dbName = 'test';
|
||||
*
|
||||
* // Connect using MongoClient
|
||||
* MongoClient.connect(url, function(err, client) {
|
||||
* // Use the admin database for the operation
|
||||
* const adminDb = client.db(dbName).admin();
|
||||
*
|
||||
* // List all the available databases
|
||||
* adminDb.listDatabases(function(err, dbs) {
|
||||
* test.equal(null, err);
|
||||
* test.ok(dbs.databases.length > 0);
|
||||
* client.close();
|
||||
* });
|
||||
* });
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a new Admin instance (INTERNAL TYPE, do not instantiate directly)
|
||||
* @class
|
||||
* @return {Admin} a collection instance.
|
||||
*/
|
||||
var Admin = function(db, topology, promiseLibrary) {
|
||||
if (!(this instanceof Admin)) return new Admin(db, topology);
|
||||
|
||||
// Internal state
|
||||
this.s = {
|
||||
db: db,
|
||||
topology: topology,
|
||||
promiseLibrary: promiseLibrary
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* The callback format for results
|
||||
* @callback Admin~resultCallback
|
||||
* @param {MongoError} error An error instance representing the error during the execution.
|
||||
* @param {object} result The result object if the command was executed successfully.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Execute a command
|
||||
* @method
|
||||
* @param {object} command The command hash
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
|
||||
* @param {number} [options.maxTimeMS=null] Number of milliseconds to wait before aborting the query.
|
||||
* @param {Admin~resultCallback} [callback] The command result callback
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
Admin.prototype.command = function(command, options, callback) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
|
||||
options = args.length ? args.shift() : {};
|
||||
|
||||
return executeOperation(this.s.db.s.topology, this.s.db.executeDbAdminCommand.bind(this.s.db), [
|
||||
command,
|
||||
options,
|
||||
callback
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the server information for the current
|
||||
* instance of the db client
|
||||
*
|
||||
* @param {Object} [options] optional parameters for this operation
|
||||
* @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
|
||||
*/
|
||||
Admin.prototype.buildInfo = function(options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
const cmd = { buildinfo: 1 };
|
||||
return executeOperation(this.s.db.s.topology, this.s.db.executeDbAdminCommand.bind(this.s.db), [
|
||||
cmd,
|
||||
options,
|
||||
callback
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the server information for the current
|
||||
* instance of the db client
|
||||
*
|
||||
* @param {Object} [options] optional parameters for this operation
|
||||
* @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
|
||||
*/
|
||||
Admin.prototype.serverInfo = function(options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
const cmd = { buildinfo: 1 };
|
||||
return executeOperation(this.s.db.s.topology, this.s.db.executeDbAdminCommand.bind(this.s.db), [
|
||||
cmd,
|
||||
options,
|
||||
callback
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve this db's server status.
|
||||
*
|
||||
* @param {Object} [options] optional parameters for this operation
|
||||
* @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
|
||||
*/
|
||||
Admin.prototype.serverStatus = function(options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
return executeOperation(this.s.db.s.topology, serverStatus, [this, options, callback]);
|
||||
};
|
||||
|
||||
var serverStatus = function(self, options, callback) {
|
||||
self.s.db.executeDbAdminCommand({ serverStatus: 1 }, options, function(err, doc) {
|
||||
if (err == null && doc.ok === 1) {
|
||||
callback(null, doc);
|
||||
} else {
|
||||
if (err) return callback(err, false);
|
||||
return callback(toError(doc), false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Ping the MongoDB server and retrieve results
|
||||
*
|
||||
* @param {Object} [options] optional parameters for this operation
|
||||
* @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
|
||||
*/
|
||||
Admin.prototype.ping = function(options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
const cmd = { ping: 1 };
|
||||
return executeOperation(this.s.db.s.topology, this.s.db.executeDbAdminCommand.bind(this.s.db), [
|
||||
cmd,
|
||||
options,
|
||||
callback
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a user to the database.
|
||||
* @method
|
||||
* @param {string} username The username.
|
||||
* @param {string} password The password.
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {(number|string)} [options.w=null] The write concern.
|
||||
* @param {number} [options.wtimeout=null] 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 {object} [options.customData=null] Custom data associated with the user (only Mongodb 2.6 or higher)
|
||||
* @param {object[]} [options.roles=null] Roles associated with the created user (only Mongodb 2.6 or higher)
|
||||
* @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
|
||||
*/
|
||||
Admin.prototype.addUser = function(username, password, options, callback) {
|
||||
var self = this;
|
||||
var args = Array.prototype.slice.call(arguments, 2);
|
||||
callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
|
||||
|
||||
options = args.length ? args.shift() : {};
|
||||
options = options || {};
|
||||
// Get the options
|
||||
options = applyWriteConcern(shallowClone(options), { db: self.s.db });
|
||||
// Set the db name to admin
|
||||
options.dbName = 'admin';
|
||||
|
||||
return executeOperation(this.s.db.s.topology, this.s.db.addUser.bind(this.s.db), [
|
||||
username,
|
||||
password,
|
||||
options,
|
||||
callback
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a user from a database
|
||||
* @method
|
||||
* @param {string} username The username.
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {(number|string)} [options.w=null] The write concern.
|
||||
* @param {number} [options.wtimeout=null] 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 {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
|
||||
*/
|
||||
Admin.prototype.removeUser = function(username, options, callback) {
|
||||
var self = this;
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
|
||||
|
||||
options = args.length ? args.shift() : {};
|
||||
options = options || {};
|
||||
// Get the options
|
||||
options = applyWriteConcern(shallowClone(options), { db: self.s.db });
|
||||
// Set the db name
|
||||
options.dbName = 'admin';
|
||||
|
||||
return executeOperation(this.s.db.s.topology, this.s.db.removeUser.bind(this.s.db), [
|
||||
username,
|
||||
options,
|
||||
callback
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate an existing collection
|
||||
*
|
||||
* @param {string} collectionName The name of the collection to validate.
|
||||
* @param {object} [options=null] Optional 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
|
||||
*/
|
||||
Admin.prototype.validateCollection = function(collectionName, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
return executeOperation(this.s.db.s.topology, validateCollection, [
|
||||
this,
|
||||
collectionName,
|
||||
options,
|
||||
callback
|
||||
]);
|
||||
};
|
||||
|
||||
var validateCollection = function(self, collectionName, options, callback) {
|
||||
var command = { validate: collectionName };
|
||||
var keys = Object.keys(options);
|
||||
|
||||
// Decorate command with extra options
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (options.hasOwnProperty(keys[i]) && keys[i] !== 'session') {
|
||||
command[keys[i]] = options[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
self.s.db.command(command, options, function(err, doc) {
|
||||
if (err != null) return callback(err, null);
|
||||
|
||||
if (doc.ok === 0) return callback(new Error('Error with validate command'), null);
|
||||
if (doc.result != null && doc.result.constructor !== String)
|
||||
return callback(new Error('Error with validation data'), null);
|
||||
if (doc.result != null && doc.result.match(/exception|corrupt/) != null)
|
||||
return callback(new Error('Error: invalid collection ' + collectionName), null);
|
||||
if (doc.valid != null && !doc.valid)
|
||||
return callback(new Error('Error: invalid collection ' + collectionName), null);
|
||||
|
||||
return callback(null, doc);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* List the available databases
|
||||
*
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {boolean} [options.nameOnly=false] Whether the command should return only db names, or names and size info.
|
||||
* @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
|
||||
*/
|
||||
Admin.prototype.listDatabases = function(options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
var cmd = { listDatabases: 1 };
|
||||
if (options.nameOnly) cmd.nameOnly = Number(cmd.nameOnly);
|
||||
return executeOperation(this.s.db.s.topology, this.s.db.executeDbAdminCommand.bind(this.s.db), [
|
||||
cmd,
|
||||
options,
|
||||
callback
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get ReplicaSet status
|
||||
*
|
||||
* @param {Object} [options] optional parameters for this operation
|
||||
* @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
|
||||
*/
|
||||
Admin.prototype.replSetGetStatus = function(options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
return executeOperation(this.s.db.s.topology, replSetGetStatus, [this, options, callback]);
|
||||
};
|
||||
|
||||
var replSetGetStatus = function(self, options, callback) {
|
||||
self.s.db.executeDbAdminCommand({ replSetGetStatus: 1 }, options, function(err, doc) {
|
||||
if (err == null && doc.ok === 1) return callback(null, doc);
|
||||
if (err) return callback(err, false);
|
||||
callback(toError(doc), false);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Admin;
|
397
ProjectNow/NodeServer/node_modules/mongodb/lib/aggregation_cursor.js
generated
vendored
Normal file
397
ProjectNow/NodeServer/node_modules/mongodb/lib/aggregation_cursor.js
generated
vendored
Normal file
@@ -0,0 +1,397 @@
|
||||
'use strict';
|
||||
|
||||
const inherits = require('util').inherits;
|
||||
const MongoError = require('mongodb-core').MongoError;
|
||||
const Readable = require('stream').Readable;
|
||||
const CoreCursor = require('./cursor');
|
||||
|
||||
/**
|
||||
* @fileOverview The **AggregationCursor** class is an internal class that embodies an aggregation cursor on MongoDB
|
||||
* allowing for iteration over the results returned from the underlying query. It supports
|
||||
* one by one document iteration, conversion to an array or can be iterated as a Node 4.X
|
||||
* or higher stream
|
||||
*
|
||||
* **AGGREGATIONCURSOR Cannot directly be instantiated**
|
||||
* @example
|
||||
* const MongoClient = require('mongodb').MongoClient;
|
||||
* const test = require('assert');
|
||||
* // Connection url
|
||||
* const url = 'mongodb://localhost:27017';
|
||||
* // Database Name
|
||||
* const dbName = 'test';
|
||||
* // Connect using MongoClient
|
||||
* MongoClient.connect(url, function(err, client) {
|
||||
* // Create a collection we want to drop later
|
||||
* const col = client.db(dbName).collection('createIndexExample1');
|
||||
* // Insert a bunch of documents
|
||||
* col.insert([{a:1, b:1}
|
||||
* , {a:2, b:2}, {a:3, b:3}
|
||||
* , {a:4, b:4}], {w:1}, function(err, result) {
|
||||
* test.equal(null, err);
|
||||
* // Show that duplicate records got dropped
|
||||
* col.aggregation({}, {cursor: {}}).toArray(function(err, items) {
|
||||
* test.equal(null, err);
|
||||
* test.equal(4, items.length);
|
||||
* client.close();
|
||||
* });
|
||||
* });
|
||||
* });
|
||||
*/
|
||||
|
||||
/**
|
||||
* Namespace provided by the browser.
|
||||
* @external Readable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new Aggregation Cursor instance (INTERNAL TYPE, do not instantiate directly)
|
||||
* @class AggregationCursor
|
||||
* @extends external:Readable
|
||||
* @fires AggregationCursor#data
|
||||
* @fires AggregationCursor#end
|
||||
* @fires AggregationCursor#close
|
||||
* @fires AggregationCursor#readable
|
||||
* @return {AggregationCursor} an AggregationCursor instance.
|
||||
*/
|
||||
var AggregationCursor = function(bson, ns, cmd, options, topology, topologyOptions) {
|
||||
CoreCursor.apply(this, Array.prototype.slice.call(arguments, 0));
|
||||
var state = AggregationCursor.INIT;
|
||||
var streamOptions = {};
|
||||
|
||||
// MaxTimeMS
|
||||
var maxTimeMS = null;
|
||||
|
||||
// Get the promiseLibrary
|
||||
var promiseLibrary = options.promiseLibrary || Promise;
|
||||
|
||||
// Set up
|
||||
Readable.call(this, { objectMode: true });
|
||||
|
||||
// Internal state
|
||||
this.s = {
|
||||
// MaxTimeMS
|
||||
maxTimeMS: maxTimeMS,
|
||||
// State
|
||||
state: state,
|
||||
// Stream options
|
||||
streamOptions: streamOptions,
|
||||
// BSON
|
||||
bson: bson,
|
||||
// Namespace
|
||||
ns: ns,
|
||||
// Command
|
||||
cmd: cmd,
|
||||
// Options
|
||||
options: options,
|
||||
// Topology
|
||||
topology: topology,
|
||||
// Topology Options
|
||||
topologyOptions: topologyOptions,
|
||||
// Promise library
|
||||
promiseLibrary: promiseLibrary,
|
||||
// Optional ClientSession
|
||||
session: options.session
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* AggregationCursor stream data event, fired for each document in the cursor.
|
||||
*
|
||||
* @event AggregationCursor#data
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* AggregationCursor stream end event
|
||||
*
|
||||
* @event AggregationCursor#end
|
||||
* @type {null}
|
||||
*/
|
||||
|
||||
/**
|
||||
* AggregationCursor stream close event
|
||||
*
|
||||
* @event AggregationCursor#close
|
||||
* @type {null}
|
||||
*/
|
||||
|
||||
/**
|
||||
* AggregationCursor stream readable event
|
||||
*
|
||||
* @event AggregationCursor#readable
|
||||
* @type {null}
|
||||
*/
|
||||
|
||||
// Inherit from Readable
|
||||
inherits(AggregationCursor, Readable);
|
||||
|
||||
// Extend the Cursor
|
||||
for (var name in CoreCursor.prototype) {
|
||||
AggregationCursor.prototype[name] = CoreCursor.prototype[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch size for the cursor.
|
||||
* @method
|
||||
* @param {number} value The batchSize for the cursor.
|
||||
* @throws {MongoError}
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.batchSize = function(value) {
|
||||
if (this.s.state === AggregationCursor.CLOSED || this.isDead())
|
||||
throw MongoError.create({ message: 'Cursor is closed', driver: true });
|
||||
if (typeof value !== 'number')
|
||||
throw MongoError.create({ message: 'batchSize requires an integer', drvier: true });
|
||||
if (this.s.cmd.cursor) this.s.cmd.cursor.batchSize = value;
|
||||
this.setCursorBatchSize(value);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a geoNear stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {object} document The geoNear stage document.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.geoNear = function(document) {
|
||||
this.s.cmd.pipeline.push({ $geoNear: document });
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a group stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {object} document The group stage document.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.group = function(document) {
|
||||
this.s.cmd.pipeline.push({ $group: document });
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a limit stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {number} value The state limit value.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.limit = function(value) {
|
||||
this.s.cmd.pipeline.push({ $limit: value });
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a match stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {object} document The match stage document.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.match = function(document) {
|
||||
this.s.cmd.pipeline.push({ $match: document });
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a maxTimeMS stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {number} value The state maxTimeMS value.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.maxTimeMS = function(value) {
|
||||
if (this.s.topology.lastIsMaster().minWireVersion > 2) {
|
||||
this.s.cmd.maxTimeMS = value;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a out stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {number} destination The destination name.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.out = function(destination) {
|
||||
this.s.cmd.pipeline.push({ $out: destination });
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a project stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {object} document The project stage document.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.project = function(document) {
|
||||
this.s.cmd.pipeline.push({ $project: document });
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a lookup stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {object} document The lookup stage document.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.lookup = function(document) {
|
||||
this.s.cmd.pipeline.push({ $lookup: document });
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a redact stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {object} document The redact stage document.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.redact = function(document) {
|
||||
this.s.cmd.pipeline.push({ $redact: document });
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a skip stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {number} value The state skip value.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.skip = function(value) {
|
||||
this.s.cmd.pipeline.push({ $skip: value });
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a sort stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {object} document The sort stage document.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.sort = function(document) {
|
||||
this.s.cmd.pipeline.push({ $sort: document });
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a unwind stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {number} field The unwind field name.
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
AggregationCursor.prototype.unwind = function(field) {
|
||||
this.s.cmd.pipeline.push({ $unwind: field });
|
||||
return this;
|
||||
};
|
||||
|
||||
AggregationCursor.prototype.get = AggregationCursor.prototype.toArray;
|
||||
|
||||
/**
|
||||
* Get the next available document from the cursor, returns null if no more documents are available.
|
||||
* @function AggregationCursor.prototype.next
|
||||
* @param {AggregationCursor~resultCallback} [callback] The result callback.
|
||||
* @throws {MongoError}
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check if there is any document still available in the cursor
|
||||
* @function AggregationCursor.prototype.hasNext
|
||||
* @param {AggregationCursor~resultCallback} [callback] The result callback.
|
||||
* @throws {MongoError}
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
|
||||
/**
|
||||
* The callback format for results
|
||||
* @callback AggregationCursor~toArrayResultCallback
|
||||
* @param {MongoError} error An error instance representing the error during the execution.
|
||||
* @param {object[]} documents All the documents the satisfy the cursor.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns an array of documents. The caller is responsible for making sure that there
|
||||
* is enough memory to store the results. Note that the array only contain partial
|
||||
* results when this cursor had been previouly accessed. In that case,
|
||||
* cursor.rewind() can be used to reset the cursor.
|
||||
* @method AggregationCursor.prototype.toArray
|
||||
* @param {AggregationCursor~toArrayResultCallback} [callback] The result callback.
|
||||
* @throws {MongoError}
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
|
||||
/**
|
||||
* The callback format for results
|
||||
* @callback AggregationCursor~resultCallback
|
||||
* @param {MongoError} error An error instance representing the error during the execution.
|
||||
* @param {(object|null)} result The result object if the command was executed successfully.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Iterates over all the documents for this cursor. As with **{cursor.toArray}**,
|
||||
* not all of the elements will be iterated if this cursor had been previouly accessed.
|
||||
* In that case, **{cursor.rewind}** can be used to reset the cursor. However, unlike
|
||||
* **{cursor.toArray}**, the cursor will only hold a maximum of batch size elements
|
||||
* at any given time if batch size is specified. Otherwise, the caller is responsible
|
||||
* for making sure that the entire result can fit the memory.
|
||||
* @method AggregationCursor.prototype.each
|
||||
* @param {AggregationCursor~resultCallback} callback The result callback.
|
||||
* @throws {MongoError}
|
||||
* @return {null}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Close the cursor, sending a AggregationCursor command and emitting close.
|
||||
* @method AggregationCursor.prototype.close
|
||||
* @param {AggregationCursor~resultCallback} [callback] The result callback.
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Is the cursor closed
|
||||
* @method AggregationCursor.prototype.isClosed
|
||||
* @return {boolean}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Execute the explain for the cursor
|
||||
* @method AggregationCursor.prototype.explain
|
||||
* @param {AggregationCursor~resultCallback} [callback] The result callback.
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Clone the cursor
|
||||
* @function AggregationCursor.prototype.clone
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resets the cursor
|
||||
* @function AggregationCursor.prototype.rewind
|
||||
* @return {AggregationCursor}
|
||||
*/
|
||||
|
||||
/**
|
||||
* The callback format for the forEach iterator method
|
||||
* @callback AggregationCursor~iteratorCallback
|
||||
* @param {Object} doc An emitted document for the iterator
|
||||
*/
|
||||
|
||||
/**
|
||||
* The callback error format for the forEach iterator method
|
||||
* @callback AggregationCursor~endCallback
|
||||
* @param {MongoError} error An error instance representing the error during the execution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Iterates over all the documents for this cursor using the iterator, callback pattern.
|
||||
* @method AggregationCursor.prototype.forEach
|
||||
* @param {AggregationCursor~iteratorCallback} iterator The iteration callback.
|
||||
* @param {AggregationCursor~endCallback} callback The end callback.
|
||||
* @throws {MongoError}
|
||||
* @return {null}
|
||||
*/
|
||||
|
||||
AggregationCursor.INIT = 0;
|
||||
AggregationCursor.OPEN = 1;
|
||||
AggregationCursor.CLOSED = 2;
|
||||
|
||||
module.exports = AggregationCursor;
|
31
ProjectNow/NodeServer/node_modules/mongodb/lib/apm.js
generated
vendored
Normal file
31
ProjectNow/NodeServer/node_modules/mongodb/lib/apm.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
|
||||
class Instrumentation extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
instrument(MongoClient, callback) {
|
||||
// store a reference to the original functions
|
||||
this.$MongoClient = MongoClient;
|
||||
const $prototypeConnect = this.$prototypeConnect = MongoClient.prototype.connect; // eslint-disable-line
|
||||
|
||||
const instrumentation = this;
|
||||
MongoClient.prototype.connect = function(callback) {
|
||||
this.s.options.monitorCommands = true;
|
||||
this.on('commandStarted', event => instrumentation.emit('started', event));
|
||||
this.on('commandSucceeded', event => instrumentation.emit('succeeded', event));
|
||||
this.on('commandFailed', event => instrumentation.emit('failed', event));
|
||||
return $prototypeConnect.call(this, callback);
|
||||
};
|
||||
|
||||
if (typeof callback === 'function') callback(null, this);
|
||||
}
|
||||
|
||||
uninstrument() {
|
||||
this.$MongoClient.prototype.connect = this.$prototypeConnect;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Instrumentation;
|
136
ProjectNow/NodeServer/node_modules/mongodb/lib/authenticate.js
generated
vendored
Normal file
136
ProjectNow/NodeServer/node_modules/mongodb/lib/authenticate.js
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
'use strict';
|
||||
|
||||
var shallowClone = require('./utils').shallowClone,
|
||||
handleCallback = require('./utils').handleCallback,
|
||||
MongoError = require('mongodb-core').MongoError,
|
||||
f = require('util').format;
|
||||
|
||||
var authenticate = function(client, username, password, options, callback) {
|
||||
// Did the user destroy the topology
|
||||
if (client.topology && client.topology.isDestroyed())
|
||||
return callback(new MongoError('topology was destroyed'));
|
||||
|
||||
// the default db to authenticate against is 'self'
|
||||
// if authententicate is called from a retry context, it may be another one, like admin
|
||||
var authdb = options.dbName;
|
||||
authdb = options.authdb ? options.authdb : authdb;
|
||||
authdb = options.authSource ? options.authSource : authdb;
|
||||
|
||||
// Callback
|
||||
var _callback = function(err, result) {
|
||||
if (client.listeners('authenticated').length > 0) {
|
||||
client.emit('authenticated', err, result);
|
||||
}
|
||||
|
||||
// Return to caller
|
||||
handleCallback(callback, err, result);
|
||||
};
|
||||
|
||||
// authMechanism
|
||||
var authMechanism = options.authMechanism || '';
|
||||
authMechanism = authMechanism.toUpperCase();
|
||||
|
||||
// If classic auth delegate to auth command
|
||||
if (authMechanism === 'MONGODB-CR') {
|
||||
client.topology.auth('mongocr', authdb, username, password, function(err) {
|
||||
if (err) return handleCallback(callback, err, false);
|
||||
_callback(null, true);
|
||||
});
|
||||
} else if (authMechanism === 'PLAIN') {
|
||||
client.topology.auth('plain', authdb, username, password, function(err) {
|
||||
if (err) return handleCallback(callback, err, false);
|
||||
_callback(null, true);
|
||||
});
|
||||
} else if (authMechanism === 'MONGODB-X509') {
|
||||
client.topology.auth('x509', authdb, username, password, function(err) {
|
||||
if (err) return handleCallback(callback, err, false);
|
||||
_callback(null, true);
|
||||
});
|
||||
} else if (authMechanism === 'SCRAM-SHA-1') {
|
||||
client.topology.auth('scram-sha-1', authdb, username, password, function(err) {
|
||||
if (err) return handleCallback(callback, err, false);
|
||||
_callback(null, true);
|
||||
});
|
||||
} else if (authMechanism === 'SCRAM-SHA-256') {
|
||||
client.topology.auth('scram-sha-256', authdb, username, password, function(err) {
|
||||
if (err) return handleCallback(callback, err, false);
|
||||
_callback(null, true);
|
||||
});
|
||||
} else if (authMechanism === 'GSSAPI') {
|
||||
if (process.platform === 'win32') {
|
||||
client.topology.auth('sspi', authdb, username, password, options, function(err) {
|
||||
if (err) return handleCallback(callback, err, false);
|
||||
_callback(null, true);
|
||||
});
|
||||
} else {
|
||||
client.topology.auth('gssapi', authdb, username, password, options, function(err) {
|
||||
if (err) return handleCallback(callback, err, false);
|
||||
_callback(null, true);
|
||||
});
|
||||
}
|
||||
} else if (authMechanism === 'DEFAULT') {
|
||||
client.topology.auth('default', authdb, username, password, function(err) {
|
||||
if (err) return handleCallback(callback, err, false);
|
||||
_callback(null, true);
|
||||
});
|
||||
} else {
|
||||
handleCallback(
|
||||
callback,
|
||||
MongoError.create({
|
||||
message: f('authentication mechanism %s not supported', options.authMechanism),
|
||||
driver: true
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function(self, username, password, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
// Shallow copy the options
|
||||
options = shallowClone(options);
|
||||
|
||||
// Set default mechanism
|
||||
if (!options.authMechanism) {
|
||||
options.authMechanism = 'DEFAULT';
|
||||
} else if (
|
||||
options.authMechanism !== 'GSSAPI' &&
|
||||
options.authMechanism !== 'DEFAULT' &&
|
||||
options.authMechanism !== 'MONGODB-CR' &&
|
||||
options.authMechanism !== 'MONGODB-X509' &&
|
||||
options.authMechanism !== 'SCRAM-SHA-1' &&
|
||||
options.authMechanism !== 'SCRAM-SHA-256' &&
|
||||
options.authMechanism !== 'PLAIN'
|
||||
) {
|
||||
return handleCallback(
|
||||
callback,
|
||||
MongoError.create({
|
||||
message:
|
||||
'only DEFAULT, GSSAPI, PLAIN, MONGODB-X509, or SCRAM-SHA-1 is supported by authMechanism',
|
||||
driver: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// If we have a callback fallback
|
||||
if (typeof callback === 'function')
|
||||
return authenticate(self, username, password, options, function(err, r) {
|
||||
// Support failed auth method
|
||||
if (err && err.message && err.message.indexOf('saslStart') !== -1) err.code = 59;
|
||||
// Reject error
|
||||
if (err) return callback(err, r);
|
||||
callback(null, r);
|
||||
});
|
||||
|
||||
// Return a promise
|
||||
return new self.s.promiseLibrary(function(resolve, reject) {
|
||||
authenticate(self, username, password, options, function(err, r) {
|
||||
// Support failed auth method
|
||||
if (err && err.message && err.message.indexOf('saslStart') !== -1) err.code = 59;
|
||||
// Reject error
|
||||
if (err) return reject(err);
|
||||
resolve(r);
|
||||
});
|
||||
});
|
||||
};
|
442
ProjectNow/NodeServer/node_modules/mongodb/lib/bulk/common.js
generated
vendored
Normal file
442
ProjectNow/NodeServer/node_modules/mongodb/lib/bulk/common.js
generated
vendored
Normal file
@@ -0,0 +1,442 @@
|
||||
'use strict';
|
||||
|
||||
var Long = require('mongodb-core').BSON.Long,
|
||||
MongoError = require('mongodb-core').MongoError,
|
||||
util = require('util');
|
||||
|
||||
// Error codes
|
||||
var UNKNOWN_ERROR = 8;
|
||||
var INVALID_BSON_ERROR = 22;
|
||||
var WRITE_CONCERN_ERROR = 64;
|
||||
var MULTIPLE_ERROR = 65;
|
||||
|
||||
// Insert types
|
||||
var INSERT = 1;
|
||||
var UPDATE = 2;
|
||||
var REMOVE = 3;
|
||||
|
||||
/**
|
||||
* Helper function to define properties
|
||||
* @ignore
|
||||
*/
|
||||
var defineReadOnlyProperty = function(self, name, value) {
|
||||
Object.defineProperty(self, name, {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Keeps the state of a unordered batch so we can rewrite the results
|
||||
* correctly after command execution
|
||||
* @ignore
|
||||
*/
|
||||
var Batch = function(batchType, originalZeroIndex) {
|
||||
this.originalZeroIndex = originalZeroIndex;
|
||||
this.currentIndex = 0;
|
||||
this.originalIndexes = [];
|
||||
this.batchType = batchType;
|
||||
this.operations = [];
|
||||
this.size = 0;
|
||||
this.sizeBytes = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wraps a legacy operation so we can correctly rewrite it's error
|
||||
* @ignore
|
||||
*/
|
||||
var LegacyOp = function(batchType, operation, index) {
|
||||
this.batchType = batchType;
|
||||
this.index = index;
|
||||
this.operation = operation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new BulkWriteResult instance (INTERNAL TYPE, do not instantiate directly)
|
||||
*
|
||||
* @class
|
||||
* @property {boolean} ok Did bulk operation correctly execute
|
||||
* @property {number} nInserted number of inserted documents
|
||||
* @property {number} nUpdated number of documents updated logically
|
||||
* @property {number} nUpserted Number of upserted documents
|
||||
* @property {number} nModified Number of documents updated physically on disk
|
||||
* @property {number} nRemoved Number of removed documents
|
||||
* @return {BulkWriteResult} a BulkWriteResult instance
|
||||
*/
|
||||
var BulkWriteResult = function(bulkResult) {
|
||||
defineReadOnlyProperty(this, 'ok', bulkResult.ok);
|
||||
defineReadOnlyProperty(this, 'nInserted', bulkResult.nInserted);
|
||||
defineReadOnlyProperty(this, 'nUpserted', bulkResult.nUpserted);
|
||||
defineReadOnlyProperty(this, 'nMatched', bulkResult.nMatched);
|
||||
defineReadOnlyProperty(this, 'nModified', bulkResult.nModified);
|
||||
defineReadOnlyProperty(this, 'nRemoved', bulkResult.nRemoved);
|
||||
|
||||
/**
|
||||
* Return an array of inserted ids
|
||||
*
|
||||
* @return {object[]}
|
||||
*/
|
||||
this.getInsertedIds = function() {
|
||||
return bulkResult.insertedIds;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of upserted ids
|
||||
*
|
||||
* @return {object[]}
|
||||
*/
|
||||
this.getUpsertedIds = function() {
|
||||
return bulkResult.upserted;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the upserted id at position x
|
||||
*
|
||||
* @param {number} index the number of the upserted id to return, returns undefined if no result for passed in index
|
||||
* @return {object}
|
||||
*/
|
||||
this.getUpsertedIdAt = function(index) {
|
||||
return bulkResult.upserted[index];
|
||||
};
|
||||
|
||||
/**
|
||||
* Return raw internal result
|
||||
*
|
||||
* @return {object}
|
||||
*/
|
||||
this.getRawResponse = function() {
|
||||
return bulkResult;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the bulk operation contains a write error
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
this.hasWriteErrors = function() {
|
||||
return bulkResult.writeErrors.length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the number of write errors off the bulk operation
|
||||
*
|
||||
* @return {number}
|
||||
*/
|
||||
this.getWriteErrorCount = function() {
|
||||
return bulkResult.writeErrors.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a specific write error object
|
||||
*
|
||||
* @param {number} index of the write error to return, returns null if there is no result for passed in index
|
||||
* @return {WriteError}
|
||||
*/
|
||||
this.getWriteErrorAt = function(index) {
|
||||
if (index < bulkResult.writeErrors.length) {
|
||||
return bulkResult.writeErrors[index];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve all write errors
|
||||
*
|
||||
* @return {object[]}
|
||||
*/
|
||||
this.getWriteErrors = function() {
|
||||
return bulkResult.writeErrors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve lastOp if available
|
||||
*
|
||||
* @return {object}
|
||||
*/
|
||||
this.getLastOp = function() {
|
||||
return bulkResult.lastOp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the write concern error if any
|
||||
*
|
||||
* @return {WriteConcernError}
|
||||
*/
|
||||
this.getWriteConcernError = function() {
|
||||
if (bulkResult.writeConcernErrors.length === 0) {
|
||||
return null;
|
||||
} else if (bulkResult.writeConcernErrors.length === 1) {
|
||||
// Return the error
|
||||
return bulkResult.writeConcernErrors[0];
|
||||
} else {
|
||||
// Combine the errors
|
||||
var errmsg = '';
|
||||
for (var i = 0; i < bulkResult.writeConcernErrors.length; i++) {
|
||||
var err = bulkResult.writeConcernErrors[i];
|
||||
errmsg = errmsg + err.errmsg;
|
||||
|
||||
// TODO: Something better
|
||||
if (i === 0) errmsg = errmsg + ' and ';
|
||||
}
|
||||
|
||||
return new WriteConcernError({ errmsg: errmsg, code: WRITE_CONCERN_ERROR });
|
||||
}
|
||||
};
|
||||
|
||||
this.toJSON = function() {
|
||||
return bulkResult;
|
||||
};
|
||||
|
||||
this.toString = function() {
|
||||
return 'BulkWriteResult(' + this.toJSON(bulkResult) + ')';
|
||||
};
|
||||
|
||||
this.isOk = function() {
|
||||
return bulkResult.ok === 1;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new WriteConcernError instance (INTERNAL TYPE, do not instantiate directly)
|
||||
*
|
||||
* @class
|
||||
* @property {number} code Write concern error code.
|
||||
* @property {string} errmsg Write concern error message.
|
||||
* @return {WriteConcernError} a WriteConcernError instance
|
||||
*/
|
||||
var WriteConcernError = function(err) {
|
||||
if (!(this instanceof WriteConcernError)) return new WriteConcernError(err);
|
||||
|
||||
// Define properties
|
||||
defineReadOnlyProperty(this, 'code', err.code);
|
||||
defineReadOnlyProperty(this, 'errmsg', err.errmsg);
|
||||
|
||||
this.toJSON = function() {
|
||||
return { code: err.code, errmsg: err.errmsg };
|
||||
};
|
||||
|
||||
this.toString = function() {
|
||||
return 'WriteConcernError(' + err.errmsg + ')';
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new WriteError instance (INTERNAL TYPE, do not instantiate directly)
|
||||
*
|
||||
* @class
|
||||
* @property {number} code Write concern error code.
|
||||
* @property {number} index Write concern error original bulk operation index.
|
||||
* @property {string} errmsg Write concern error message.
|
||||
* @return {WriteConcernError} a WriteConcernError instance
|
||||
*/
|
||||
var WriteError = function(err) {
|
||||
if (!(this instanceof WriteError)) return new WriteError(err);
|
||||
|
||||
// Define properties
|
||||
defineReadOnlyProperty(this, 'code', err.code);
|
||||
defineReadOnlyProperty(this, 'index', err.index);
|
||||
defineReadOnlyProperty(this, 'errmsg', err.errmsg);
|
||||
|
||||
//
|
||||
// Define access methods
|
||||
this.getOperation = function() {
|
||||
return err.op;
|
||||
};
|
||||
|
||||
this.toJSON = function() {
|
||||
return { code: err.code, index: err.index, errmsg: err.errmsg, op: err.op };
|
||||
};
|
||||
|
||||
this.toString = function() {
|
||||
return 'WriteError(' + JSON.stringify(this.toJSON()) + ')';
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Merges results into shared data structure
|
||||
* @ignore
|
||||
*/
|
||||
var mergeBatchResults = function(ordered, batch, bulkResult, err, result) {
|
||||
// If we have an error set the result to be the err object
|
||||
if (err) {
|
||||
result = err;
|
||||
} else if (result && result.result) {
|
||||
result = result.result;
|
||||
} else if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do we have a top level error stop processing and return
|
||||
if (result.ok === 0 && bulkResult.ok === 1) {
|
||||
bulkResult.ok = 0;
|
||||
|
||||
var writeError = {
|
||||
index: 0,
|
||||
code: result.code || 0,
|
||||
errmsg: result.message,
|
||||
op: batch.operations[0]
|
||||
};
|
||||
|
||||
bulkResult.writeErrors.push(new WriteError(writeError));
|
||||
return;
|
||||
} else if (result.ok === 0 && bulkResult.ok === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Deal with opTime if available
|
||||
if (result.opTime || result.lastOp) {
|
||||
var opTime = result.lastOp || result.opTime;
|
||||
var lastOpTS = null;
|
||||
var lastOpT = null;
|
||||
|
||||
// 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;
|
||||
}
|
||||
} 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
|
||||
var opTimeTS = typeof opTime.ts === 'number' ? Long.fromNumber(opTime.ts) : opTime.ts;
|
||||
var 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)) {
|
||||
bulkResult.lastOp = opTime;
|
||||
} else if (opTimeTS.equals(lastOpTS)) {
|
||||
if (opTimeT.greaterThan(lastOpT)) {
|
||||
bulkResult.lastOp = opTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we have an insert Batch type
|
||||
if (batch.batchType === INSERT && result.n) {
|
||||
bulkResult.nInserted = bulkResult.nInserted + result.n;
|
||||
}
|
||||
|
||||
// If we have an insert Batch type
|
||||
if (batch.batchType === REMOVE && result.n) {
|
||||
bulkResult.nRemoved = bulkResult.nRemoved + result.n;
|
||||
}
|
||||
|
||||
var nUpserted = 0;
|
||||
|
||||
// We have an array of upserted values, we need to rewrite the indexes
|
||||
if (Array.isArray(result.upserted)) {
|
||||
nUpserted = result.upserted.length;
|
||||
|
||||
for (var i = 0; i < result.upserted.length; i++) {
|
||||
bulkResult.upserted.push({
|
||||
index: result.upserted[i].index + batch.originalZeroIndex,
|
||||
_id: result.upserted[i]._id
|
||||
});
|
||||
}
|
||||
} else if (result.upserted) {
|
||||
nUpserted = 1;
|
||||
|
||||
bulkResult.upserted.push({
|
||||
index: batch.originalZeroIndex,
|
||||
_id: result.upserted
|
||||
});
|
||||
}
|
||||
|
||||
// If we have an update Batch type
|
||||
if (batch.batchType === UPDATE && result.n) {
|
||||
var nModified = result.nModified;
|
||||
bulkResult.nUpserted = bulkResult.nUpserted + nUpserted;
|
||||
bulkResult.nMatched = bulkResult.nMatched + (result.n - nUpserted);
|
||||
|
||||
if (typeof nModified === 'number') {
|
||||
bulkResult.nModified = bulkResult.nModified + nModified;
|
||||
} else {
|
||||
bulkResult.nModified = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(result.writeErrors)) {
|
||||
for (i = 0; i < result.writeErrors.length; i++) {
|
||||
writeError = {
|
||||
index: batch.originalZeroIndex + result.writeErrors[i].index,
|
||||
code: result.writeErrors[i].code,
|
||||
errmsg: result.writeErrors[i].errmsg,
|
||||
op: batch.operations[result.writeErrors[i].index]
|
||||
};
|
||||
|
||||
bulkResult.writeErrors.push(new WriteError(writeError));
|
||||
}
|
||||
}
|
||||
|
||||
if (result.writeConcernError) {
|
||||
bulkResult.writeConcernErrors.push(new WriteConcernError(result.writeConcernError));
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Clone the options
|
||||
var cloneOptions = function(options) {
|
||||
var clone = {};
|
||||
var keys = Object.keys(options);
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
clone[keys[i]] = options[keys[i]];
|
||||
}
|
||||
|
||||
return clone;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new BulkWriteError
|
||||
*
|
||||
* @class
|
||||
* @param {Error|string|object} message The error message
|
||||
* @param {BulkWriteResult} result The result of the bulk write operation
|
||||
* @return {BulkWriteError} A BulkWriteError instance
|
||||
* @extends {MongoError}
|
||||
*/
|
||||
const BulkWriteError = function(error, result) {
|
||||
var message = error.err || error.errmsg || error.errMessage || error;
|
||||
MongoError.call(this, message);
|
||||
|
||||
var keys = typeof error === 'object' ? Object.keys(error) : [];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
this[keys[i]] = error[keys[i]];
|
||||
}
|
||||
|
||||
this.name = 'BulkWriteError';
|
||||
this.result = result;
|
||||
};
|
||||
util.inherits(BulkWriteError, MongoError);
|
||||
|
||||
// Exports symbols
|
||||
exports.BulkWriteError = BulkWriteError;
|
||||
exports.BulkWriteResult = BulkWriteResult;
|
||||
exports.WriteError = WriteError;
|
||||
exports.Batch = Batch;
|
||||
exports.LegacyOp = LegacyOp;
|
||||
exports.mergeBatchResults = mergeBatchResults;
|
||||
exports.cloneOptions = cloneOptions;
|
||||
exports.INVALID_BSON_ERROR = INVALID_BSON_ERROR;
|
||||
exports.WRITE_CONCERN_ERROR = WRITE_CONCERN_ERROR;
|
||||
exports.MULTIPLE_ERROR = MULTIPLE_ERROR;
|
||||
exports.UNKNOWN_ERROR = UNKNOWN_ERROR;
|
||||
exports.INSERT = INSERT;
|
||||
exports.UPDATE = UPDATE;
|
||||
exports.REMOVE = REMOVE;
|
610
ProjectNow/NodeServer/node_modules/mongodb/lib/bulk/ordered.js
generated
vendored
Normal file
610
ProjectNow/NodeServer/node_modules/mongodb/lib/bulk/ordered.js
generated
vendored
Normal file
@@ -0,0 +1,610 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('./common');
|
||||
const utils = require('../utils');
|
||||
const toError = require('../utils').toError;
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const shallowClone = utils.shallowClone;
|
||||
const BulkWriteResult = common.BulkWriteResult;
|
||||
const ObjectID = require('mongodb-core').BSON.ObjectID;
|
||||
const BSON = require('mongodb-core').BSON;
|
||||
const Batch = common.Batch;
|
||||
const mergeBatchResults = common.mergeBatchResults;
|
||||
const executeOperation = utils.executeOperation;
|
||||
const BulkWriteError = require('./common').BulkWriteError;
|
||||
const applyWriteConcern = utils.applyWriteConcern;
|
||||
|
||||
var 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
|
||||
]);
|
||||
|
||||
/**
|
||||
* Create a FindOperatorsOrdered instance (INTERNAL TYPE, do not instantiate directly)
|
||||
* @class
|
||||
* @return {FindOperatorsOrdered} a FindOperatorsOrdered instance.
|
||||
*/
|
||||
var FindOperatorsOrdered = function(self) {
|
||||
this.s = self.s;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a single update document to the bulk operation
|
||||
*
|
||||
* @method
|
||||
* @param {object} doc update operations
|
||||
* @throws {MongoError}
|
||||
* @return {OrderedBulkOperation}
|
||||
*/
|
||||
FindOperatorsOrdered.prototype.update = function(updateDocument) {
|
||||
// Perform upsert
|
||||
var upsert = typeof this.s.currentOp.upsert === 'boolean' ? this.s.currentOp.upsert : false;
|
||||
|
||||
// Establish the update command
|
||||
var document = {
|
||||
q: this.s.currentOp.selector,
|
||||
u: updateDocument,
|
||||
multi: true,
|
||||
upsert: upsert
|
||||
};
|
||||
|
||||
// Clear out current Op
|
||||
this.s.currentOp = null;
|
||||
// Add the update document to the list
|
||||
return addToOperationsList(this, common.UPDATE, document);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a single update one document to the bulk operation
|
||||
*
|
||||
* @method
|
||||
* @param {object} doc update operations
|
||||
* @throws {MongoError}
|
||||
* @return {OrderedBulkOperation}
|
||||
*/
|
||||
FindOperatorsOrdered.prototype.updateOne = function(updateDocument) {
|
||||
// Perform upsert
|
||||
var upsert = typeof this.s.currentOp.upsert === 'boolean' ? this.s.currentOp.upsert : false;
|
||||
|
||||
// Establish the update command
|
||||
var document = {
|
||||
q: this.s.currentOp.selector,
|
||||
u: updateDocument,
|
||||
multi: false,
|
||||
upsert: upsert
|
||||
};
|
||||
|
||||
// Clear out current Op
|
||||
this.s.currentOp = null;
|
||||
// Add the update document to the list
|
||||
return addToOperationsList(this, common.UPDATE, document);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a replace one operation to the bulk operation
|
||||
*
|
||||
* @method
|
||||
* @param {object} doc the new document to replace the existing one with
|
||||
* @throws {MongoError}
|
||||
* @return {OrderedBulkOperation}
|
||||
*/
|
||||
FindOperatorsOrdered.prototype.replaceOne = function(updateDocument) {
|
||||
this.updateOne(updateDocument);
|
||||
};
|
||||
|
||||
/**
|
||||
* Upsert modifier for update bulk operation
|
||||
*
|
||||
* @method
|
||||
* @throws {MongoError}
|
||||
* @return {FindOperatorsOrdered}
|
||||
*/
|
||||
FindOperatorsOrdered.prototype.upsert = function() {
|
||||
this.s.currentOp.upsert = true;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a remove one operation to the bulk operation
|
||||
*
|
||||
* @method
|
||||
* @throws {MongoError}
|
||||
* @return {OrderedBulkOperation}
|
||||
*/
|
||||
FindOperatorsOrdered.prototype.deleteOne = function() {
|
||||
// Establish the update command
|
||||
var document = {
|
||||
q: this.s.currentOp.selector,
|
||||
limit: 1
|
||||
};
|
||||
|
||||
// Clear out current Op
|
||||
this.s.currentOp = null;
|
||||
// Add the remove document to the list
|
||||
return addToOperationsList(this, common.REMOVE, document);
|
||||
};
|
||||
|
||||
// Backward compatibility
|
||||
FindOperatorsOrdered.prototype.removeOne = FindOperatorsOrdered.prototype.deleteOne;
|
||||
|
||||
/**
|
||||
* Add a remove operation to the bulk operation
|
||||
*
|
||||
* @method
|
||||
* @throws {MongoError}
|
||||
* @return {OrderedBulkOperation}
|
||||
*/
|
||||
FindOperatorsOrdered.prototype.delete = function() {
|
||||
// Establish the update command
|
||||
var document = {
|
||||
q: this.s.currentOp.selector,
|
||||
limit: 0
|
||||
};
|
||||
|
||||
// Clear out current Op
|
||||
this.s.currentOp = null;
|
||||
// Add the remove document to the list
|
||||
return addToOperationsList(this, common.REMOVE, document);
|
||||
};
|
||||
|
||||
// Backward compatibility
|
||||
FindOperatorsOrdered.prototype.remove = FindOperatorsOrdered.prototype.delete;
|
||||
|
||||
// Add to internal list of documents
|
||||
var addToOperationsList = function(_self, docType, document) {
|
||||
// Get the bsonSize
|
||||
var bsonSize = bson.calculateObjectSize(document, {
|
||||
checkKeys: false
|
||||
});
|
||||
|
||||
// Throw error if the doc is bigger than the max BSON size
|
||||
if (bsonSize >= _self.s.maxBatchSizeBytes) {
|
||||
throw toError('document is larger than the maximum size ' + _self.s.maxBatchSizeBytes);
|
||||
}
|
||||
|
||||
// Create a new batch object if we don't have a current one
|
||||
if (_self.s.currentBatch == null) _self.s.currentBatch = new Batch(docType, _self.s.currentIndex);
|
||||
|
||||
// Check if we need to create a new batch
|
||||
if (
|
||||
_self.s.currentBatchSize + 1 >= _self.s.maxWriteBatchSize ||
|
||||
_self.s.currentBatchSizeBytes + _self.s.currentBatchSizeBytes >= _self.s.maxBatchSizeBytes ||
|
||||
_self.s.currentBatch.batchType !== docType
|
||||
) {
|
||||
// Save the batch to the execution stack
|
||||
_self.s.batches.push(_self.s.currentBatch);
|
||||
|
||||
// Create a new batch
|
||||
_self.s.currentBatch = new Batch(docType, _self.s.currentIndex);
|
||||
|
||||
// Reset the current size trackers
|
||||
_self.s.currentBatchSize = 0;
|
||||
_self.s.currentBatchSizeBytes = 0;
|
||||
} else {
|
||||
// Update current batch size
|
||||
_self.s.currentBatchSize = _self.s.currentBatchSize + 1;
|
||||
_self.s.currentBatchSizeBytes = _self.s.currentBatchSizeBytes + bsonSize;
|
||||
}
|
||||
|
||||
if (docType === common.INSERT) {
|
||||
_self.s.bulkResult.insertedIds.push({ index: _self.s.currentIndex, _id: document._id });
|
||||
}
|
||||
|
||||
// We have an array of documents
|
||||
if (Array.isArray(document)) {
|
||||
throw toError('operation passed in cannot be an Array');
|
||||
} else {
|
||||
_self.s.currentBatch.originalIndexes.push(_self.s.currentIndex);
|
||||
_self.s.currentBatch.operations.push(document);
|
||||
_self.s.currentBatchSizeBytes = _self.s.currentBatchSizeBytes + bsonSize;
|
||||
_self.s.currentIndex = _self.s.currentIndex + 1;
|
||||
}
|
||||
|
||||
// Return self
|
||||
return _self;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new OrderedBulkOperation instance (INTERNAL TYPE, do not instantiate directly)
|
||||
* @class
|
||||
* @property {number} length Get the number of operations in the bulk.
|
||||
* @return {OrderedBulkOperation} a OrderedBulkOperation instance.
|
||||
*/
|
||||
function OrderedBulkOperation(topology, collection, options) {
|
||||
options = options == null ? {} : options;
|
||||
// TODO Bring from driver information in isMaster
|
||||
var executed = false;
|
||||
|
||||
// Current item
|
||||
var currentOp = null;
|
||||
|
||||
// Handle to the bson serializer, used to calculate running sizes
|
||||
var bson = topology.bson;
|
||||
|
||||
// Namespace for the operation
|
||||
var namespace = collection.collectionName;
|
||||
|
||||
// Set max byte size
|
||||
var maxBatchSizeBytes =
|
||||
topology.isMasterDoc && topology.isMasterDoc.maxBsonObjectSize
|
||||
? topology.isMasterDoc.maxBsonObjectSize
|
||||
: 1024 * 1025 * 16;
|
||||
var maxWriteBatchSize =
|
||||
topology.isMasterDoc && topology.isMasterDoc.maxWriteBatchSize
|
||||
? topology.isMasterDoc.maxWriteBatchSize
|
||||
: 1000;
|
||||
|
||||
// Get the write concern
|
||||
var writeConcern = applyWriteConcern(shallowClone(options), { collection: collection }, options);
|
||||
writeConcern = writeConcern.writeConcern;
|
||||
|
||||
// Get the promiseLibrary
|
||||
var promiseLibrary = options.promiseLibrary || Promise;
|
||||
|
||||
// Final results
|
||||
var bulkResult = {
|
||||
ok: 1,
|
||||
writeErrors: [],
|
||||
writeConcernErrors: [],
|
||||
insertedIds: [],
|
||||
nInserted: 0,
|
||||
nUpserted: 0,
|
||||
nMatched: 0,
|
||||
nModified: 0,
|
||||
nRemoved: 0,
|
||||
upserted: []
|
||||
};
|
||||
|
||||
// Internal state
|
||||
this.s = {
|
||||
// Final result
|
||||
bulkResult: bulkResult,
|
||||
// Current batch state
|
||||
currentBatch: null,
|
||||
currentIndex: 0,
|
||||
currentBatchSize: 0,
|
||||
currentBatchSizeBytes: 0,
|
||||
batches: [],
|
||||
// Write concern
|
||||
writeConcern: writeConcern,
|
||||
// Max batch size options
|
||||
maxBatchSizeBytes: maxBatchSizeBytes,
|
||||
maxWriteBatchSize: maxWriteBatchSize,
|
||||
// Namespace
|
||||
namespace: namespace,
|
||||
// BSON
|
||||
bson: bson,
|
||||
// Topology
|
||||
topology: topology,
|
||||
// Options
|
||||
options: options,
|
||||
// Current operation
|
||||
currentOp: currentOp,
|
||||
// Executed
|
||||
executed: executed,
|
||||
// Collection
|
||||
collection: collection,
|
||||
// Promise Library
|
||||
promiseLibrary: promiseLibrary,
|
||||
// Fundamental error
|
||||
err: null,
|
||||
// Bypass validation
|
||||
bypassDocumentValidation:
|
||||
typeof options.bypassDocumentValidation === 'boolean'
|
||||
? options.bypassDocumentValidation
|
||||
: false,
|
||||
// check keys
|
||||
checkKeys: typeof options.checkKeys === 'boolean' ? options.checkKeys : true
|
||||
};
|
||||
}
|
||||
|
||||
OrderedBulkOperation.prototype.raw = function(op) {
|
||||
var key = Object.keys(op)[0];
|
||||
|
||||
// Set up the force server object id
|
||||
var forceServerObjectId =
|
||||
typeof this.s.options.forceServerObjectId === 'boolean'
|
||||
? this.s.options.forceServerObjectId
|
||||
: this.s.collection.s.db.options.forceServerObjectId;
|
||||
|
||||
// Update operations
|
||||
if (
|
||||
(op.updateOne && op.updateOne.q) ||
|
||||
(op.updateMany && op.updateMany.q) ||
|
||||
(op.replaceOne && op.replaceOne.q)
|
||||
) {
|
||||
op[key].multi = op.updateOne || op.replaceOne ? false : true;
|
||||
return addToOperationsList(this, common.UPDATE, op[key]);
|
||||
}
|
||||
|
||||
// Crud spec update format
|
||||
if (op.updateOne || op.updateMany || op.replaceOne) {
|
||||
var multi = op.updateOne || op.replaceOne ? false : true;
|
||||
var operation = { q: op[key].filter, u: op[key].update || op[key].replacement, multi: multi };
|
||||
operation.upsert = op[key].upsert ? true : false;
|
||||
if (op.collation) operation.collation = op.collation;
|
||||
if (op[key].arrayFilters) operation.arrayFilters = op[key].arrayFilters;
|
||||
return addToOperationsList(this, common.UPDATE, operation);
|
||||
}
|
||||
|
||||
// Remove operations
|
||||
if (
|
||||
op.removeOne ||
|
||||
op.removeMany ||
|
||||
(op.deleteOne && op.deleteOne.q) ||
|
||||
(op.deleteMany && op.deleteMany.q)
|
||||
) {
|
||||
op[key].limit = op.removeOne ? 1 : 0;
|
||||
return addToOperationsList(this, common.REMOVE, op[key]);
|
||||
}
|
||||
|
||||
// Crud spec delete operations, less efficient
|
||||
if (op.deleteOne || op.deleteMany) {
|
||||
var limit = op.deleteOne ? 1 : 0;
|
||||
operation = { q: op[key].filter, limit: limit };
|
||||
if (op.collation) operation.collation = op.collation;
|
||||
return addToOperationsList(this, common.REMOVE, operation);
|
||||
}
|
||||
|
||||
// Insert operations
|
||||
if (op.insertOne && op.insertOne.document == null) {
|
||||
if (forceServerObjectId !== true && op.insertOne._id == null) op.insertOne._id = new ObjectID();
|
||||
return addToOperationsList(this, common.INSERT, op.insertOne);
|
||||
} else if (op.insertOne && op.insertOne.document) {
|
||||
if (forceServerObjectId !== true && op.insertOne.document._id == null)
|
||||
op.insertOne.document._id = new ObjectID();
|
||||
return addToOperationsList(this, common.INSERT, op.insertOne.document);
|
||||
}
|
||||
|
||||
if (op.insertMany) {
|
||||
for (var i = 0; i < op.insertMany.length; i++) {
|
||||
if (forceServerObjectId !== true && op.insertMany[i]._id == null)
|
||||
op.insertMany[i]._id = new ObjectID();
|
||||
addToOperationsList(this, common.INSERT, op.insertMany[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// No valid type of operation
|
||||
throw toError(
|
||||
'bulkWrite only supports insertOne, insertMany, updateOne, updateMany, removeOne, removeMany, deleteOne, deleteMany'
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a single insert document to the bulk operation
|
||||
*
|
||||
* @param {object} doc the document to insert
|
||||
* @throws {MongoError}
|
||||
* @return {OrderedBulkOperation}
|
||||
*/
|
||||
OrderedBulkOperation.prototype.insert = function(document) {
|
||||
if (this.s.collection.s.db.options.forceServerObjectId !== true && document._id == null)
|
||||
document._id = new ObjectID();
|
||||
return addToOperationsList(this, common.INSERT, document);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initiate a find operation for an update/updateOne/remove/removeOne/replaceOne
|
||||
*
|
||||
* @method
|
||||
* @param {object} selector The selector for the bulk operation.
|
||||
* @throws {MongoError}
|
||||
* @return {FindOperatorsOrdered}
|
||||
*/
|
||||
OrderedBulkOperation.prototype.find = function(selector) {
|
||||
if (!selector) {
|
||||
throw toError('Bulk find operation must specify a selector');
|
||||
}
|
||||
|
||||
// Save a current selector
|
||||
this.s.currentOp = {
|
||||
selector: selector
|
||||
};
|
||||
|
||||
return new FindOperatorsOrdered(this);
|
||||
};
|
||||
|
||||
Object.defineProperty(OrderedBulkOperation.prototype, 'length', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.currentIndex;
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Execute next write command in a chain
|
||||
var executeCommands = function(self, options, callback) {
|
||||
if (self.s.batches.length === 0) {
|
||||
return handleCallback(callback, null, new BulkWriteResult(self.s.bulkResult));
|
||||
}
|
||||
|
||||
// Ordered execution of the command
|
||||
var batch = self.s.batches.shift();
|
||||
|
||||
var resultHandler = function(err, result) {
|
||||
// Error is a driver related error not a bulk op error, terminate
|
||||
if ((err && err.driver) || (err && err.message)) {
|
||||
return handleCallback(callback, err);
|
||||
}
|
||||
|
||||
// If we have and error
|
||||
if (err) err.ok = 0;
|
||||
// Merge the results together
|
||||
var mergeResult = mergeBatchResults(true, batch, self.s.bulkResult, err, result);
|
||||
const writeResult = new BulkWriteResult(self.s.bulkResult);
|
||||
if (mergeResult != null) {
|
||||
return handleCallback(callback, null, writeResult);
|
||||
}
|
||||
|
||||
// If we are ordered and have errors and they are
|
||||
// not all replication errors terminate the operation
|
||||
if (self.s.bulkResult.writeErrors.length > 0) {
|
||||
if (self.s.bulkResult.writeErrors.length === 1) {
|
||||
return handleCallback(
|
||||
callback,
|
||||
new BulkWriteError(toError(self.s.bulkResult.writeErrors[0]), writeResult),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
return handleCallback(
|
||||
callback,
|
||||
new BulkWriteError(
|
||||
toError({
|
||||
message: 'write operation failed',
|
||||
code: self.s.bulkResult.writeErrors[0].code,
|
||||
writeErrors: self.s.bulkResult.writeErrors
|
||||
}),
|
||||
writeResult
|
||||
),
|
||||
null
|
||||
);
|
||||
} else if (writeResult.getWriteConcernError()) {
|
||||
return handleCallback(
|
||||
callback,
|
||||
new BulkWriteError(toError(writeResult.getWriteConcernError()), writeResult),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
// Execute the next command in line
|
||||
executeCommands(self, options, callback);
|
||||
};
|
||||
|
||||
var finalOptions = Object.assign({ ordered: true }, options);
|
||||
if (self.s.writeConcern != null) {
|
||||
finalOptions.writeConcern = self.s.writeConcern;
|
||||
}
|
||||
|
||||
// Set an operationIf if provided
|
||||
if (self.operationId) {
|
||||
resultHandler.operationId = self.operationId;
|
||||
}
|
||||
|
||||
// Serialize functions
|
||||
if (self.s.options.serializeFunctions) {
|
||||
finalOptions.serializeFunctions = true;
|
||||
}
|
||||
|
||||
// Ignore undefined
|
||||
if (self.s.options.ignoreUndefined) {
|
||||
finalOptions.ignoreUndefined = true;
|
||||
}
|
||||
|
||||
// Is the bypassDocumentValidation options specific
|
||||
if (self.s.bypassDocumentValidation === true) {
|
||||
finalOptions.bypassDocumentValidation = true;
|
||||
}
|
||||
|
||||
// Is the checkKeys option disabled
|
||||
if (self.s.checkKeys === false) {
|
||||
finalOptions.checkKeys = false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (batch.batchType === common.INSERT) {
|
||||
self.s.topology.insert(
|
||||
self.s.collection.namespace,
|
||||
batch.operations,
|
||||
finalOptions,
|
||||
resultHandler
|
||||
);
|
||||
} else if (batch.batchType === common.UPDATE) {
|
||||
self.s.topology.update(
|
||||
self.s.collection.namespace,
|
||||
batch.operations,
|
||||
finalOptions,
|
||||
resultHandler
|
||||
);
|
||||
} else if (batch.batchType === common.REMOVE) {
|
||||
self.s.topology.remove(
|
||||
self.s.collection.namespace,
|
||||
batch.operations,
|
||||
finalOptions,
|
||||
resultHandler
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
// Force top level error
|
||||
err.ok = 0;
|
||||
// Merge top level error and return
|
||||
handleCallback(callback, null, mergeBatchResults(false, batch, self.s.bulkResult, err, null));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The callback format for results
|
||||
* @callback OrderedBulkOperation~resultCallback
|
||||
* @param {MongoError} error An error instance representing the error during the execution.
|
||||
* @param {BulkWriteResult} result The bulk write result.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Execute the ordered bulk operation
|
||||
*
|
||||
* @method
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {(number|string)} [options.w=null] The write concern.
|
||||
* @param {number} [options.wtimeout=null] 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 {OrderedBulkOperation~resultCallback} [callback] The result callback
|
||||
* @throws {MongoError}
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
OrderedBulkOperation.prototype.execute = function(_writeConcern, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
if (this.s.executed) {
|
||||
var executedError = toError('batch cannot be re-executed');
|
||||
return typeof callback === 'function'
|
||||
? callback(executedError, null)
|
||||
: this.s.promiseLibrary.reject(executedError);
|
||||
}
|
||||
|
||||
if (typeof _writeConcern === 'function') {
|
||||
callback = _writeConcern;
|
||||
} else if (_writeConcern && typeof _writeConcern === 'object') {
|
||||
this.s.writeConcern = _writeConcern;
|
||||
}
|
||||
|
||||
// If we have current batch
|
||||
if (this.s.currentBatch) this.s.batches.push(this.s.currentBatch);
|
||||
|
||||
// If we have no operations in the bulk raise an error
|
||||
if (this.s.batches.length === 0) {
|
||||
var emptyBatchError = toError('Invalid Operation, no operations specified');
|
||||
return typeof callback === 'function'
|
||||
? callback(emptyBatchError, null)
|
||||
: this.s.promiseLibrary.reject(emptyBatchError);
|
||||
}
|
||||
|
||||
return executeOperation(this.s.topology, executeCommands, [this, options, callback]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an unordered batch object
|
||||
* @ignore
|
||||
*/
|
||||
var initializeOrderedBulkOp = function(topology, collection, options) {
|
||||
return new OrderedBulkOperation(topology, collection, options);
|
||||
};
|
||||
|
||||
initializeOrderedBulkOp.OrderedBulkOperation = OrderedBulkOperation;
|
||||
module.exports = initializeOrderedBulkOp;
|
||||
module.exports.Bulk = OrderedBulkOperation;
|
624
ProjectNow/NodeServer/node_modules/mongodb/lib/bulk/unordered.js
generated
vendored
Normal file
624
ProjectNow/NodeServer/node_modules/mongodb/lib/bulk/unordered.js
generated
vendored
Normal file
@@ -0,0 +1,624 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('./common');
|
||||
const utils = require('../utils');
|
||||
const toError = require('../utils').toError;
|
||||
const handleCallback = require('../utils').handleCallback;
|
||||
const shallowClone = utils.shallowClone;
|
||||
const BulkWriteResult = common.BulkWriteResult;
|
||||
const ObjectID = require('mongodb-core').BSON.ObjectID;
|
||||
const BSON = require('mongodb-core').BSON;
|
||||
const Batch = common.Batch;
|
||||
const mergeBatchResults = common.mergeBatchResults;
|
||||
const executeOperation = utils.executeOperation;
|
||||
const BulkWriteError = require('./common').BulkWriteError;
|
||||
const applyWriteConcern = utils.applyWriteConcern;
|
||||
|
||||
var 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
|
||||
]);
|
||||
|
||||
/**
|
||||
* Create a FindOperatorsUnordered instance (INTERNAL TYPE, do not instantiate directly)
|
||||
* @class
|
||||
* @property {number} length Get the number of operations in the bulk.
|
||||
* @return {FindOperatorsUnordered} a FindOperatorsUnordered instance.
|
||||
*/
|
||||
var FindOperatorsUnordered = function(self) {
|
||||
this.s = self.s;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a single update document to the bulk operation
|
||||
*
|
||||
* @method
|
||||
* @param {object} updateDocument update operations
|
||||
* @throws {MongoError}
|
||||
* @return {FindOperatorsUnordered}
|
||||
*/
|
||||
FindOperatorsUnordered.prototype.update = function(updateDocument) {
|
||||
// Perform upsert
|
||||
var upsert = typeof this.s.currentOp.upsert === 'boolean' ? this.s.currentOp.upsert : false;
|
||||
|
||||
// Establish the update command
|
||||
var document = {
|
||||
q: this.s.currentOp.selector,
|
||||
u: updateDocument,
|
||||
multi: true,
|
||||
upsert: upsert
|
||||
};
|
||||
|
||||
// Clear out current Op
|
||||
this.s.currentOp = null;
|
||||
// Add the update document to the list
|
||||
return addToOperationsList(this, common.UPDATE, document);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a single update one document to the bulk operation
|
||||
*
|
||||
* @method
|
||||
* @param {object} updateDocument update operations
|
||||
* @throws {MongoError}
|
||||
* @return {FindOperatorsUnordered}
|
||||
*/
|
||||
FindOperatorsUnordered.prototype.updateOne = function(updateDocument) {
|
||||
// Perform upsert
|
||||
var upsert = typeof this.s.currentOp.upsert === 'boolean' ? this.s.currentOp.upsert : false;
|
||||
|
||||
// Establish the update command
|
||||
var document = {
|
||||
q: this.s.currentOp.selector,
|
||||
u: updateDocument,
|
||||
multi: false,
|
||||
upsert: upsert
|
||||
};
|
||||
|
||||
// Clear out current Op
|
||||
this.s.currentOp = null;
|
||||
// Add the update document to the list
|
||||
return addToOperationsList(this, common.UPDATE, document);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a replace one operation to the bulk operation
|
||||
*
|
||||
* @method
|
||||
* @param {object} updateDocument the new document to replace the existing one with
|
||||
* @throws {MongoError}
|
||||
* @return {FindOperatorsUnordered}
|
||||
*/
|
||||
FindOperatorsUnordered.prototype.replaceOne = function(updateDocument) {
|
||||
this.updateOne(updateDocument);
|
||||
};
|
||||
|
||||
/**
|
||||
* Upsert modifier for update bulk operation
|
||||
*
|
||||
* @method
|
||||
* @throws {MongoError}
|
||||
* @return {FindOperatorsUnordered}
|
||||
*/
|
||||
FindOperatorsUnordered.prototype.upsert = function() {
|
||||
this.s.currentOp.upsert = true;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a remove one operation to the bulk operation
|
||||
*
|
||||
* @method
|
||||
* @throws {MongoError}
|
||||
* @return {FindOperatorsUnordered}
|
||||
*/
|
||||
FindOperatorsUnordered.prototype.removeOne = function() {
|
||||
// Establish the update command
|
||||
var document = {
|
||||
q: this.s.currentOp.selector,
|
||||
limit: 1
|
||||
};
|
||||
|
||||
// Clear out current Op
|
||||
this.s.currentOp = null;
|
||||
// Add the remove document to the list
|
||||
return addToOperationsList(this, common.REMOVE, document);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a remove operation to the bulk operation
|
||||
*
|
||||
* @method
|
||||
* @throws {MongoError}
|
||||
* @return {FindOperatorsUnordered}
|
||||
*/
|
||||
FindOperatorsUnordered.prototype.remove = function() {
|
||||
// Establish the update command
|
||||
var document = {
|
||||
q: this.s.currentOp.selector,
|
||||
limit: 0
|
||||
};
|
||||
|
||||
// Clear out current Op
|
||||
this.s.currentOp = null;
|
||||
// Add the remove document to the list
|
||||
return addToOperationsList(this, common.REMOVE, document);
|
||||
};
|
||||
|
||||
//
|
||||
// Add to the operations list
|
||||
//
|
||||
var addToOperationsList = function(_self, docType, document) {
|
||||
// Get the bsonSize
|
||||
var bsonSize = bson.calculateObjectSize(document, {
|
||||
checkKeys: false
|
||||
});
|
||||
// Throw error if the doc is bigger than the max BSON size
|
||||
if (bsonSize >= _self.s.maxBatchSizeBytes)
|
||||
throw toError('document is larger than the maximum size ' + _self.s.maxBatchSizeBytes);
|
||||
// Holds the current batch
|
||||
_self.s.currentBatch = null;
|
||||
// Get the right type of batch
|
||||
if (docType === common.INSERT) {
|
||||
_self.s.currentBatch = _self.s.currentInsertBatch;
|
||||
} else if (docType === common.UPDATE) {
|
||||
_self.s.currentBatch = _self.s.currentUpdateBatch;
|
||||
} else if (docType === common.REMOVE) {
|
||||
_self.s.currentBatch = _self.s.currentRemoveBatch;
|
||||
}
|
||||
|
||||
// Create a new batch object if we don't have a current one
|
||||
if (_self.s.currentBatch == null) _self.s.currentBatch = new Batch(docType, _self.s.currentIndex);
|
||||
|
||||
// Check if we need to create a new batch
|
||||
if (
|
||||
_self.s.currentBatch.size + 1 >= _self.s.maxWriteBatchSize ||
|
||||
_self.s.currentBatch.sizeBytes + bsonSize >= _self.s.maxBatchSizeBytes ||
|
||||
_self.s.currentBatch.batchType !== docType
|
||||
) {
|
||||
// Save the batch to the execution stack
|
||||
_self.s.batches.push(_self.s.currentBatch);
|
||||
|
||||
// Create a new batch
|
||||
_self.s.currentBatch = new Batch(docType, _self.s.currentIndex);
|
||||
}
|
||||
|
||||
// We have an array of documents
|
||||
if (Array.isArray(document)) {
|
||||
throw toError('operation passed in cannot be an Array');
|
||||
} else {
|
||||
_self.s.currentBatch.operations.push(document);
|
||||
_self.s.currentBatch.originalIndexes.push(_self.s.currentIndex);
|
||||
_self.s.currentIndex = _self.s.currentIndex + 1;
|
||||
}
|
||||
|
||||
// Save back the current Batch to the right type
|
||||
if (docType === common.INSERT) {
|
||||
_self.s.currentInsertBatch = _self.s.currentBatch;
|
||||
_self.s.bulkResult.insertedIds.push({
|
||||
index: _self.s.bulkResult.insertedIds.length,
|
||||
_id: document._id
|
||||
});
|
||||
} else if (docType === common.UPDATE) {
|
||||
_self.s.currentUpdateBatch = _self.s.currentBatch;
|
||||
} else if (docType === common.REMOVE) {
|
||||
_self.s.currentRemoveBatch = _self.s.currentBatch;
|
||||
}
|
||||
|
||||
// Update current batch size
|
||||
_self.s.currentBatch.size = _self.s.currentBatch.size + 1;
|
||||
_self.s.currentBatch.sizeBytes = _self.s.currentBatch.sizeBytes + bsonSize;
|
||||
|
||||
// Return self
|
||||
return _self;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new UnorderedBulkOperation instance (INTERNAL TYPE, do not instantiate directly)
|
||||
* @class
|
||||
* @property {number} length Get the number of operations in the bulk.
|
||||
* @return {UnorderedBulkOperation} a UnorderedBulkOperation instance.
|
||||
*/
|
||||
var UnorderedBulkOperation = function(topology, collection, options) {
|
||||
options = options == null ? {} : options;
|
||||
|
||||
// Get the namesspace for the write operations
|
||||
var namespace = collection.collectionName;
|
||||
// Used to mark operation as executed
|
||||
var executed = false;
|
||||
|
||||
// Current item
|
||||
// var currentBatch = null;
|
||||
var currentOp = null;
|
||||
|
||||
// Handle to the bson serializer, used to calculate running sizes
|
||||
var bson = topology.bson;
|
||||
|
||||
// Set max byte size
|
||||
var maxBatchSizeBytes =
|
||||
topology.isMasterDoc && topology.isMasterDoc.maxBsonObjectSize
|
||||
? topology.isMasterDoc.maxBsonObjectSize
|
||||
: 1024 * 1025 * 16;
|
||||
var maxWriteBatchSize =
|
||||
topology.isMasterDoc && topology.isMasterDoc.maxWriteBatchSize
|
||||
? topology.isMasterDoc.maxWriteBatchSize
|
||||
: 1000;
|
||||
|
||||
// Get the write concern
|
||||
var writeConcern = applyWriteConcern(shallowClone(options), { collection: collection }, options);
|
||||
writeConcern = writeConcern.writeConcern;
|
||||
|
||||
// Get the promiseLibrary
|
||||
var promiseLibrary = options.promiseLibrary || Promise;
|
||||
|
||||
// Final results
|
||||
var bulkResult = {
|
||||
ok: 1,
|
||||
writeErrors: [],
|
||||
writeConcernErrors: [],
|
||||
insertedIds: [],
|
||||
nInserted: 0,
|
||||
nUpserted: 0,
|
||||
nMatched: 0,
|
||||
nModified: 0,
|
||||
nRemoved: 0,
|
||||
upserted: []
|
||||
};
|
||||
|
||||
// Internal state
|
||||
this.s = {
|
||||
// Final result
|
||||
bulkResult: bulkResult,
|
||||
// Current batch state
|
||||
currentInsertBatch: null,
|
||||
currentUpdateBatch: null,
|
||||
currentRemoveBatch: null,
|
||||
currentBatch: null,
|
||||
currentIndex: 0,
|
||||
batches: [],
|
||||
// Write concern
|
||||
writeConcern: writeConcern,
|
||||
// Max batch size options
|
||||
maxBatchSizeBytes: maxBatchSizeBytes,
|
||||
maxWriteBatchSize: maxWriteBatchSize,
|
||||
// Namespace
|
||||
namespace: namespace,
|
||||
// BSON
|
||||
bson: bson,
|
||||
// Topology
|
||||
topology: topology,
|
||||
// Options
|
||||
options: options,
|
||||
// Current operation
|
||||
currentOp: currentOp,
|
||||
// Executed
|
||||
executed: executed,
|
||||
// Collection
|
||||
collection: collection,
|
||||
// Promise Library
|
||||
promiseLibrary: promiseLibrary,
|
||||
// Bypass validation
|
||||
bypassDocumentValidation:
|
||||
typeof options.bypassDocumentValidation === 'boolean'
|
||||
? options.bypassDocumentValidation
|
||||
: false,
|
||||
// check keys
|
||||
checkKeys: typeof options.checkKeys === 'boolean' ? options.checkKeys : true
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a single insert document to the bulk operation
|
||||
*
|
||||
* @param {object} document the document to insert
|
||||
* @throws {MongoError}
|
||||
* @return {UnorderedBulkOperation}
|
||||
*/
|
||||
UnorderedBulkOperation.prototype.insert = function(document) {
|
||||
if (this.s.collection.s.db.options.forceServerObjectId !== true && document._id == null)
|
||||
document._id = new ObjectID();
|
||||
return addToOperationsList(this, common.INSERT, document);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initiate a find operation for an update/updateOne/remove/removeOne/replaceOne
|
||||
*
|
||||
* @method
|
||||
* @param {object} selector The selector for the bulk operation.
|
||||
* @throws {MongoError}
|
||||
* @return {FindOperatorsUnordered}
|
||||
*/
|
||||
UnorderedBulkOperation.prototype.find = function(selector) {
|
||||
if (!selector) {
|
||||
throw toError('Bulk find operation must specify a selector');
|
||||
}
|
||||
|
||||
// Save a current selector
|
||||
this.s.currentOp = {
|
||||
selector: selector
|
||||
};
|
||||
|
||||
return new FindOperatorsUnordered(this);
|
||||
};
|
||||
|
||||
Object.defineProperty(UnorderedBulkOperation.prototype, 'length', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.currentIndex;
|
||||
}
|
||||
});
|
||||
|
||||
UnorderedBulkOperation.prototype.raw = function(op) {
|
||||
var key = Object.keys(op)[0];
|
||||
|
||||
// Set up the force server object id
|
||||
var forceServerObjectId =
|
||||
typeof this.s.options.forceServerObjectId === 'boolean'
|
||||
? this.s.options.forceServerObjectId
|
||||
: this.s.collection.s.db.options.forceServerObjectId;
|
||||
|
||||
// Update operations
|
||||
if (
|
||||
(op.updateOne && op.updateOne.q) ||
|
||||
(op.updateMany && op.updateMany.q) ||
|
||||
(op.replaceOne && op.replaceOne.q)
|
||||
) {
|
||||
op[key].multi = op.updateOne || op.replaceOne ? false : true;
|
||||
return addToOperationsList(this, common.UPDATE, op[key]);
|
||||
}
|
||||
|
||||
// Crud spec update format
|
||||
if (op.updateOne || op.updateMany || op.replaceOne) {
|
||||
var multi = op.updateOne || op.replaceOne ? false : true;
|
||||
var operation = { q: op[key].filter, u: op[key].update || op[key].replacement, multi: multi };
|
||||
if (op[key].upsert) operation.upsert = true;
|
||||
if (op[key].arrayFilters) operation.arrayFilters = op[key].arrayFilters;
|
||||
return addToOperationsList(this, common.UPDATE, operation);
|
||||
}
|
||||
|
||||
// Remove operations
|
||||
if (
|
||||
op.removeOne ||
|
||||
op.removeMany ||
|
||||
(op.deleteOne && op.deleteOne.q) ||
|
||||
(op.deleteMany && op.deleteMany.q)
|
||||
) {
|
||||
op[key].limit = op.removeOne ? 1 : 0;
|
||||
return addToOperationsList(this, common.REMOVE, op[key]);
|
||||
}
|
||||
|
||||
// Crud spec delete operations, less efficient
|
||||
if (op.deleteOne || op.deleteMany) {
|
||||
var limit = op.deleteOne ? 1 : 0;
|
||||
operation = { q: op[key].filter, limit: limit };
|
||||
return addToOperationsList(this, common.REMOVE, operation);
|
||||
}
|
||||
|
||||
// Insert operations
|
||||
if (op.insertOne && op.insertOne.document == null) {
|
||||
if (forceServerObjectId !== true && op.insertOne._id == null) op.insertOne._id = new ObjectID();
|
||||
return addToOperationsList(this, common.INSERT, op.insertOne);
|
||||
} else if (op.insertOne && op.insertOne.document) {
|
||||
if (forceServerObjectId !== true && op.insertOne.document._id == null)
|
||||
op.insertOne.document._id = new ObjectID();
|
||||
return addToOperationsList(this, common.INSERT, op.insertOne.document);
|
||||
}
|
||||
|
||||
if (op.insertMany) {
|
||||
for (var i = 0; i < op.insertMany.length; i++) {
|
||||
if (forceServerObjectId !== true && op.insertMany[i]._id == null)
|
||||
op.insertMany[i]._id = new ObjectID();
|
||||
addToOperationsList(this, common.INSERT, op.insertMany[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// No valid type of operation
|
||||
throw toError(
|
||||
'bulkWrite only supports insertOne, insertMany, updateOne, updateMany, removeOne, removeMany, deleteOne, deleteMany'
|
||||
);
|
||||
};
|
||||
|
||||
//
|
||||
// Execute the command
|
||||
var executeBatch = function(self, batch, options, callback) {
|
||||
var finalOptions = Object.assign({ ordered: false }, options);
|
||||
if (self.s.writeConcern != null) {
|
||||
finalOptions.writeConcern = self.s.writeConcern;
|
||||
}
|
||||
|
||||
var resultHandler = function(err, result) {
|
||||
// Error is a driver related error not a bulk op error, terminate
|
||||
if ((err && err.driver) || (err && err.message)) {
|
||||
return handleCallback(callback, err);
|
||||
}
|
||||
|
||||
// If we have and error
|
||||
if (err) err.ok = 0;
|
||||
handleCallback(callback, null, mergeBatchResults(false, batch, self.s.bulkResult, err, result));
|
||||
};
|
||||
|
||||
// Set an operationIf if provided
|
||||
if (self.operationId) {
|
||||
resultHandler.operationId = self.operationId;
|
||||
}
|
||||
|
||||
// Serialize functions
|
||||
if (self.s.options.serializeFunctions) {
|
||||
finalOptions.serializeFunctions = true;
|
||||
}
|
||||
|
||||
// Ignore undefined
|
||||
if (self.s.options.ignoreUndefined) {
|
||||
finalOptions.ignoreUndefined = true;
|
||||
}
|
||||
|
||||
// Is the bypassDocumentValidation options specific
|
||||
if (self.s.bypassDocumentValidation === true) {
|
||||
finalOptions.bypassDocumentValidation = true;
|
||||
}
|
||||
|
||||
// Is the checkKeys option disabled
|
||||
if (self.s.checkKeys === false) {
|
||||
finalOptions.checkKeys = false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (batch.batchType === common.INSERT) {
|
||||
self.s.topology.insert(
|
||||
self.s.collection.namespace,
|
||||
batch.operations,
|
||||
finalOptions,
|
||||
resultHandler
|
||||
);
|
||||
} else if (batch.batchType === common.UPDATE) {
|
||||
self.s.topology.update(
|
||||
self.s.collection.namespace,
|
||||
batch.operations,
|
||||
finalOptions,
|
||||
resultHandler
|
||||
);
|
||||
} else if (batch.batchType === common.REMOVE) {
|
||||
self.s.topology.remove(
|
||||
self.s.collection.namespace,
|
||||
batch.operations,
|
||||
finalOptions,
|
||||
resultHandler
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
// Force top level error
|
||||
err.ok = 0;
|
||||
// Merge top level error and return
|
||||
handleCallback(callback, null, mergeBatchResults(false, batch, self.s.bulkResult, err, null));
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Execute all the commands
|
||||
var executeBatches = function(self, options, callback) {
|
||||
var numberOfCommandsToExecute = self.s.batches.length;
|
||||
// Execute over all the batches
|
||||
for (var i = 0; i < self.s.batches.length; i++) {
|
||||
executeBatch(self, self.s.batches[i], options, function(err) {
|
||||
// Count down the number of commands left to execute
|
||||
numberOfCommandsToExecute = numberOfCommandsToExecute - 1;
|
||||
|
||||
// Execute
|
||||
if (numberOfCommandsToExecute === 0) {
|
||||
// Driver level error
|
||||
if (err) return handleCallback(callback, err);
|
||||
|
||||
const writeResult = new BulkWriteResult(self.s.bulkResult);
|
||||
if (self.s.bulkResult.writeErrors.length > 0) {
|
||||
if (self.s.bulkResult.writeErrors.length === 1) {
|
||||
return handleCallback(
|
||||
callback,
|
||||
new BulkWriteError(toError(self.s.bulkResult.writeErrors[0]), writeResult),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
return handleCallback(
|
||||
callback,
|
||||
new BulkWriteError(
|
||||
toError({
|
||||
message: 'write operation failed',
|
||||
code: self.s.bulkResult.writeErrors[0].code,
|
||||
writeErrors: self.s.bulkResult.writeErrors
|
||||
}),
|
||||
writeResult
|
||||
),
|
||||
null
|
||||
);
|
||||
} else if (writeResult.getWriteConcernError()) {
|
||||
return handleCallback(
|
||||
callback,
|
||||
new BulkWriteError(toError(writeResult.getWriteConcernError()), writeResult),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
return handleCallback(callback, null, writeResult);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The callback format for results
|
||||
* @callback UnorderedBulkOperation~resultCallback
|
||||
* @param {MongoError} error An error instance representing the error during the execution.
|
||||
* @param {BulkWriteResult} result The bulk write result.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Execute the ordered bulk operation
|
||||
*
|
||||
* @method
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {(number|string)} [options.w=null] The write concern.
|
||||
* @param {number} [options.wtimeout=null] 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 {UnorderedBulkOperation~resultCallback} [callback] The result callback
|
||||
* @throws {MongoError}
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
UnorderedBulkOperation.prototype.execute = function(_writeConcern, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
if (this.s.executed) {
|
||||
var executedError = toError('batch cannot be re-executed');
|
||||
return typeof callback === 'function'
|
||||
? callback(executedError, null)
|
||||
: this.s.promiseLibrary.reject(executedError);
|
||||
}
|
||||
|
||||
if (typeof _writeConcern === 'function') {
|
||||
callback = _writeConcern;
|
||||
} else if (_writeConcern && typeof _writeConcern === 'object') {
|
||||
this.s.writeConcern = _writeConcern;
|
||||
}
|
||||
|
||||
// If we have current batch
|
||||
if (this.s.currentInsertBatch) this.s.batches.push(this.s.currentInsertBatch);
|
||||
if (this.s.currentUpdateBatch) this.s.batches.push(this.s.currentUpdateBatch);
|
||||
if (this.s.currentRemoveBatch) this.s.batches.push(this.s.currentRemoveBatch);
|
||||
|
||||
// If we have no operations in the bulk raise an error
|
||||
if (this.s.batches.length === 0) {
|
||||
var emptyBatchError = toError('Invalid Operation, no operations specified');
|
||||
return typeof callback === 'function'
|
||||
? callback(emptyBatchError, null)
|
||||
: this.s.promiseLibrary.reject(emptyBatchError);
|
||||
}
|
||||
|
||||
return executeOperation(this.s.topology, executeBatches, [this, options, callback]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an unordered batch object
|
||||
* @ignore
|
||||
*/
|
||||
var initializeUnorderedBulkOp = function(topology, collection, options) {
|
||||
return new UnorderedBulkOperation(topology, collection, options);
|
||||
};
|
||||
|
||||
initializeUnorderedBulkOp.UnorderedBulkOperation = UnorderedBulkOperation;
|
||||
module.exports = initializeUnorderedBulkOp;
|
||||
module.exports.Bulk = UnorderedBulkOperation;
|
359
ProjectNow/NodeServer/node_modules/mongodb/lib/change_stream.js
generated
vendored
Normal file
359
ProjectNow/NodeServer/node_modules/mongodb/lib/change_stream.js
generated
vendored
Normal file
@@ -0,0 +1,359 @@
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('events'),
|
||||
inherits = require('util').inherits,
|
||||
MongoNetworkError = require('mongodb-core').MongoNetworkError;
|
||||
|
||||
var cursorOptionNames = ['maxAwaitTimeMS', 'collation', 'readPreference'];
|
||||
|
||||
/**
|
||||
* Creates a new Change Stream instance. Normally created using {@link Collection#watch|Collection.watch()}.
|
||||
* @class ChangeStream
|
||||
* @since 3.0.0
|
||||
* @param {(Db|Collection)} changeDomain The collection against which to create the change stream
|
||||
* @param {Array} pipeline An array of {@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/|aggregation pipeline stages} through which to pass change stream documents
|
||||
* @param {object} [options=null] Optional settings
|
||||
* @param {string} [options.fullDocument='default'] Allowed values: ‘default’, ‘updateLookup’. When set to ‘updateLookup’, the change stream will include both a delta describing the changes to the document, as well as a copy of the entire document that was changed from some time after the change occurred.
|
||||
* @param {number} [options.maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a change stream query
|
||||
* @param {object} [options.resumeAfter=null] Specifies the logical starting point for the new change stream. This should be the _id field from a previously returned change stream document.
|
||||
* @param {number} [options.batchSize=null] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
||||
* @param {object} [options.collation=null] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
||||
* @param {ReadPreference} [options.readPreference=null] The read preference. Defaults to the read preference of the database or collection. See {@link https://docs.mongodb.com/manual/reference/read-preference|read preference documentation}.
|
||||
* @fires ChangeStream#close
|
||||
* @fires ChangeStream#change
|
||||
* @fires ChangeStream#end
|
||||
* @fires ChangeStream#error
|
||||
* @return {ChangeStream} a ChangeStream instance.
|
||||
*/
|
||||
var ChangeStream = function(collection, pipeline, options) {
|
||||
var Collection = require('./collection');
|
||||
|
||||
// Ensure the provided collection is actually a collection
|
||||
if (!(collection instanceof Collection)) {
|
||||
throw new Error(
|
||||
'collection provided to ChangeStream constructor is not an instance of Collection'
|
||||
);
|
||||
}
|
||||
|
||||
var self = this;
|
||||
self.pipeline = pipeline || [];
|
||||
self.options = options || {};
|
||||
self.promiseLibrary = collection.s.promiseLibrary;
|
||||
|
||||
// Extract namespace and serverConfig from the collection
|
||||
self.namespace = {
|
||||
collection: collection.collectionName,
|
||||
database: collection.s.db.databaseName
|
||||
};
|
||||
|
||||
self.serverConfig = collection.s.db.serverConfig;
|
||||
|
||||
// Determine correct read preference
|
||||
self.options.readPreference = self.options.readPreference || collection.s.readPreference;
|
||||
|
||||
// Create contained Change Stream cursor
|
||||
self.cursor = createChangeStreamCursor(self);
|
||||
|
||||
// Listen for any `change` listeners being added to ChangeStream
|
||||
self.on('newListener', function(eventName) {
|
||||
if (eventName === 'change' && self.cursor && self.cursor.listenerCount('change') === 0) {
|
||||
self.cursor.on('data', function(change) {
|
||||
processNewChange(self, null, change);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Listen for all `change` listeners being removed from ChangeStream
|
||||
self.on('removeListener', function(eventName) {
|
||||
if (eventName === 'change' && self.listenerCount('change') === 0 && self.cursor) {
|
||||
self.cursor.removeAllListeners('data');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
inherits(ChangeStream, EventEmitter);
|
||||
|
||||
// Create a new change stream cursor based on self's configuration
|
||||
var createChangeStreamCursor = function(self) {
|
||||
if (self.resumeToken) {
|
||||
self.options.resumeAfter = self.resumeToken;
|
||||
}
|
||||
|
||||
var changeStreamCursor = buildChangeStreamAggregationCommand(
|
||||
self.serverConfig,
|
||||
self.namespace,
|
||||
self.pipeline,
|
||||
self.resumeToken,
|
||||
self.options
|
||||
);
|
||||
|
||||
/**
|
||||
* Fired for each new matching change in the specified namespace. Attaching a `change` event listener to a Change Stream will switch the stream into flowing mode. Data will then be passed as soon as it is available.
|
||||
*
|
||||
* @event ChangeStream#change
|
||||
* @type {object}
|
||||
*/
|
||||
if (self.listenerCount('change') > 0) {
|
||||
changeStreamCursor.on('data', function(change) {
|
||||
processNewChange(self, null, change);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Change stream close event
|
||||
*
|
||||
* @event ChangeStream#close
|
||||
* @type {null}
|
||||
*/
|
||||
changeStreamCursor.on('close', function() {
|
||||
self.emit('close');
|
||||
});
|
||||
|
||||
/**
|
||||
* Change stream end event
|
||||
*
|
||||
* @event ChangeStream#end
|
||||
* @type {null}
|
||||
*/
|
||||
changeStreamCursor.on('end', function() {
|
||||
self.emit('end');
|
||||
});
|
||||
|
||||
/**
|
||||
* Fired when the stream encounters an error.
|
||||
*
|
||||
* @event ChangeStream#error
|
||||
* @type {Error}
|
||||
*/
|
||||
changeStreamCursor.on('error', function(error) {
|
||||
self.emit('error', error);
|
||||
});
|
||||
|
||||
return changeStreamCursor;
|
||||
};
|
||||
|
||||
var buildChangeStreamAggregationCommand = function(
|
||||
serverConfig,
|
||||
namespace,
|
||||
pipeline,
|
||||
resumeToken,
|
||||
options
|
||||
) {
|
||||
var changeStreamStageOptions = {};
|
||||
if (options.fullDocument) {
|
||||
changeStreamStageOptions.fullDocument = options.fullDocument;
|
||||
}
|
||||
|
||||
if (resumeToken || options.resumeAfter) {
|
||||
changeStreamStageOptions.resumeAfter = resumeToken || options.resumeAfter;
|
||||
}
|
||||
|
||||
// Map cursor options
|
||||
var cursorOptions = {};
|
||||
cursorOptionNames.forEach(function(optionName) {
|
||||
if (options[optionName]) {
|
||||
cursorOptions[optionName] = options[optionName];
|
||||
}
|
||||
});
|
||||
|
||||
var changeStreamPipeline = [{ $changeStream: changeStreamStageOptions }];
|
||||
|
||||
changeStreamPipeline = changeStreamPipeline.concat(pipeline);
|
||||
|
||||
var command = {
|
||||
aggregate: namespace.collection,
|
||||
pipeline: changeStreamPipeline,
|
||||
readConcern: { level: 'majority' },
|
||||
cursor: {
|
||||
batchSize: options.batchSize || 1
|
||||
}
|
||||
};
|
||||
|
||||
// Create and return the cursor
|
||||
return serverConfig.cursor(
|
||||
namespace.database + '.' + namespace.collection,
|
||||
command,
|
||||
cursorOptions
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if there is any document still available in the Change Stream
|
||||
* @function ChangeStream.prototype.hasNext
|
||||
* @param {ChangeStream~resultCallback} [callback] The result callback.
|
||||
* @throws {MongoError}
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
ChangeStream.prototype.hasNext = function(callback) {
|
||||
return this.cursor.hasNext(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the next available document from the Change Stream, returns null if no more documents are available.
|
||||
* @function ChangeStream.prototype.next
|
||||
* @param {ChangeStream~resultCallback} [callback] The result callback.
|
||||
* @throws {MongoError}
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
ChangeStream.prototype.next = function(callback) {
|
||||
var self = this;
|
||||
if (this.isClosed()) {
|
||||
if (callback) return callback(new Error('Change Stream is not open.'), null);
|
||||
return self.promiseLibrary.reject(new Error('Change Stream is not open.'));
|
||||
}
|
||||
return this.cursor
|
||||
.next()
|
||||
.then(function(change) {
|
||||
return processNewChange(self, null, change, callback);
|
||||
})
|
||||
.catch(function(err) {
|
||||
return processNewChange(self, err, null, callback);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Is the cursor closed
|
||||
* @method ChangeStream.prototype.isClosed
|
||||
* @return {boolean}
|
||||
*/
|
||||
ChangeStream.prototype.isClosed = function() {
|
||||
if (this.cursor) {
|
||||
return this.cursor.isClosed();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Close the Change Stream
|
||||
* @method ChangeStream.prototype.close
|
||||
* @param {ChangeStream~resultCallback} [callback] The result callback.
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
ChangeStream.prototype.close = function(callback) {
|
||||
if (!this.cursor) {
|
||||
if (callback) return callback();
|
||||
return this.promiseLibrary.resolve();
|
||||
}
|
||||
|
||||
// Tidy up the existing cursor
|
||||
var cursor = this.cursor;
|
||||
delete this.cursor;
|
||||
return cursor.close(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method pulls all the data out of a readable stream, and writes it to the supplied destination, automatically managing the flow so that the destination is not overwhelmed by a fast readable stream.
|
||||
* @method
|
||||
* @param {Writable} destination The destination for writing data
|
||||
* @param {object} [options] {@link https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options|Pipe options}
|
||||
* @return {null}
|
||||
*/
|
||||
ChangeStream.prototype.pipe = function(destination, options) {
|
||||
if (!this.pipeDestinations) {
|
||||
this.pipeDestinations = [];
|
||||
}
|
||||
this.pipeDestinations.push(destination);
|
||||
return this.cursor.pipe(destination, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method will remove the hooks set up for a previous pipe() call.
|
||||
* @param {Writable} [destination] The destination for writing data
|
||||
* @return {null}
|
||||
*/
|
||||
ChangeStream.prototype.unpipe = function(destination) {
|
||||
if (this.pipeDestinations && this.pipeDestinations.indexOf(destination) > -1) {
|
||||
this.pipeDestinations.splice(this.pipeDestinations.indexOf(destination), 1);
|
||||
}
|
||||
return this.cursor.unpipe(destination);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method will cause a stream in flowing mode to stop emitting data events. Any data that becomes available will remain in the internal buffer.
|
||||
* @return {null}
|
||||
*/
|
||||
ChangeStream.prototype.pause = function() {
|
||||
return this.cursor.pause();
|
||||
};
|
||||
|
||||
/**
|
||||
* This method will cause the readable stream to resume emitting data events.
|
||||
* @return {null}
|
||||
*/
|
||||
ChangeStream.prototype.resume = function() {
|
||||
return this.cursor.resume();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a modified Readable stream including a possible transform method.
|
||||
* @method
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {function} [options.transform=null] A transformation method applied to each document emitted by the stream.
|
||||
* @return {Cursor}
|
||||
*/
|
||||
ChangeStream.prototype.stream = function(options) {
|
||||
this.streamOptions = options;
|
||||
return this.cursor.stream(options);
|
||||
};
|
||||
|
||||
// Handle new change events. This method brings together the routes from the callback, event emitter, and promise ways of using ChangeStream.
|
||||
var processNewChange = function(self, err, change, callback) {
|
||||
// Handle errors
|
||||
if (err) {
|
||||
// Handle resumable MongoNetworkErrors
|
||||
if (err instanceof MongoNetworkError && !self.attemptingResume) {
|
||||
self.attemptingResume = true;
|
||||
return self.cursor.close(function(closeErr) {
|
||||
if (closeErr) {
|
||||
if (callback) return callback(err, null);
|
||||
return self.promiseLibrary.reject(err);
|
||||
}
|
||||
|
||||
// Establish a new cursor
|
||||
self.cursor = createChangeStreamCursor(self);
|
||||
|
||||
// Attempt to reconfigure piping
|
||||
if (self.pipeDestinations) {
|
||||
var cursorStream = self.cursor.stream(self.streamOptions);
|
||||
for (var pipeDestination in self.pipeDestinations) {
|
||||
cursorStream.pipe(pipeDestination);
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt the next() operation again
|
||||
if (callback) return self.next(callback);
|
||||
return self.next();
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof callback === 'function') return callback(err, null);
|
||||
if (self.listenerCount('error')) return self.emit('error', err);
|
||||
return self.promiseLibrary.reject(err);
|
||||
}
|
||||
self.attemptingResume = false;
|
||||
|
||||
// Cache the resume token if it is present. If it is not present return an error.
|
||||
if (!change || !change._id) {
|
||||
var noResumeTokenError = new Error(
|
||||
'A change stream document has been received that lacks a resume token (_id).'
|
||||
);
|
||||
if (typeof callback === 'function') return callback(noResumeTokenError, null);
|
||||
if (self.listenerCount('error')) return self.emit('error', noResumeTokenError);
|
||||
return self.promiseLibrary.reject(noResumeTokenError);
|
||||
}
|
||||
self.resumeToken = change._id;
|
||||
|
||||
// Return the change
|
||||
if (typeof callback === 'function') return callback(err, change);
|
||||
if (self.listenerCount('change')) return self.emit('change', change);
|
||||
return self.promiseLibrary.resolve(change);
|
||||
};
|
||||
|
||||
/**
|
||||
* The callback format for results
|
||||
* @callback ChangeStream~resultCallback
|
||||
* @param {MongoError} error An error instance representing the error during the execution.
|
||||
* @param {(object|null)} result The result object if the command was executed successfully.
|
||||
*/
|
||||
|
||||
module.exports = ChangeStream;
|
3041
ProjectNow/NodeServer/node_modules/mongodb/lib/collection.js
generated
vendored
Normal file
3041
ProjectNow/NodeServer/node_modules/mongodb/lib/collection.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
324
ProjectNow/NodeServer/node_modules/mongodb/lib/command_cursor.js
generated
vendored
Normal file
324
ProjectNow/NodeServer/node_modules/mongodb/lib/command_cursor.js
generated
vendored
Normal file
@@ -0,0 +1,324 @@
|
||||
'use strict';
|
||||
|
||||
const inherits = require('util').inherits;
|
||||
const ReadPreference = require('mongodb-core').ReadPreference;
|
||||
const MongoError = require('mongodb-core').MongoError;
|
||||
const Readable = require('stream').Readable;
|
||||
const CoreCursor = require('./cursor');
|
||||
|
||||
/**
|
||||
* @fileOverview The **CommandCursor** class is an internal class that embodies a
|
||||
* generalized cursor based on a MongoDB command allowing for iteration over the
|
||||
* results returned. It supports one by one document iteration, conversion to an
|
||||
* array or can be iterated as a Node 0.10.X or higher stream
|
||||
*
|
||||
* **CommandCursor Cannot directly be instantiated**
|
||||
* @example
|
||||
* const MongoClient = require('mongodb').MongoClient;
|
||||
* const test = require('assert');
|
||||
* // Connection url
|
||||
* const url = 'mongodb://localhost:27017';
|
||||
* // Database Name
|
||||
* const dbName = 'test';
|
||||
* // Connect using MongoClient
|
||||
* MongoClient.connect(url, function(err, client) {
|
||||
* // Create a collection we want to drop later
|
||||
* const col = client.db(dbName).collection('listCollectionsExample1');
|
||||
* // Insert a bunch of documents
|
||||
* col.insert([{a:1, b:1}
|
||||
* , {a:2, b:2}, {a:3, b:3}
|
||||
* , {a:4, b:4}], {w:1}, function(err, result) {
|
||||
* test.equal(null, err);
|
||||
* // List the database collections available
|
||||
* db.listCollections().toArray(function(err, items) {
|
||||
* test.equal(null, err);
|
||||
* client.close();
|
||||
* });
|
||||
* });
|
||||
* });
|
||||
*/
|
||||
|
||||
/**
|
||||
* Namespace provided by the browser.
|
||||
* @external Readable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new Command Cursor instance (INTERNAL TYPE, do not instantiate directly)
|
||||
* @class CommandCursor
|
||||
* @extends external:Readable
|
||||
* @fires CommandCursor#data
|
||||
* @fires CommandCursor#end
|
||||
* @fires CommandCursor#close
|
||||
* @fires CommandCursor#readable
|
||||
* @return {CommandCursor} an CommandCursor instance.
|
||||
*/
|
||||
var CommandCursor = function(bson, ns, cmd, options, topology, topologyOptions) {
|
||||
CoreCursor.apply(this, Array.prototype.slice.call(arguments, 0));
|
||||
var state = CommandCursor.INIT;
|
||||
var streamOptions = {};
|
||||
|
||||
// MaxTimeMS
|
||||
var maxTimeMS = null;
|
||||
|
||||
// Get the promiseLibrary
|
||||
var promiseLibrary = options.promiseLibrary || Promise;
|
||||
|
||||
// Set up
|
||||
Readable.call(this, { objectMode: true });
|
||||
|
||||
// Internal state
|
||||
this.s = {
|
||||
// MaxTimeMS
|
||||
maxTimeMS: maxTimeMS,
|
||||
// State
|
||||
state: state,
|
||||
// Stream options
|
||||
streamOptions: streamOptions,
|
||||
// BSON
|
||||
bson: bson,
|
||||
// Namespace
|
||||
ns: ns,
|
||||
// Command
|
||||
cmd: cmd,
|
||||
// Options
|
||||
options: options,
|
||||
// Topology
|
||||
topology: topology,
|
||||
// Topology Options
|
||||
topologyOptions: topologyOptions,
|
||||
// Promise library
|
||||
promiseLibrary: promiseLibrary,
|
||||
// Optional ClientSession
|
||||
session: options.session
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* CommandCursor stream data event, fired for each document in the cursor.
|
||||
*
|
||||
* @event CommandCursor#data
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* CommandCursor stream end event
|
||||
*
|
||||
* @event CommandCursor#end
|
||||
* @type {null}
|
||||
*/
|
||||
|
||||
/**
|
||||
* CommandCursor stream close event
|
||||
*
|
||||
* @event CommandCursor#close
|
||||
* @type {null}
|
||||
*/
|
||||
|
||||
/**
|
||||
* CommandCursor stream readable event
|
||||
*
|
||||
* @event CommandCursor#readable
|
||||
* @type {null}
|
||||
*/
|
||||
|
||||
// Inherit from Readable
|
||||
inherits(CommandCursor, Readable);
|
||||
|
||||
// Set the methods to inherit from prototype
|
||||
var methodsToInherit = [
|
||||
'_next',
|
||||
'next',
|
||||
'hasNext',
|
||||
'each',
|
||||
'forEach',
|
||||
'toArray',
|
||||
'rewind',
|
||||
'bufferedCount',
|
||||
'readBufferedDocuments',
|
||||
'close',
|
||||
'isClosed',
|
||||
'kill',
|
||||
'setCursorBatchSize',
|
||||
'_find',
|
||||
'_getmore',
|
||||
'_killcursor',
|
||||
'isDead',
|
||||
'explain',
|
||||
'isNotified',
|
||||
'isKilled',
|
||||
'_endSession',
|
||||
'_initImplicitSession'
|
||||
];
|
||||
|
||||
// Only inherit the types we need
|
||||
for (var i = 0; i < methodsToInherit.length; i++) {
|
||||
CommandCursor.prototype[methodsToInherit[i]] = CoreCursor.prototype[methodsToInherit[i]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ReadPreference for the cursor.
|
||||
* @method
|
||||
* @param {(string|ReadPreference)} readPreference The new read preference for the cursor.
|
||||
* @throws {MongoError}
|
||||
* @return {Cursor}
|
||||
*/
|
||||
CommandCursor.prototype.setReadPreference = function(readPreference) {
|
||||
if (this.s.state === CommandCursor.CLOSED || this.isDead()) {
|
||||
throw MongoError.create({ message: 'Cursor is closed', driver: true });
|
||||
}
|
||||
|
||||
if (this.s.state !== CommandCursor.INIT) {
|
||||
throw MongoError.create({
|
||||
message: 'cannot change cursor readPreference after cursor has been accessed',
|
||||
driver: true
|
||||
});
|
||||
}
|
||||
|
||||
if (readPreference instanceof ReadPreference) {
|
||||
this.s.options.readPreference = readPreference;
|
||||
} else if (typeof readPreference === 'string') {
|
||||
this.s.options.readPreference = new ReadPreference(readPreference);
|
||||
} else {
|
||||
throw new TypeError('Invalid read preference: ' + readPreference);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the batch size for the cursor.
|
||||
* @method
|
||||
* @param {number} value The batchSize for the cursor.
|
||||
* @throws {MongoError}
|
||||
* @return {CommandCursor}
|
||||
*/
|
||||
CommandCursor.prototype.batchSize = function(value) {
|
||||
if (this.s.state === CommandCursor.CLOSED || this.isDead())
|
||||
throw MongoError.create({ message: 'Cursor is closed', driver: true });
|
||||
if (typeof value !== 'number')
|
||||
throw MongoError.create({ message: 'batchSize requires an integer', driver: true });
|
||||
if (this.s.cmd.cursor) this.s.cmd.cursor.batchSize = value;
|
||||
this.setCursorBatchSize(value);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a maxTimeMS stage to the aggregation pipeline
|
||||
* @method
|
||||
* @param {number} value The state maxTimeMS value.
|
||||
* @return {CommandCursor}
|
||||
*/
|
||||
CommandCursor.prototype.maxTimeMS = function(value) {
|
||||
if (this.s.topology.lastIsMaster().minWireVersion > 2) {
|
||||
this.s.cmd.maxTimeMS = value;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
CommandCursor.prototype.get = CommandCursor.prototype.toArray;
|
||||
|
||||
/**
|
||||
* Get the next available document from the cursor, returns null if no more documents are available.
|
||||
* @function CommandCursor.prototype.next
|
||||
* @param {CommandCursor~resultCallback} [callback] The result callback.
|
||||
* @throws {MongoError}
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check if there is any document still available in the cursor
|
||||
* @function CommandCursor.prototype.hasNext
|
||||
* @param {CommandCursor~resultCallback} [callback] The result callback.
|
||||
* @throws {MongoError}
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
|
||||
/**
|
||||
* The callback format for results
|
||||
* @callback CommandCursor~toArrayResultCallback
|
||||
* @param {MongoError} error An error instance representing the error during the execution.
|
||||
* @param {object[]} documents All the documents the satisfy the cursor.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns an array of documents. The caller is responsible for making sure that there
|
||||
* is enough memory to store the results. Note that the array only contain partial
|
||||
* results when this cursor had been previouly accessed.
|
||||
* @method CommandCursor.prototype.toArray
|
||||
* @param {CommandCursor~toArrayResultCallback} [callback] The result callback.
|
||||
* @throws {MongoError}
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
|
||||
/**
|
||||
* The callback format for results
|
||||
* @callback CommandCursor~resultCallback
|
||||
* @param {MongoError} error An error instance representing the error during the execution.
|
||||
* @param {(object|null)} result The result object if the command was executed successfully.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Iterates over all the documents for this cursor. As with **{cursor.toArray}**,
|
||||
* not all of the elements will be iterated if this cursor had been previouly accessed.
|
||||
* In that case, **{cursor.rewind}** can be used to reset the cursor. However, unlike
|
||||
* **{cursor.toArray}**, the cursor will only hold a maximum of batch size elements
|
||||
* at any given time if batch size is specified. Otherwise, the caller is responsible
|
||||
* for making sure that the entire result can fit the memory.
|
||||
* @method CommandCursor.prototype.each
|
||||
* @param {CommandCursor~resultCallback} callback The result callback.
|
||||
* @throws {MongoError}
|
||||
* @return {null}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Close the cursor, sending a KillCursor command and emitting close.
|
||||
* @method CommandCursor.prototype.close
|
||||
* @param {CommandCursor~resultCallback} [callback] The result callback.
|
||||
* @return {Promise} returns Promise if no callback passed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Is the cursor closed
|
||||
* @method CommandCursor.prototype.isClosed
|
||||
* @return {boolean}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Clone the cursor
|
||||
* @function CommandCursor.prototype.clone
|
||||
* @return {CommandCursor}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resets the cursor
|
||||
* @function CommandCursor.prototype.rewind
|
||||
* @return {CommandCursor}
|
||||
*/
|
||||
|
||||
/**
|
||||
* The callback format for the forEach iterator method
|
||||
* @callback CommandCursor~iteratorCallback
|
||||
* @param {Object} doc An emitted document for the iterator
|
||||
*/
|
||||
|
||||
/**
|
||||
* The callback error format for the forEach iterator method
|
||||
* @callback CommandCursor~endCallback
|
||||
* @param {MongoError} error An error instance representing the error during the execution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Iterates over all the documents for this cursor using the iterator, callback pattern.
|
||||
* @method CommandCursor.prototype.forEach
|
||||
* @param {CommandCursor~iteratorCallback} iterator The iteration callback.
|
||||
* @param {CommandCursor~endCallback} callback The end callback.
|
||||
* @throws {MongoError}
|
||||
* @return {null}
|
||||
*/
|
||||
|
||||
CommandCursor.INIT = 0;
|
||||
CommandCursor.OPEN = 1;
|
||||
CommandCursor.CLOSED = 2;
|
||||
|
||||
module.exports = CommandCursor;
|
1263
ProjectNow/NodeServer/node_modules/mongodb/lib/cursor.js
generated
vendored
Normal file
1263
ProjectNow/NodeServer/node_modules/mongodb/lib/cursor.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1748
ProjectNow/NodeServer/node_modules/mongodb/lib/db.js
generated
vendored
Normal file
1748
ProjectNow/NodeServer/node_modules/mongodb/lib/db.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
415
ProjectNow/NodeServer/node_modules/mongodb/lib/gridfs-stream/download.js
generated
vendored
Normal file
415
ProjectNow/NodeServer/node_modules/mongodb/lib/gridfs-stream/download.js
generated
vendored
Normal file
@@ -0,0 +1,415 @@
|
||||
'use strict';
|
||||
|
||||
var stream = require('stream'),
|
||||
util = require('util');
|
||||
|
||||
module.exports = GridFSBucketReadStream;
|
||||
|
||||
/**
|
||||
* A readable stream that enables you to read buffers from GridFS.
|
||||
*
|
||||
* Do not instantiate this class directly. Use `openDownloadStream()` instead.
|
||||
*
|
||||
* @class
|
||||
* @param {Collection} chunks Handle for chunks collection
|
||||
* @param {Collection} files Handle for files collection
|
||||
* @param {Object} readPreference The read preference to use
|
||||
* @param {Object} filter The query to use to find the file document
|
||||
* @param {Object} [options=null] Optional settings.
|
||||
* @param {Number} [options.sort=null] Optional sort for the file find query
|
||||
* @param {Number} [options.skip=null] Optional skip for the file find query
|
||||
* @param {Number} [options.start=null] Optional 0-based offset in bytes to start streaming from
|
||||
* @param {Number} [options.end=null] Optional 0-based offset in bytes to stop streaming before
|
||||
* @fires GridFSBucketReadStream#error
|
||||
* @fires GridFSBucketReadStream#file
|
||||
* @return {GridFSBucketReadStream} a GridFSBucketReadStream instance.
|
||||
*/
|
||||
|
||||
function GridFSBucketReadStream(chunks, files, readPreference, filter, options) {
|
||||
this.s = {
|
||||
bytesRead: 0,
|
||||
chunks: chunks,
|
||||
cursor: null,
|
||||
expected: 0,
|
||||
files: files,
|
||||
filter: filter,
|
||||
init: false,
|
||||
expectedEnd: 0,
|
||||
file: null,
|
||||
options: options,
|
||||
readPreference: readPreference
|
||||
};
|
||||
|
||||
stream.Readable.call(this);
|
||||
}
|
||||
|
||||
util.inherits(GridFSBucketReadStream, stream.Readable);
|
||||
|
||||
/**
|
||||
* An error occurred
|
||||
*
|
||||
* @event GridFSBucketReadStream#error
|
||||
* @type {Error}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fires when the stream loaded the file document corresponding to the
|
||||
* provided id.
|
||||
*
|
||||
* @event GridFSBucketReadStream#file
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Emitted when a chunk of data is available to be consumed.
|
||||
*
|
||||
* @event GridFSBucketReadStream#data
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fired when the stream is exhausted (no more data events).
|
||||
*
|
||||
* @event GridFSBucketReadStream#end
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fired when the stream is exhausted and the underlying cursor is killed
|
||||
*
|
||||
* @event GridFSBucketReadStream#close
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reads from the cursor and pushes to the stream.
|
||||
* @method
|
||||
*/
|
||||
|
||||
GridFSBucketReadStream.prototype._read = function() {
|
||||
var _this = this;
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
waitForFile(_this, function() {
|
||||
doRead(_this);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the 0-based offset in bytes to start streaming from. Throws
|
||||
* an error if this stream has entered flowing mode
|
||||
* (e.g. if you've already called `on('data')`)
|
||||
* @method
|
||||
* @param {Number} start Offset in bytes to start reading at
|
||||
* @return {GridFSBucketReadStream}
|
||||
*/
|
||||
|
||||
GridFSBucketReadStream.prototype.start = function(start) {
|
||||
throwIfInitialized(this);
|
||||
this.s.options.start = start;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the 0-based offset in bytes to start streaming from. Throws
|
||||
* an error if this stream has entered flowing mode
|
||||
* (e.g. if you've already called `on('data')`)
|
||||
* @method
|
||||
* @param {Number} end Offset in bytes to stop reading at
|
||||
* @return {GridFSBucketReadStream}
|
||||
*/
|
||||
|
||||
GridFSBucketReadStream.prototype.end = function(end) {
|
||||
throwIfInitialized(this);
|
||||
this.s.options.end = end;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Marks this stream as aborted (will never push another `data` event)
|
||||
* and kills the underlying cursor. Will emit the 'end' event, and then
|
||||
* the 'close' event once the cursor is successfully killed.
|
||||
*
|
||||
* @method
|
||||
* @param {GridFSBucket~errorCallback} [callback] called when the cursor is successfully closed or an error occurred.
|
||||
* @fires GridFSBucketWriteStream#close
|
||||
* @fires GridFSBucketWriteStream#end
|
||||
*/
|
||||
|
||||
GridFSBucketReadStream.prototype.abort = function(callback) {
|
||||
var _this = this;
|
||||
this.push(null);
|
||||
this.destroyed = true;
|
||||
if (this.s.cursor) {
|
||||
this.s.cursor.close(function(error) {
|
||||
_this.emit('close');
|
||||
callback && callback(error);
|
||||
});
|
||||
} else {
|
||||
if (!this.s.init) {
|
||||
// If not initialized, fire close event because we will never
|
||||
// get a cursor
|
||||
_this.emit('close');
|
||||
}
|
||||
callback && callback();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function throwIfInitialized(self) {
|
||||
if (self.s.init) {
|
||||
throw new Error('You cannot change options after the stream has entered' + 'flowing mode!');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function doRead(_this) {
|
||||
if (_this.destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
_this.s.cursor.next(function(error, doc) {
|
||||
if (_this.destroyed) {
|
||||
return;
|
||||
}
|
||||
if (error) {
|
||||
return __handleError(_this, error);
|
||||
}
|
||||
if (!doc) {
|
||||
_this.push(null);
|
||||
return _this.s.cursor.close(function(error) {
|
||||
if (error) {
|
||||
return __handleError(_this, error);
|
||||
}
|
||||
_this.emit('close');
|
||||
});
|
||||
}
|
||||
|
||||
var bytesRemaining = _this.s.file.length - _this.s.bytesRead;
|
||||
var expectedN = _this.s.expected++;
|
||||
var expectedLength = Math.min(_this.s.file.chunkSize, bytesRemaining);
|
||||
|
||||
if (doc.n > expectedN) {
|
||||
var errmsg = 'ChunkIsMissing: Got unexpected n: ' + doc.n + ', expected: ' + expectedN;
|
||||
return __handleError(_this, new Error(errmsg));
|
||||
}
|
||||
|
||||
if (doc.n < expectedN) {
|
||||
errmsg = 'ExtraChunk: Got unexpected n: ' + doc.n + ', expected: ' + expectedN;
|
||||
return __handleError(_this, new Error(errmsg));
|
||||
}
|
||||
|
||||
var buf = Buffer.isBuffer(doc.data) ? doc.data : doc.data.buffer;
|
||||
|
||||
if (buf.length !== expectedLength) {
|
||||
if (bytesRemaining <= 0) {
|
||||
errmsg = 'ExtraChunk: Got unexpected n: ' + doc.n;
|
||||
return __handleError(_this, new Error(errmsg));
|
||||
}
|
||||
|
||||
errmsg =
|
||||
'ChunkIsWrongSize: Got unexpected length: ' + buf.length + ', expected: ' + expectedLength;
|
||||
return __handleError(_this, new Error(errmsg));
|
||||
}
|
||||
|
||||
_this.s.bytesRead += buf.length;
|
||||
|
||||
if (buf.length === 0) {
|
||||
return _this.push(null);
|
||||
}
|
||||
|
||||
var sliceStart = null;
|
||||
var sliceEnd = null;
|
||||
|
||||
if (_this.s.bytesToSkip != null) {
|
||||
sliceStart = _this.s.bytesToSkip;
|
||||
_this.s.bytesToSkip = 0;
|
||||
}
|
||||
|
||||
if (expectedN === _this.s.expectedEnd && _this.s.bytesToTrim != null) {
|
||||
sliceEnd = _this.s.bytesToTrim;
|
||||
}
|
||||
|
||||
// If the remaining amount of data left is < chunkSize read the right amount of data
|
||||
if (_this.s.options.end && _this.s.options.end - _this.s.bytesToSkip < buf.length) {
|
||||
sliceEnd = _this.s.options.end - _this.s.bytesToSkip;
|
||||
}
|
||||
|
||||
if (sliceStart != null || sliceEnd != null) {
|
||||
buf = buf.slice(sliceStart || 0, sliceEnd || buf.length);
|
||||
}
|
||||
|
||||
_this.push(buf);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function init(self) {
|
||||
var findOneOptions = {};
|
||||
if (self.s.readPreference) {
|
||||
findOneOptions.readPreference = self.s.readPreference;
|
||||
}
|
||||
if (self.s.options && self.s.options.sort) {
|
||||
findOneOptions.sort = self.s.options.sort;
|
||||
}
|
||||
if (self.s.options && self.s.options.skip) {
|
||||
findOneOptions.skip = self.s.options.skip;
|
||||
}
|
||||
|
||||
self.s.files.findOne(self.s.filter, findOneOptions, function(error, doc) {
|
||||
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';
|
||||
var err = new Error(errmsg);
|
||||
err.code = 'ENOENT';
|
||||
return __handleError(self, err);
|
||||
}
|
||||
|
||||
// If document is empty, kill the stream immediately and don't
|
||||
// execute any reads
|
||||
if (doc.length <= 0) {
|
||||
self.push(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.destroyed) {
|
||||
// If user destroys the stream before we have a cursor, wait
|
||||
// until the query is done to say we're 'closed' because we can't
|
||||
// cancel a query.
|
||||
self.emit('close');
|
||||
return;
|
||||
}
|
||||
|
||||
self.s.bytesToSkip = handleStartOption(self, doc, self.s.options);
|
||||
|
||||
var filter = { files_id: doc._id };
|
||||
|
||||
// Currently (MongoDB 3.4.4) skip function does not support the index,
|
||||
// it needs to retrieve all the documents first and then skip them. (CS-25811)
|
||||
// As work around we use $gte on the "n" field.
|
||||
if (self.s.options && self.s.options.start != null) {
|
||||
var skip = Math.floor(self.s.options.start / doc.chunkSize);
|
||||
if (skip > 0) {
|
||||
filter['n'] = { $gte: skip };
|
||||
}
|
||||
}
|
||||
self.s.cursor = self.s.chunks.find(filter).sort({ n: 1 });
|
||||
|
||||
if (self.s.readPreference) {
|
||||
self.s.cursor.setReadPreference(self.s.readPreference);
|
||||
}
|
||||
|
||||
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);
|
||||
self.emit('file', doc);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function waitForFile(_this, callback) {
|
||||
if (_this.s.file) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
if (!_this.s.init) {
|
||||
init(_this);
|
||||
_this.s.init = true;
|
||||
}
|
||||
|
||||
_this.once('file', function() {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function handleStartOption(stream, doc, options) {
|
||||
if (options && options.start != null) {
|
||||
if (options.start > doc.length) {
|
||||
throw new Error(
|
||||
'Stream start (' +
|
||||
options.start +
|
||||
') must not be ' +
|
||||
'more than the length of the file (' +
|
||||
doc.length +
|
||||
')'
|
||||
);
|
||||
}
|
||||
if (options.start < 0) {
|
||||
throw new Error('Stream start (' + options.start + ') must not be ' + 'negative');
|
||||
}
|
||||
if (options.end != null && options.end < options.start) {
|
||||
throw new Error(
|
||||
'Stream start (' +
|
||||
options.start +
|
||||
') must not be ' +
|
||||
'greater than stream end (' +
|
||||
options.end +
|
||||
')'
|
||||
);
|
||||
}
|
||||
|
||||
stream.s.bytesRead = Math.floor(options.start / doc.chunkSize) * doc.chunkSize;
|
||||
stream.s.expected = Math.floor(options.start / doc.chunkSize);
|
||||
|
||||
return options.start - stream.s.bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function handleEndOption(stream, doc, cursor, options) {
|
||||
if (options && options.end != null) {
|
||||
if (options.end > doc.length) {
|
||||
throw new Error(
|
||||
'Stream end (' +
|
||||
options.end +
|
||||
') must not be ' +
|
||||
'more than the length of the file (' +
|
||||
doc.length +
|
||||
')'
|
||||
);
|
||||
}
|
||||
if (options.start < 0) {
|
||||
throw new Error('Stream end (' + options.end + ') must not be ' + 'negative');
|
||||
}
|
||||
|
||||
var start = options.start != null ? Math.floor(options.start / doc.chunkSize) : 0;
|
||||
|
||||
cursor.limit(Math.ceil(options.end / doc.chunkSize) - start);
|
||||
|
||||
stream.s.expectedEnd = Math.ceil(options.end / doc.chunkSize);
|
||||
|
||||
return Math.ceil(options.end / doc.chunkSize) * doc.chunkSize - options.end;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function __handleError(_this, error) {
|
||||
_this.emit('error', error);
|
||||
}
|
346
ProjectNow/NodeServer/node_modules/mongodb/lib/gridfs-stream/index.js
generated
vendored
Normal file
346
ProjectNow/NodeServer/node_modules/mongodb/lib/gridfs-stream/index.js
generated
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
'use strict';
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var GridFSBucketReadStream = require('./download');
|
||||
var GridFSBucketWriteStream = require('./upload');
|
||||
var shallowClone = require('../utils').shallowClone;
|
||||
var toError = require('../utils').toError;
|
||||
var util = require('util');
|
||||
var executeOperation = require('../utils').executeOperation;
|
||||
|
||||
var DEFAULT_GRIDFS_BUCKET_OPTIONS = {
|
||||
bucketName: 'fs',
|
||||
chunkSizeBytes: 255 * 1024
|
||||
};
|
||||
|
||||
module.exports = GridFSBucket;
|
||||
|
||||
/**
|
||||
* Constructor for a streaming GridFS interface
|
||||
* @class
|
||||
* @param {Db} db A db handle
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {string} [options.bucketName="fs"] The 'files' and 'chunks' collections will be prefixed with the bucket name followed by a dot.
|
||||
* @param {number} [options.chunkSizeBytes=255 * 1024] Number of bytes stored in each chunk. Defaults to 255KB
|
||||
* @param {object} [options.writeConcern=null] Optional write concern to be passed to write operations, for instance `{ w: 1 }`
|
||||
* @param {object} [options.readPreference=null] Optional read preference to be passed to read operations
|
||||
* @fires GridFSBucketWriteStream#index
|
||||
* @return {GridFSBucket}
|
||||
*/
|
||||
|
||||
function GridFSBucket(db, options) {
|
||||
Emitter.apply(this);
|
||||
this.setMaxListeners(0);
|
||||
|
||||
if (options && typeof options === 'object') {
|
||||
options = shallowClone(options);
|
||||
var keys = Object.keys(DEFAULT_GRIDFS_BUCKET_OPTIONS);
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
if (!options[keys[i]]) {
|
||||
options[keys[i]] = DEFAULT_GRIDFS_BUCKET_OPTIONS[keys[i]];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
options = DEFAULT_GRIDFS_BUCKET_OPTIONS;
|
||||
}
|
||||
|
||||
this.s = {
|
||||
db: db,
|
||||
options: options,
|
||||
_chunksCollection: db.collection(options.bucketName + '.chunks'),
|
||||
_filesCollection: db.collection(options.bucketName + '.files'),
|
||||
checkedIndexes: false,
|
||||
calledOpenUploadStream: false,
|
||||
promiseLibrary: db.s.promiseLibrary || Promise
|
||||
};
|
||||
}
|
||||
|
||||
util.inherits(GridFSBucket, Emitter);
|
||||
|
||||
/**
|
||||
* When the first call to openUploadStream is made, the upload stream will
|
||||
* check to see if it needs to create the proper indexes on the chunks and
|
||||
* files collections. This event is fired either when 1) it determines that
|
||||
* no index creation is necessary, 2) when it successfully creates the
|
||||
* necessary indexes.
|
||||
*
|
||||
* @event GridFSBucket#index
|
||||
* @type {Error}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a writable stream (GridFSBucketWriteStream) for writing
|
||||
* buffers to GridFS. The stream's 'id' property contains the resulting
|
||||
* file's id.
|
||||
* @method
|
||||
* @param {string} filename The value of the 'filename' key in the files doc
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {number} [options.chunkSizeBytes=null] Optional overwrite this bucket's chunkSizeBytes for this file
|
||||
* @param {object} [options.metadata=null] Optional object to store in the file document's `metadata` field
|
||||
* @param {string} [options.contentType=null] Optional string to store in the file document's `contentType` field
|
||||
* @param {array} [options.aliases=null] Optional array of strings to store in the file document's `aliases` field
|
||||
* @return {GridFSBucketWriteStream}
|
||||
*/
|
||||
|
||||
GridFSBucket.prototype.openUploadStream = 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);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a writable stream (GridFSBucketWriteStream) for writing
|
||||
* buffers to GridFS for a custom file id. The stream's 'id' property contains the resulting
|
||||
* file's id.
|
||||
* @method
|
||||
* @param {string|number|object} id A custom id used to identify the file
|
||||
* @param {string} filename The value of the 'filename' key in the files doc
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {number} [options.chunkSizeBytes=null] Optional overwrite this bucket's chunkSizeBytes for this file
|
||||
* @param {object} [options.metadata=null] Optional object to store in the file document's `metadata` field
|
||||
* @param {string} [options.contentType=null] Optional string to store in the file document's `contentType` field
|
||||
* @param {array} [options.aliases=null] Optional array of strings to store in the file document's `aliases` field
|
||||
* @return {GridFSBucketWriteStream}
|
||||
*/
|
||||
|
||||
GridFSBucket.prototype.openUploadStreamWithId = 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);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a readable stream (GridFSBucketReadStream) for streaming file
|
||||
* data from GridFS.
|
||||
* @method
|
||||
* @param {ObjectId} id The id of the file doc
|
||||
* @param {Object} [options=null] Optional settings.
|
||||
* @param {Number} [options.start=null] Optional 0-based offset in bytes to start streaming from
|
||||
* @param {Number} [options.end=null] Optional 0-based offset in bytes to stop streaming before
|
||||
* @return {GridFSBucketReadStream}
|
||||
*/
|
||||
|
||||
GridFSBucket.prototype.openDownloadStream = function(id, options) {
|
||||
var filter = { _id: id };
|
||||
options = {
|
||||
start: options && options.start,
|
||||
end: options && options.end
|
||||
};
|
||||
|
||||
return new GridFSBucketReadStream(
|
||||
this.s._chunksCollection,
|
||||
this.s._filesCollection,
|
||||
this.s.options.readPreference,
|
||||
filter,
|
||||
options
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes a file with the given id
|
||||
* @method
|
||||
* @param {ObjectId} id The id of the file doc
|
||||
* @param {GridFSBucket~errorCallback} [callback]
|
||||
*/
|
||||
|
||||
GridFSBucket.prototype.delete = function(id, callback) {
|
||||
return executeOperation(this.s.db.s.topology, _delete, [this, id, callback], {
|
||||
skipSessions: true
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function _delete(_this, id, callback) {
|
||||
_this.s._filesCollection.deleteOne({ _id: id }, function(error, res) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
_this.s._chunksCollection.deleteMany({ files_id: id }, function(error) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
// Delete orphaned chunks before returning FileNotFound
|
||||
if (!res.result.n) {
|
||||
var errmsg = 'FileNotFound: no file with id ' + id + ' found';
|
||||
return callback(new Error(errmsg));
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience wrapper around find on the files collection
|
||||
* @method
|
||||
* @param {Object} filter
|
||||
* @param {Object} [options=null] Optional settings for cursor
|
||||
* @param {number} [options.batchSize=null] Optional batch size for cursor
|
||||
* @param {number} [options.limit=null] Optional limit for cursor
|
||||
* @param {number} [options.maxTimeMS=null] Optional maxTimeMS for cursor
|
||||
* @param {boolean} [options.noCursorTimeout=null] Optionally set cursor's `noCursorTimeout` flag
|
||||
* @param {number} [options.skip=null] Optional skip for cursor
|
||||
* @param {object} [options.sort=null] Optional sort for cursor
|
||||
* @return {Cursor}
|
||||
*/
|
||||
|
||||
GridFSBucket.prototype.find = function(filter, options) {
|
||||
filter = filter || {};
|
||||
options = options || {};
|
||||
|
||||
var cursor = this.s._filesCollection.find(filter);
|
||||
|
||||
if (options.batchSize != null) {
|
||||
cursor.batchSize(options.batchSize);
|
||||
}
|
||||
if (options.limit != null) {
|
||||
cursor.limit(options.limit);
|
||||
}
|
||||
if (options.maxTimeMS != null) {
|
||||
cursor.maxTimeMS(options.maxTimeMS);
|
||||
}
|
||||
if (options.noCursorTimeout != null) {
|
||||
cursor.addCursorFlag('noCursorTimeout', options.noCursorTimeout);
|
||||
}
|
||||
if (options.skip != null) {
|
||||
cursor.skip(options.skip);
|
||||
}
|
||||
if (options.sort != null) {
|
||||
cursor.sort(options.sort);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a readable stream (GridFSBucketReadStream) for streaming the
|
||||
* file with the given name from GridFS. If there are multiple files with
|
||||
* the same name, this will stream the most recent file with the given name
|
||||
* (as determined by the `uploadDate` field). You can set the `revision`
|
||||
* option to change this behavior.
|
||||
* @method
|
||||
* @param {String} filename The name of the file to stream
|
||||
* @param {Object} [options=null] Optional settings
|
||||
* @param {number} [options.revision=-1] The revision number relative to the oldest file with the given filename. 0 gets you the oldest file, 1 gets you the 2nd oldest, -1 gets you the newest.
|
||||
* @param {Number} [options.start=null] Optional 0-based offset in bytes to start streaming from
|
||||
* @param {Number} [options.end=null] Optional 0-based offset in bytes to stop streaming before
|
||||
* @return {GridFSBucketReadStream}
|
||||
*/
|
||||
|
||||
GridFSBucket.prototype.openDownloadStreamByName = function(filename, options) {
|
||||
var sort = { uploadDate: -1 };
|
||||
var skip = null;
|
||||
if (options && options.revision != null) {
|
||||
if (options.revision >= 0) {
|
||||
sort = { uploadDate: 1 };
|
||||
skip = options.revision;
|
||||
} else {
|
||||
skip = -options.revision - 1;
|
||||
}
|
||||
}
|
||||
|
||||
var filter = { filename: filename };
|
||||
options = {
|
||||
sort: sort,
|
||||
skip: skip,
|
||||
start: options && options.start,
|
||||
end: options && options.end
|
||||
};
|
||||
return new GridFSBucketReadStream(
|
||||
this.s._chunksCollection,
|
||||
this.s._filesCollection,
|
||||
this.s.options.readPreference,
|
||||
filter,
|
||||
options
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Renames the file with the given _id to the given string
|
||||
* @method
|
||||
* @param {ObjectId} id the id of the file to rename
|
||||
* @param {String} filename new name for the file
|
||||
* @param {GridFSBucket~errorCallback} [callback]
|
||||
*/
|
||||
|
||||
GridFSBucket.prototype.rename = function(id, filename, callback) {
|
||||
return executeOperation(this.s.db.s.topology, _rename, [this, id, filename, callback], {
|
||||
skipSessions: true
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function _rename(_this, id, filename, callback) {
|
||||
var filter = { _id: id };
|
||||
var update = { $set: { filename: filename } };
|
||||
_this.s._filesCollection.updateOne(filter, update, function(error, res) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
if (!res.result.n) {
|
||||
return callback(toError('File with id ' + id + ' not found'));
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes this bucket's files collection, followed by its chunks collection.
|
||||
* @method
|
||||
* @param {GridFSBucket~errorCallback} [callback]
|
||||
*/
|
||||
|
||||
GridFSBucket.prototype.drop = function(callback) {
|
||||
return executeOperation(this.s.db.s.topology, _drop, [this, callback], {
|
||||
skipSessions: true
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function _drop(_this, callback) {
|
||||
_this.s._filesCollection.drop(function(error) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
_this.s._chunksCollection.drop(function(error) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
return callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback format for all GridFSBucket methods that can accept a callback.
|
||||
* @callback GridFSBucket~errorCallback
|
||||
* @param {MongoError} error An error instance representing any errors that occurred
|
||||
*/
|
529
ProjectNow/NodeServer/node_modules/mongodb/lib/gridfs-stream/upload.js
generated
vendored
Normal file
529
ProjectNow/NodeServer/node_modules/mongodb/lib/gridfs-stream/upload.js
generated
vendored
Normal file
@@ -0,0 +1,529 @@
|
||||
'use strict';
|
||||
|
||||
var core = require('mongodb-core');
|
||||
var crypto = require('crypto');
|
||||
var stream = require('stream');
|
||||
var util = require('util');
|
||||
|
||||
var ERROR_NAMESPACE_NOT_FOUND = 26;
|
||||
|
||||
module.exports = GridFSBucketWriteStream;
|
||||
|
||||
/**
|
||||
* A writable stream that enables you to write buffers to GridFS.
|
||||
*
|
||||
* Do not instantiate this class directly. Use `openUploadStream()` instead.
|
||||
*
|
||||
* @class
|
||||
* @param {GridFSBucket} bucket Handle for this stream's corresponding bucket
|
||||
* @param {string} filename The value of the 'filename' key in the files doc
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {string|number|object} [options.id=null] Custom file id for the GridFS file.
|
||||
* @param {number} [options.chunkSizeBytes=null] The chunk size to use, in bytes
|
||||
* @param {number} [options.w=null] The write concern
|
||||
* @param {number} [options.wtimeout=null] The write concern timeout
|
||||
* @param {number} [options.j=null] The journal write concern
|
||||
* @fires GridFSBucketWriteStream#error
|
||||
* @fires GridFSBucketWriteStream#finish
|
||||
* @return {GridFSBucketWriteStream} a GridFSBucketWriteStream instance.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
this.id = options.id ? options.id : core.BSON.ObjectId();
|
||||
this.chunkSizeBytes = this.options.chunkSizeBytes;
|
||||
this.bufToStore = new Buffer(this.chunkSizeBytes);
|
||||
this.length = 0;
|
||||
this.md5 = 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;
|
||||
|
||||
var _this = this;
|
||||
checkIndexes(this, function() {
|
||||
_this.bucket.s.checkedIndexes = true;
|
||||
_this.bucket.emit('index');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
util.inherits(GridFSBucketWriteStream, stream.Writable);
|
||||
|
||||
/**
|
||||
* An error occurred
|
||||
*
|
||||
* @event GridFSBucketWriteStream#error
|
||||
* @type {Error}
|
||||
*/
|
||||
|
||||
/**
|
||||
* `end()` was called and the write stream successfully wrote the file
|
||||
* metadata and all the chunks to MongoDB.
|
||||
*
|
||||
* @event GridFSBucketWriteStream#finish
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Write a buffer to the stream.
|
||||
*
|
||||
* @method
|
||||
* @param {Buffer} chunk Buffer to write
|
||||
* @param {String} encoding Optional encoding for the buffer
|
||||
* @param {Function} callback Function to call when the chunk was added to the buffer, or if the entire chunk was persisted to MongoDB if this chunk caused a flush.
|
||||
* @return {Boolean} False if this write required flushing a chunk to MongoDB. True otherwise.
|
||||
*/
|
||||
|
||||
GridFSBucketWriteStream.prototype.write = function(chunk, encoding, callback) {
|
||||
var _this = this;
|
||||
return waitForIndexes(this, function() {
|
||||
return doWrite(_this, chunk, encoding, callback);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Places this write stream into an aborted state (all future writes fail)
|
||||
* and deletes all chunks that have already been written.
|
||||
*
|
||||
* @method
|
||||
* @param {GridFSBucket~errorCallback} callback called when chunks are successfully removed or error occurred
|
||||
* @return {Promise} if no callback specified
|
||||
*/
|
||||
|
||||
GridFSBucketWriteStream.prototype.abort = function(callback) {
|
||||
if (this.state.streamEnd) {
|
||||
var error = new Error('Cannot abort a stream that has already completed');
|
||||
if (typeof callback === 'function') {
|
||||
return callback(error);
|
||||
}
|
||||
return this.state.promiseLibrary.reject(error);
|
||||
}
|
||||
if (this.state.aborted) {
|
||||
error = new Error('Cannot call abort() on a stream twice');
|
||||
if (typeof callback === 'function') {
|
||||
return callback(error);
|
||||
}
|
||||
return this.state.promiseLibrary.reject(error);
|
||||
}
|
||||
this.state.aborted = true;
|
||||
this.chunks.deleteMany({ files_id: this.id }, function(error) {
|
||||
if (typeof callback === 'function') callback(error);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells the stream that no more data will be coming in. The stream will
|
||||
* persist the remaining data to MongoDB, write the files document, and
|
||||
* then emit a 'finish' event.
|
||||
*
|
||||
* @method
|
||||
* @param {Buffer} chunk Buffer to write
|
||||
* @param {String} encoding Optional encoding for the buffer
|
||||
* @param {Function} callback Function to call when all files and chunks have been persisted to MongoDB
|
||||
*/
|
||||
|
||||
GridFSBucketWriteStream.prototype.end = function(chunk, encoding, callback) {
|
||||
var _this = this;
|
||||
if (typeof chunk === 'function') {
|
||||
(callback = chunk), (chunk = null), (encoding = null);
|
||||
} else if (typeof encoding === 'function') {
|
||||
(callback = encoding), (encoding = null);
|
||||
}
|
||||
|
||||
if (checkAborted(this, callback)) {
|
||||
return;
|
||||
}
|
||||
this.state.streamEnd = true;
|
||||
|
||||
if (callback) {
|
||||
this.once('finish', function(result) {
|
||||
callback(null, result);
|
||||
});
|
||||
}
|
||||
|
||||
if (!chunk) {
|
||||
waitForIndexes(this, function() {
|
||||
writeRemnant(_this);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.write(chunk, encoding, function() {
|
||||
writeRemnant(_this);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function __handleError(_this, error, callback) {
|
||||
if (_this.state.errored) {
|
||||
return;
|
||||
}
|
||||
_this.state.errored = true;
|
||||
if (callback) {
|
||||
return callback(error);
|
||||
}
|
||||
_this.emit('error', error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function createChunkDoc(filesId, n, data) {
|
||||
return {
|
||||
_id: core.BSON.ObjectId(),
|
||||
files_id: filesId,
|
||||
n: n,
|
||||
data: data
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
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) {
|
||||
var index = { files_id: 1, n: 1 };
|
||||
_this.chunks.createIndex(index, { background: false, unique: true }, function(error) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
return;
|
||||
}
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
var hasChunksIndex = false;
|
||||
indexes.forEach(function(index) {
|
||||
if (index.key) {
|
||||
var keys = Object.keys(index.key);
|
||||
if (keys.length === 2 && index.key.files_id === 1 && index.key.n === 1) {
|
||||
hasChunksIndex = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (hasChunksIndex) {
|
||||
callback();
|
||||
} else {
|
||||
index = { files_id: 1, n: 1 };
|
||||
var indexOptions = getWriteOptions(_this);
|
||||
|
||||
indexOptions.background = false;
|
||||
indexOptions.unique = true;
|
||||
|
||||
_this.chunks.createIndex(index, indexOptions, function(error) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function checkDone(_this, callback) {
|
||||
if (_this.done) return true;
|
||||
if (_this.state.streamEnd && _this.state.outstandingRequests === 0 && !_this.state.errored) {
|
||||
// Set done so we dont' trigger duplicate createFilesDoc
|
||||
_this.done = true;
|
||||
// Create a new files doc
|
||||
var filesDoc = createFilesDoc(
|
||||
_this.id,
|
||||
_this.length,
|
||||
_this.chunkSizeBytes,
|
||||
_this.md5.digest('hex'),
|
||||
_this.filename,
|
||||
_this.options.contentType,
|
||||
_this.options.aliases,
|
||||
_this.options.metadata
|
||||
);
|
||||
|
||||
if (checkAborted(_this, callback)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_this.files.insert(filesDoc, getWriteOptions(_this), function(error) {
|
||||
if (error) {
|
||||
return __handleError(_this, error, callback);
|
||||
}
|
||||
_this.emit('finish', filesDoc);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function checkIndexes(_this, callback) {
|
||||
_this.files.findOne({}, { _id: 1 }, function(error, doc) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
if (doc) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
_this.files.listIndexes().toArray(function(error, indexes) {
|
||||
if (error) {
|
||||
// Collection doesn't exist so create index
|
||||
if (error.code === ERROR_NAMESPACE_NOT_FOUND) {
|
||||
var index = { filename: 1, uploadDate: 1 };
|
||||
_this.files.createIndex(index, { background: false }, function(error) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
checkChunksIndex(_this, callback);
|
||||
});
|
||||
return;
|
||||
}
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
var hasFileIndex = false;
|
||||
indexes.forEach(function(index) {
|
||||
var keys = Object.keys(index.key);
|
||||
if (keys.length === 2 && index.key.filename === 1 && index.key.uploadDate === 1) {
|
||||
hasFileIndex = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasFileIndex) {
|
||||
checkChunksIndex(_this, callback);
|
||||
} else {
|
||||
index = { filename: 1, uploadDate: 1 };
|
||||
|
||||
var indexOptions = getWriteOptions(_this);
|
||||
|
||||
indexOptions.background = false;
|
||||
|
||||
_this.files.createIndex(index, indexOptions, function(error) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
checkChunksIndex(_this, callback);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function createFilesDoc(_id, length, chunkSize, md5, filename, contentType, aliases, metadata) {
|
||||
var ret = {
|
||||
_id: _id,
|
||||
length: length,
|
||||
chunkSize: chunkSize,
|
||||
uploadDate: new Date(),
|
||||
md5: md5,
|
||||
filename: filename
|
||||
};
|
||||
|
||||
if (contentType) {
|
||||
ret.contentType = contentType;
|
||||
}
|
||||
|
||||
if (aliases) {
|
||||
ret.aliases = aliases;
|
||||
}
|
||||
|
||||
if (metadata) {
|
||||
ret.metadata = metadata;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function doWrite(_this, chunk, encoding, callback) {
|
||||
if (checkAborted(_this, callback)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var inputBuf = Buffer.isBuffer(chunk) ? chunk : new Buffer(chunk, encoding);
|
||||
|
||||
_this.length += inputBuf.length;
|
||||
|
||||
// Input is small enough to fit in our buffer
|
||||
if (_this.pos + inputBuf.length < _this.chunkSizeBytes) {
|
||||
inputBuf.copy(_this.bufToStore, _this.pos);
|
||||
_this.pos += inputBuf.length;
|
||||
|
||||
callback && callback();
|
||||
|
||||
// Note that we reverse the typical semantics of write's return value
|
||||
// to be compatible with node's `.pipe()` function.
|
||||
// True means client can keep writing.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, buffer is too big for current chunk, so we need to flush
|
||||
// to MongoDB.
|
||||
var inputBufRemaining = inputBuf.length;
|
||||
var spaceRemaining = _this.chunkSizeBytes - _this.pos;
|
||||
var numToCopy = Math.min(spaceRemaining, inputBuf.length);
|
||||
var outstandingRequests = 0;
|
||||
while (inputBufRemaining > 0) {
|
||||
var inputBufPos = inputBuf.length - inputBufRemaining;
|
||||
inputBuf.copy(_this.bufToStore, _this.pos, inputBufPos, inputBufPos + numToCopy);
|
||||
_this.pos += numToCopy;
|
||||
spaceRemaining -= numToCopy;
|
||||
if (spaceRemaining === 0) {
|
||||
_this.md5.update(_this.bufToStore);
|
||||
var doc = createChunkDoc(_this.id, _this.n, _this.bufToStore);
|
||||
++_this.state.outstandingRequests;
|
||||
++outstandingRequests;
|
||||
|
||||
if (checkAborted(_this, callback)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_this.chunks.insert(doc, getWriteOptions(_this), function(error) {
|
||||
if (error) {
|
||||
return __handleError(_this, error);
|
||||
}
|
||||
--_this.state.outstandingRequests;
|
||||
--outstandingRequests;
|
||||
|
||||
if (!outstandingRequests) {
|
||||
_this.emit('drain', doc);
|
||||
callback && callback();
|
||||
checkDone(_this);
|
||||
}
|
||||
});
|
||||
|
||||
spaceRemaining = _this.chunkSizeBytes;
|
||||
_this.pos = 0;
|
||||
++_this.n;
|
||||
}
|
||||
inputBufRemaining -= numToCopy;
|
||||
numToCopy = Math.min(spaceRemaining, inputBufRemaining);
|
||||
}
|
||||
|
||||
// Note that we reverse the typical semantics of write's return value
|
||||
// to be compatible with node's `.pipe()` function.
|
||||
// False means the client should wait for the 'drain' event.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function getWriteOptions(_this) {
|
||||
var obj = {};
|
||||
if (_this.options.writeConcern) {
|
||||
obj.w = _this.options.writeConcern.w;
|
||||
obj.wtimeout = _this.options.writeConcern.wtimeout;
|
||||
obj.j = _this.options.writeConcern.j;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function waitForIndexes(_this, callback) {
|
||||
if (_this.bucket.s.checkedIndexes) {
|
||||
return callback(false);
|
||||
}
|
||||
|
||||
_this.bucket.once('index', function() {
|
||||
callback(true);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function writeRemnant(_this, callback) {
|
||||
// Buffer is empty, so don't bother to insert
|
||||
if (_this.pos === 0) {
|
||||
return checkDone(_this, callback);
|
||||
}
|
||||
|
||||
++_this.state.outstandingRequests;
|
||||
|
||||
// Create a new buffer to make sure the buffer isn't bigger than it needs
|
||||
// to be.
|
||||
var remnant = new Buffer(_this.pos);
|
||||
_this.bufToStore.copy(remnant, 0, 0, _this.pos);
|
||||
_this.md5.update(remnant);
|
||||
var doc = createChunkDoc(_this.id, _this.n, remnant);
|
||||
|
||||
// If the stream was aborted, do not write remnant
|
||||
if (checkAborted(_this, callback)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_this.chunks.insert(doc, getWriteOptions(_this), function(error) {
|
||||
if (error) {
|
||||
return __handleError(_this, error);
|
||||
}
|
||||
--_this.state.outstandingRequests;
|
||||
checkDone(_this);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
||||
function checkAborted(_this, callback) {
|
||||
if (_this.state.aborted) {
|
||||
if (typeof callback === 'function') {
|
||||
callback(new Error('this stream has been aborted'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
234
ProjectNow/NodeServer/node_modules/mongodb/lib/gridfs/chunk.js
generated
vendored
Normal file
234
ProjectNow/NodeServer/node_modules/mongodb/lib/gridfs/chunk.js
generated
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
'use strict';
|
||||
|
||||
var Binary = require('mongodb-core').BSON.Binary,
|
||||
ObjectID = require('mongodb-core').BSON.ObjectID;
|
||||
|
||||
/**
|
||||
* Class for representing a single chunk in GridFS.
|
||||
*
|
||||
* @class
|
||||
*
|
||||
* @param file {GridStore} The {@link GridStore} object holding this chunk.
|
||||
* @param mongoObject {object} The mongo object representation of this chunk.
|
||||
*
|
||||
* @throws Error when the type of data field for {@link mongoObject} is not
|
||||
* supported. Currently supported types for data field are instances of
|
||||
* {@link String}, {@link Array}, {@link Binary} and {@link Binary}
|
||||
* from the bson module
|
||||
*
|
||||
* @see Chunk#buildMongoObject
|
||||
*/
|
||||
var Chunk = function(file, mongoObject, writeConcern) {
|
||||
if (!(this instanceof Chunk)) return new Chunk(file, mongoObject);
|
||||
|
||||
this.file = file;
|
||||
var mongoObjectFinal = mongoObject == null ? {} : mongoObject;
|
||||
this.writeConcern = writeConcern || { w: 1 };
|
||||
this.objectId = mongoObjectFinal._id == null ? new ObjectID() : mongoObjectFinal._id;
|
||||
this.chunkNumber = mongoObjectFinal.n == null ? 0 : mongoObjectFinal.n;
|
||||
this.data = new Binary();
|
||||
|
||||
if (typeof mongoObjectFinal.data === 'string') {
|
||||
var buffer = new Buffer(mongoObjectFinal.data.length);
|
||||
buffer.write(mongoObjectFinal.data, 0, mongoObjectFinal.data.length, 'binary');
|
||||
this.data = new Binary(buffer);
|
||||
} else if (Array.isArray(mongoObjectFinal.data)) {
|
||||
buffer = new Buffer(mongoObjectFinal.data.length);
|
||||
var data = mongoObjectFinal.data.join('');
|
||||
buffer.write(data, 0, data.length, 'binary');
|
||||
this.data = new Binary(buffer);
|
||||
} else if (mongoObjectFinal.data && mongoObjectFinal.data._bsontype === 'Binary') {
|
||||
this.data = mongoObjectFinal.data;
|
||||
} else if (!Buffer.isBuffer(mongoObjectFinal.data) && !(mongoObjectFinal.data == null)) {
|
||||
throw Error('Illegal chunk format');
|
||||
}
|
||||
|
||||
// Update position
|
||||
this.internalPosition = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a data to this object and advance the read/write head.
|
||||
*
|
||||
* @param data {string} the data to write
|
||||
* @param callback {function(*, GridStore)} This will be called after executing
|
||||
* this method. The first parameter will contain null and the second one
|
||||
* will contain a reference to this object.
|
||||
*/
|
||||
Chunk.prototype.write = function(data, callback) {
|
||||
this.data.write(data, this.internalPosition, data.length, 'binary');
|
||||
this.internalPosition = this.data.length();
|
||||
if (callback != null) return callback(null, this);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads data and advances the read/write head.
|
||||
*
|
||||
* @param length {number} The length of data to read.
|
||||
*
|
||||
* @return {string} The data read if the given length will not exceed the end of
|
||||
* the chunk. Returns an empty String otherwise.
|
||||
*/
|
||||
Chunk.prototype.read = function(length) {
|
||||
// Default to full read if no index defined
|
||||
length = length == null || length === 0 ? this.length() : length;
|
||||
|
||||
if (this.length() - this.internalPosition + 1 >= length) {
|
||||
var data = this.data.read(this.internalPosition, length);
|
||||
this.internalPosition = this.internalPosition + length;
|
||||
return data;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
Chunk.prototype.readSlice = function(length) {
|
||||
if (this.length() - this.internalPosition >= length) {
|
||||
var data = null;
|
||||
if (this.data.buffer != null) {
|
||||
//Pure BSON
|
||||
data = this.data.buffer.slice(this.internalPosition, this.internalPosition + length);
|
||||
} else {
|
||||
//Native BSON
|
||||
data = new Buffer(length);
|
||||
length = this.data.readInto(data, this.internalPosition);
|
||||
}
|
||||
this.internalPosition = this.internalPosition + length;
|
||||
return data;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the read/write head is at the end.
|
||||
*
|
||||
* @return {boolean} Whether the read/write head has reached the end of this
|
||||
* chunk.
|
||||
*/
|
||||
Chunk.prototype.eof = function() {
|
||||
return this.internalPosition === this.length() ? true : false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads one character from the data of this chunk and advances the read/write
|
||||
* head.
|
||||
*
|
||||
* @return {string} a single character data read if the the read/write head is
|
||||
* not at the end of the chunk. Returns an empty String otherwise.
|
||||
*/
|
||||
Chunk.prototype.getc = function() {
|
||||
return this.read(1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the contents of the data in this chunk and resets the read/write head
|
||||
* to the initial position.
|
||||
*/
|
||||
Chunk.prototype.rewind = function() {
|
||||
this.internalPosition = 0;
|
||||
this.data = new Binary();
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves this chunk to the database. Also overwrites existing entries having the
|
||||
* same id as this chunk.
|
||||
*
|
||||
* @param callback {function(*, GridStore)} This will be called after executing
|
||||
* this method. The first parameter will contain null and the second one
|
||||
* will contain a reference to this object.
|
||||
*/
|
||||
Chunk.prototype.save = function(options, callback) {
|
||||
var self = this;
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
self.file.chunkCollection(function(err, collection) {
|
||||
if (err) return callback(err);
|
||||
|
||||
// Merge the options
|
||||
var writeOptions = { upsert: true };
|
||||
for (var name in options) writeOptions[name] = options[name];
|
||||
for (name in self.writeConcern) writeOptions[name] = self.writeConcern[name];
|
||||
|
||||
if (self.data.length() > 0) {
|
||||
self.buildMongoObject(function(mongoObject) {
|
||||
var options = { forceServerObjectId: true };
|
||||
for (var name in self.writeConcern) {
|
||||
options[name] = self.writeConcern[name];
|
||||
}
|
||||
|
||||
collection.replaceOne({ _id: self.objectId }, mongoObject, writeOptions, function(err) {
|
||||
callback(err, self);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
callback(null, self);
|
||||
}
|
||||
// });
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a mongoDB object representation of this chunk.
|
||||
*
|
||||
* @param callback {function(Object)} This will be called after executing this
|
||||
* method. The object will be passed to the first parameter and will have
|
||||
* the structure:
|
||||
*
|
||||
* <pre><code>
|
||||
* {
|
||||
* '_id' : , // {number} id for this chunk
|
||||
* 'files_id' : , // {number} foreign key to the file collection
|
||||
* 'n' : , // {number} chunk number
|
||||
* 'data' : , // {bson#Binary} the chunk data itself
|
||||
* }
|
||||
* </code></pre>
|
||||
*
|
||||
* @see <a href="http://www.mongodb.org/display/DOCS/GridFS+Specification#GridFSSpecification-{{chunks}}">MongoDB GridFS Chunk Object Structure</a>
|
||||
*/
|
||||
Chunk.prototype.buildMongoObject = function(callback) {
|
||||
var mongoObject = {
|
||||
files_id: this.file.fileId,
|
||||
n: this.chunkNumber,
|
||||
data: this.data
|
||||
};
|
||||
// If we are saving using a specific ObjectId
|
||||
if (this.objectId != null) mongoObject._id = this.objectId;
|
||||
|
||||
callback(mongoObject);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {number} the length of the data
|
||||
*/
|
||||
Chunk.prototype.length = function() {
|
||||
return this.data.length();
|
||||
};
|
||||
|
||||
/**
|
||||
* The position of the read/write head
|
||||
* @name position
|
||||
* @lends Chunk#
|
||||
* @field
|
||||
*/
|
||||
Object.defineProperty(Chunk.prototype, 'position', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.internalPosition;
|
||||
},
|
||||
set: function(value) {
|
||||
this.internalPosition = value;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The default chunk size
|
||||
* @constant
|
||||
*/
|
||||
Chunk.DEFAULT_CHUNK_SIZE = 1024 * 255;
|
||||
|
||||
module.exports = Chunk;
|
1902
ProjectNow/NodeServer/node_modules/mongodb/lib/gridfs/grid_store.js
generated
vendored
Normal file
1902
ProjectNow/NodeServer/node_modules/mongodb/lib/gridfs/grid_store.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1051
ProjectNow/NodeServer/node_modules/mongodb/lib/mongo_client.js
generated
vendored
Normal file
1051
ProjectNow/NodeServer/node_modules/mongodb/lib/mongo_client.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
452
ProjectNow/NodeServer/node_modules/mongodb/lib/topologies/mongos.js
generated
vendored
Normal file
452
ProjectNow/NodeServer/node_modules/mongodb/lib/topologies/mongos.js
generated
vendored
Normal file
@@ -0,0 +1,452 @@
|
||||
'use strict';
|
||||
|
||||
const TopologyBase = require('./topology_base').TopologyBase;
|
||||
const MongoError = require('mongodb-core').MongoError;
|
||||
const CMongos = require('mongodb-core').Mongos;
|
||||
const Cursor = require('../cursor');
|
||||
const Server = require('./server');
|
||||
const Store = require('./topology_base').Store;
|
||||
const MAX_JS_INT = require('../utils').MAX_JS_INT;
|
||||
const translateOptions = require('../utils').translateOptions;
|
||||
const filterOptions = require('../utils').filterOptions;
|
||||
const mergeOptions = require('../utils').mergeOptions;
|
||||
|
||||
/**
|
||||
* @fileOverview The **Mongos** class is a class that represents a Mongos Proxy topology and is
|
||||
* used to construct connections.
|
||||
*
|
||||
* **Mongos Should not be used, use MongoClient.connect**
|
||||
*/
|
||||
|
||||
// Allowed parameters
|
||||
var legalOptionNames = [
|
||||
'ha',
|
||||
'haInterval',
|
||||
'acceptableLatencyMS',
|
||||
'poolSize',
|
||||
'ssl',
|
||||
'checkServerIdentity',
|
||||
'sslValidate',
|
||||
'sslCA',
|
||||
'sslCRL',
|
||||
'sslCert',
|
||||
'ciphers',
|
||||
'ecdhCurve',
|
||||
'sslKey',
|
||||
'sslPass',
|
||||
'socketOptions',
|
||||
'bufferMaxEntries',
|
||||
'store',
|
||||
'auto_reconnect',
|
||||
'autoReconnect',
|
||||
'emitError',
|
||||
'keepAlive',
|
||||
'keepAliveInitialDelay',
|
||||
'noDelay',
|
||||
'connectTimeoutMS',
|
||||
'socketTimeoutMS',
|
||||
'loggerLevel',
|
||||
'logger',
|
||||
'reconnectTries',
|
||||
'appname',
|
||||
'domainsEnabled',
|
||||
'servername',
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'promiseLibrary',
|
||||
'monitorCommands'
|
||||
];
|
||||
|
||||
/**
|
||||
* Creates a new Mongos instance
|
||||
* @class
|
||||
* @deprecated
|
||||
* @param {Server[]} servers A seedlist of servers participating in the replicaset.
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {booelan} [options.ha=true] Turn on high availability monitoring.
|
||||
* @param {number} [options.haInterval=5000] Time between each replicaset status check.
|
||||
* @param {number} [options.poolSize=5] Number of connections in the connection pool for each server instance, set to 5 as default for legacy reasons.
|
||||
* @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for MongoS proxy selection
|
||||
* @param {boolean} [options.ssl=false] Use ssl connection (needs to have a mongod server with ssl support)
|
||||
* @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 {object} [options.sslValidate=true] Validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {array} [options.sslCA=null] Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {array} [options.sslCRL=null] Array of revocation certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {string} [options.ciphers=null] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
|
||||
* @param {string} [options.ecdhCurve=null] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
|
||||
* @param {(Buffer|string)} [options.sslCert=null] String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {(Buffer|string)} [options.sslKey=null] String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {(Buffer|string)} [options.sslPass=null] String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {string} [options.servername=null] String containing the server name requested via TLS SNI.
|
||||
* @param {object} [options.socketOptions=null] 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.connectTimeoutMS=0] TCP Connection timeout setting
|
||||
* @param {number} [options.socketOptions.socketTimeoutMS=0] TCP Socket timeout setting
|
||||
* @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
|
||||
* @fires Mongos#ha
|
||||
* @fires Mongos#joined
|
||||
* @fires Mongos#left
|
||||
* @fires Mongos#fullsetup
|
||||
* @fires Mongos#open
|
||||
* @fires Mongos#close
|
||||
* @fires Mongos#error
|
||||
* @fires Mongos#timeout
|
||||
* @fires Mongos#parseError
|
||||
* @fires Mongos#commandStarted
|
||||
* @fires Mongos#commandSucceeded
|
||||
* @fires Mongos#commandFailed
|
||||
* @property {string} parserType the parser type used (c++ or js).
|
||||
* @return {Mongos} a Mongos instance.
|
||||
*/
|
||||
class Mongos extends TopologyBase {
|
||||
constructor(servers, options) {
|
||||
super();
|
||||
|
||||
options = options || {};
|
||||
var self = this;
|
||||
|
||||
// Filter the options
|
||||
options = filterOptions(options, legalOptionNames);
|
||||
|
||||
// Ensure all the instances are Server
|
||||
for (var i = 0; i < servers.length; i++) {
|
||||
if (!(servers[i] instanceof Server)) {
|
||||
throw MongoError.create({
|
||||
message: 'all seed list instances must be of the Server type',
|
||||
driver: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Stored options
|
||||
var storeOptions = {
|
||||
force: false,
|
||||
bufferMaxEntries:
|
||||
typeof options.bufferMaxEntries === 'number' ? options.bufferMaxEntries : MAX_JS_INT
|
||||
};
|
||||
|
||||
// Shared global store
|
||||
var store = options.store || new Store(self, storeOptions);
|
||||
|
||||
// Build seed list
|
||||
var seedlist = servers.map(function(x) {
|
||||
return { host: x.host, port: x.port };
|
||||
});
|
||||
|
||||
// Get the reconnect option
|
||||
var reconnect = typeof options.auto_reconnect === 'boolean' ? options.auto_reconnect : true;
|
||||
reconnect = typeof options.autoReconnect === 'boolean' ? options.autoReconnect : reconnect;
|
||||
|
||||
// Clone options
|
||||
var clonedOptions = mergeOptions(
|
||||
{},
|
||||
{
|
||||
disconnectHandler: store,
|
||||
cursorFactory: Cursor,
|
||||
reconnect: reconnect,
|
||||
emitError: typeof options.emitError === 'boolean' ? options.emitError : true,
|
||||
size: typeof options.poolSize === 'number' ? options.poolSize : 5,
|
||||
monitorCommands:
|
||||
typeof options.monitorCommands === 'boolean' ? options.monitorCommands : false
|
||||
}
|
||||
);
|
||||
|
||||
// Translate any SSL options and other connectivity options
|
||||
clonedOptions = translateOptions(clonedOptions, options);
|
||||
|
||||
// Socket options
|
||||
var socketOptions =
|
||||
options.socketOptions && Object.keys(options.socketOptions).length > 0
|
||||
? options.socketOptions
|
||||
: options;
|
||||
|
||||
// Translate all the options to the mongodb-core ones
|
||||
clonedOptions = translateOptions(clonedOptions, socketOptions);
|
||||
|
||||
// Build default client information
|
||||
clonedOptions.clientInfo = this.clientInfo;
|
||||
// Do we have an application specific string
|
||||
if (options.appname) {
|
||||
clonedOptions.clientInfo.application = { name: options.appname };
|
||||
}
|
||||
|
||||
// Internal state
|
||||
this.s = {
|
||||
// Create the Mongos
|
||||
coreTopology: new CMongos(seedlist, clonedOptions),
|
||||
// Server capabilities
|
||||
sCapabilities: null,
|
||||
// Debug turned on
|
||||
debug: clonedOptions.debug,
|
||||
// Store option defaults
|
||||
storeOptions: storeOptions,
|
||||
// Cloned options
|
||||
clonedOptions: clonedOptions,
|
||||
// Actual store of callbacks
|
||||
store: store,
|
||||
// Options
|
||||
options: options,
|
||||
// Server Session Pool
|
||||
sessionPool: null,
|
||||
// Active client sessions
|
||||
sessions: [],
|
||||
// Promise library
|
||||
promiseLibrary: options.promiseLibrary || Promise
|
||||
};
|
||||
}
|
||||
|
||||
// Connect
|
||||
connect(_options, callback) {
|
||||
var self = this;
|
||||
if ('function' === typeof _options) (callback = _options), (_options = {});
|
||||
if (_options == null) _options = {};
|
||||
if (!('function' === typeof callback)) callback = null;
|
||||
_options = Object.assign({}, this.s.clonedOptions, _options);
|
||||
self.s.options = _options;
|
||||
|
||||
// Update bufferMaxEntries
|
||||
self.s.storeOptions.bufferMaxEntries =
|
||||
typeof _options.bufferMaxEntries === 'number' ? _options.bufferMaxEntries : -1;
|
||||
|
||||
// Error handler
|
||||
var connectErrorHandler = function() {
|
||||
return function(err) {
|
||||
// Remove all event handlers
|
||||
var events = ['timeout', 'error', 'close'];
|
||||
events.forEach(function(e) {
|
||||
self.removeListener(e, connectErrorHandler);
|
||||
});
|
||||
|
||||
self.s.coreTopology.removeListener('connect', connectErrorHandler);
|
||||
// Force close the topology
|
||||
self.close(true);
|
||||
|
||||
// Try to callback
|
||||
try {
|
||||
callback(err);
|
||||
} catch (err) {
|
||||
process.nextTick(function() {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Actual handler
|
||||
var errorHandler = function(event) {
|
||||
return function(err) {
|
||||
if (event !== 'error') {
|
||||
self.emit(event, err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Error handler
|
||||
var reconnectHandler = function() {
|
||||
self.emit('reconnect');
|
||||
self.s.store.execute();
|
||||
};
|
||||
|
||||
// relay the event
|
||||
var relay = function(event) {
|
||||
return function(t, server) {
|
||||
self.emit(event, t, server);
|
||||
};
|
||||
};
|
||||
|
||||
// Connect handler
|
||||
var connectHandler = function() {
|
||||
// Clear out all the current handlers left over
|
||||
var events = ['timeout', 'error', 'close', 'fullsetup'];
|
||||
events.forEach(function(e) {
|
||||
self.s.coreTopology.removeAllListeners(e);
|
||||
});
|
||||
|
||||
// Set up listeners
|
||||
self.s.coreTopology.once('timeout', errorHandler('timeout'));
|
||||
self.s.coreTopology.once('error', errorHandler('error'));
|
||||
self.s.coreTopology.once('close', errorHandler('close'));
|
||||
|
||||
// Set up serverConfig listeners
|
||||
self.s.coreTopology.on('fullsetup', function() {
|
||||
self.emit('fullsetup', self);
|
||||
});
|
||||
|
||||
// Emit open event
|
||||
self.emit('open', null, self);
|
||||
|
||||
// Return correctly
|
||||
try {
|
||||
callback(null, self);
|
||||
} catch (err) {
|
||||
process.nextTick(function() {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Clear out all the current handlers left over
|
||||
var events = [
|
||||
'timeout',
|
||||
'error',
|
||||
'close',
|
||||
'serverOpening',
|
||||
'serverDescriptionChanged',
|
||||
'serverHeartbeatStarted',
|
||||
'serverHeartbeatSucceeded',
|
||||
'serverHeartbeatFailed',
|
||||
'serverClosed',
|
||||
'topologyOpening',
|
||||
'topologyClosed',
|
||||
'topologyDescriptionChanged',
|
||||
'commandStarted',
|
||||
'commandSucceeded',
|
||||
'commandFailed'
|
||||
];
|
||||
events.forEach(function(e) {
|
||||
self.s.coreTopology.removeAllListeners(e);
|
||||
});
|
||||
|
||||
// Set up SDAM listeners
|
||||
self.s.coreTopology.on('serverDescriptionChanged', relay('serverDescriptionChanged'));
|
||||
self.s.coreTopology.on('serverHeartbeatStarted', relay('serverHeartbeatStarted'));
|
||||
self.s.coreTopology.on('serverHeartbeatSucceeded', relay('serverHeartbeatSucceeded'));
|
||||
self.s.coreTopology.on('serverHeartbeatFailed', relay('serverHeartbeatFailed'));
|
||||
self.s.coreTopology.on('serverOpening', relay('serverOpening'));
|
||||
self.s.coreTopology.on('serverClosed', relay('serverClosed'));
|
||||
self.s.coreTopology.on('topologyOpening', relay('topologyOpening'));
|
||||
self.s.coreTopology.on('topologyClosed', relay('topologyClosed'));
|
||||
self.s.coreTopology.on('topologyDescriptionChanged', relay('topologyDescriptionChanged'));
|
||||
self.s.coreTopology.on('commandStarted', relay('commandStarted'));
|
||||
self.s.coreTopology.on('commandSucceeded', relay('commandSucceeded'));
|
||||
self.s.coreTopology.on('commandFailed', relay('commandFailed'));
|
||||
|
||||
// Set up listeners
|
||||
self.s.coreTopology.once('timeout', connectErrorHandler('timeout'));
|
||||
self.s.coreTopology.once('error', connectErrorHandler('error'));
|
||||
self.s.coreTopology.once('close', connectErrorHandler('close'));
|
||||
self.s.coreTopology.once('connect', connectHandler);
|
||||
// Join and leave events
|
||||
self.s.coreTopology.on('joined', relay('joined'));
|
||||
self.s.coreTopology.on('left', relay('left'));
|
||||
|
||||
// Reconnect server
|
||||
self.s.coreTopology.on('reconnect', reconnectHandler);
|
||||
|
||||
// Start connection
|
||||
self.s.coreTopology.connect(_options);
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(Mongos.prototype, 'haInterval', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.coreTopology.s.haInterval;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* A mongos connect event, used to verify that the connection is up and running
|
||||
*
|
||||
* @event Mongos#connect
|
||||
* @type {Mongos}
|
||||
*/
|
||||
|
||||
/**
|
||||
* The mongos high availability event
|
||||
*
|
||||
* @event Mongos#ha
|
||||
* @type {function}
|
||||
* @param {string} type The stage in the high availability event (start|end)
|
||||
* @param {boolean} data.norepeat This is a repeating high availability process or a single execution only
|
||||
* @param {number} data.id The id for this high availability request
|
||||
* @param {object} data.state An object containing the information about the current replicaset
|
||||
*/
|
||||
|
||||
/**
|
||||
* A server member left the mongos set
|
||||
*
|
||||
* @event Mongos#left
|
||||
* @type {function}
|
||||
* @param {string} type The type of member that left (primary|secondary|arbiter)
|
||||
* @param {Server} server The server object that left
|
||||
*/
|
||||
|
||||
/**
|
||||
* A server member joined the mongos set
|
||||
*
|
||||
* @event Mongos#joined
|
||||
* @type {function}
|
||||
* @param {string} type The type of member that joined (primary|secondary|arbiter)
|
||||
* @param {Server} server The server object that joined
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mongos fullsetup event, emitted when all proxies in the topology have been connected to.
|
||||
*
|
||||
* @event Mongos#fullsetup
|
||||
* @type {Mongos}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mongos open event, emitted when mongos can start processing commands.
|
||||
*
|
||||
* @event Mongos#open
|
||||
* @type {Mongos}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mongos close event
|
||||
*
|
||||
* @event Mongos#close
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mongos error event, emitted if there is an error listener.
|
||||
*
|
||||
* @event Mongos#error
|
||||
* @type {MongoError}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mongos timeout event
|
||||
*
|
||||
* @event Mongos#timeout
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mongos parseError event
|
||||
*
|
||||
* @event Mongos#parseError
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An event emitted indicating a command was started, if command monitoring is enabled
|
||||
*
|
||||
* @event Mongos#commandStarted
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An event emitted indicating a command succeeded, if command monitoring is enabled
|
||||
*
|
||||
* @event Mongos#commandSucceeded
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An event emitted indicating a command failed, if command monitoring is enabled
|
||||
*
|
||||
* @event Mongos#commandFailed
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
module.exports = Mongos;
|
497
ProjectNow/NodeServer/node_modules/mongodb/lib/topologies/replset.js
generated
vendored
Normal file
497
ProjectNow/NodeServer/node_modules/mongodb/lib/topologies/replset.js
generated
vendored
Normal file
@@ -0,0 +1,497 @@
|
||||
'use strict';
|
||||
|
||||
const Server = require('./server');
|
||||
const Cursor = require('../cursor');
|
||||
const MongoError = require('mongodb-core').MongoError;
|
||||
const TopologyBase = require('./topology_base').TopologyBase;
|
||||
const Store = require('./topology_base').Store;
|
||||
const CReplSet = require('mongodb-core').ReplSet;
|
||||
const MAX_JS_INT = require('../utils').MAX_JS_INT;
|
||||
const translateOptions = require('../utils').translateOptions;
|
||||
const filterOptions = require('../utils').filterOptions;
|
||||
const mergeOptions = require('../utils').mergeOptions;
|
||||
|
||||
/**
|
||||
* @fileOverview The **ReplSet** class is a class that represents a Replicaset topology and is
|
||||
* used to construct connections.
|
||||
*
|
||||
* **ReplSet Should not be used, use MongoClient.connect**
|
||||
*/
|
||||
|
||||
// Allowed parameters
|
||||
var legalOptionNames = [
|
||||
'ha',
|
||||
'haInterval',
|
||||
'replicaSet',
|
||||
'rs_name',
|
||||
'secondaryAcceptableLatencyMS',
|
||||
'connectWithNoPrimary',
|
||||
'poolSize',
|
||||
'ssl',
|
||||
'checkServerIdentity',
|
||||
'sslValidate',
|
||||
'sslCA',
|
||||
'sslCert',
|
||||
'ciphers',
|
||||
'ecdhCurve',
|
||||
'sslCRL',
|
||||
'sslKey',
|
||||
'sslPass',
|
||||
'socketOptions',
|
||||
'bufferMaxEntries',
|
||||
'store',
|
||||
'auto_reconnect',
|
||||
'autoReconnect',
|
||||
'emitError',
|
||||
'keepAlive',
|
||||
'keepAliveInitialDelay',
|
||||
'noDelay',
|
||||
'connectTimeoutMS',
|
||||
'socketTimeoutMS',
|
||||
'strategy',
|
||||
'debug',
|
||||
'family',
|
||||
'loggerLevel',
|
||||
'logger',
|
||||
'reconnectTries',
|
||||
'appname',
|
||||
'domainsEnabled',
|
||||
'servername',
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'maxStalenessSeconds',
|
||||
'promiseLibrary',
|
||||
'minSize',
|
||||
'monitorCommands'
|
||||
];
|
||||
|
||||
/**
|
||||
* Creates a new ReplSet instance
|
||||
* @class
|
||||
* @deprecated
|
||||
* @param {Server[]} servers A seedlist of servers participating in the replicaset.
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {boolean} [options.ha=true] Turn on high availability monitoring.
|
||||
* @param {number} [options.haInterval=10000] Time between each replicaset status check.
|
||||
* @param {string} [options.replicaSet] The name of the replicaset to connect to.
|
||||
* @param {number} [options.secondaryAcceptableLatencyMS=15] Sets the range of servers to pick when using NEAREST (lowest ping ms + the latency fence, ex: range of 1 to (1 + 15) ms)
|
||||
* @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
|
||||
* @param {number} [options.poolSize=5] Number of connections in the connection pool for each server instance, set to 5 as default for legacy reasons.
|
||||
* @param {boolean} [options.ssl=false] Use ssl connection (needs to have a mongod server with ssl support)
|
||||
* @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 {object} [options.sslValidate=true] Validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {array} [options.sslCA=null] Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {array} [options.sslCRL=null] Array of revocation certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {(Buffer|string)} [options.sslCert=null] String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher.
|
||||
* @param {string} [options.ciphers=null] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
|
||||
* @param {string} [options.ecdhCurve=null] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
|
||||
* @param {(Buffer|string)} [options.sslKey=null] String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {(Buffer|string)} [options.sslPass=null] String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {string} [options.servername=null] String containing the server name requested via TLS SNI.
|
||||
* @param {object} [options.socketOptions=null] 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.connectTimeoutMS=10000] TCP Connection timeout setting
|
||||
* @param {number} [options.socketOptions.socketTimeoutMS=0] TCP Socket timeout setting
|
||||
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
|
||||
* @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed);
|
||||
* @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
|
||||
* @fires ReplSet#connect
|
||||
* @fires ReplSet#ha
|
||||
* @fires ReplSet#joined
|
||||
* @fires ReplSet#left
|
||||
* @fires ReplSet#fullsetup
|
||||
* @fires ReplSet#open
|
||||
* @fires ReplSet#close
|
||||
* @fires ReplSet#error
|
||||
* @fires ReplSet#timeout
|
||||
* @fires ReplSet#parseError
|
||||
* @fires ReplSet#commandStarted
|
||||
* @fires ReplSet#commandSucceeded
|
||||
* @fires ReplSet#commandFailed
|
||||
* @property {string} parserType the parser type used (c++ or js).
|
||||
* @return {ReplSet} a ReplSet instance.
|
||||
*/
|
||||
class ReplSet extends TopologyBase {
|
||||
constructor(servers, options) {
|
||||
super();
|
||||
|
||||
options = options || {};
|
||||
var self = this;
|
||||
|
||||
// Filter the options
|
||||
options = filterOptions(options, legalOptionNames);
|
||||
|
||||
// Ensure all the instances are Server
|
||||
for (var i = 0; i < servers.length; i++) {
|
||||
if (!(servers[i] instanceof Server)) {
|
||||
throw MongoError.create({
|
||||
message: 'all seed list instances must be of the Server type',
|
||||
driver: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Stored options
|
||||
var storeOptions = {
|
||||
force: false,
|
||||
bufferMaxEntries:
|
||||
typeof options.bufferMaxEntries === 'number' ? options.bufferMaxEntries : MAX_JS_INT
|
||||
};
|
||||
|
||||
// Shared global store
|
||||
var store = options.store || new Store(self, storeOptions);
|
||||
|
||||
// Build seed list
|
||||
var seedlist = servers.map(function(x) {
|
||||
return { host: x.host, port: x.port };
|
||||
});
|
||||
|
||||
// Clone options
|
||||
var clonedOptions = mergeOptions(
|
||||
{},
|
||||
{
|
||||
disconnectHandler: store,
|
||||
cursorFactory: Cursor,
|
||||
reconnect: false,
|
||||
emitError: typeof options.emitError === 'boolean' ? options.emitError : true,
|
||||
size: typeof options.poolSize === 'number' ? options.poolSize : 5,
|
||||
monitorCommands:
|
||||
typeof options.monitorCommands === 'boolean' ? options.monitorCommands : false
|
||||
}
|
||||
);
|
||||
|
||||
// Translate any SSL options and other connectivity options
|
||||
clonedOptions = translateOptions(clonedOptions, options);
|
||||
|
||||
// Socket options
|
||||
var socketOptions =
|
||||
options.socketOptions && Object.keys(options.socketOptions).length > 0
|
||||
? options.socketOptions
|
||||
: options;
|
||||
|
||||
// Translate all the options to the mongodb-core ones
|
||||
clonedOptions = translateOptions(clonedOptions, socketOptions);
|
||||
|
||||
// Build default client information
|
||||
clonedOptions.clientInfo = this.clientInfo;
|
||||
// Do we have an application specific string
|
||||
if (options.appname) {
|
||||
clonedOptions.clientInfo.application = { name: options.appname };
|
||||
}
|
||||
|
||||
// Create the ReplSet
|
||||
var coreTopology = new CReplSet(seedlist, clonedOptions);
|
||||
|
||||
// Listen to reconnect event
|
||||
coreTopology.on('reconnect', function() {
|
||||
self.emit('reconnect');
|
||||
store.execute();
|
||||
});
|
||||
|
||||
// Internal state
|
||||
this.s = {
|
||||
// Replicaset
|
||||
coreTopology: coreTopology,
|
||||
// Server capabilities
|
||||
sCapabilities: null,
|
||||
// Debug tag
|
||||
tag: options.tag,
|
||||
// Store options
|
||||
storeOptions: storeOptions,
|
||||
// Cloned options
|
||||
clonedOptions: clonedOptions,
|
||||
// Store
|
||||
store: store,
|
||||
// Options
|
||||
options: options,
|
||||
// Server Session Pool
|
||||
sessionPool: null,
|
||||
// Active client sessions
|
||||
sessions: [],
|
||||
// Promise library
|
||||
promiseLibrary: options.promiseLibrary || Promise
|
||||
};
|
||||
|
||||
// Debug
|
||||
if (clonedOptions.debug) {
|
||||
// Last ismaster
|
||||
Object.defineProperty(this, 'replset', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return coreTopology;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Connect method
|
||||
connect(_options, callback) {
|
||||
var self = this;
|
||||
if ('function' === typeof _options) (callback = _options), (_options = {});
|
||||
if (_options == null) _options = {};
|
||||
if (!('function' === typeof callback)) callback = null;
|
||||
_options = Object.assign({}, this.s.clonedOptions, _options);
|
||||
self.s.options = _options;
|
||||
|
||||
// Update bufferMaxEntries
|
||||
self.s.storeOptions.bufferMaxEntries =
|
||||
typeof _options.bufferMaxEntries === 'number' ? _options.bufferMaxEntries : -1;
|
||||
|
||||
// Actual handler
|
||||
var errorHandler = function(event) {
|
||||
return function(err) {
|
||||
if (event !== 'error') {
|
||||
self.emit(event, err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Clear out all the current handlers left over
|
||||
var events = [
|
||||
'timeout',
|
||||
'error',
|
||||
'close',
|
||||
'serverOpening',
|
||||
'serverDescriptionChanged',
|
||||
'serverHeartbeatStarted',
|
||||
'serverHeartbeatSucceeded',
|
||||
'serverHeartbeatFailed',
|
||||
'serverClosed',
|
||||
'topologyOpening',
|
||||
'topologyClosed',
|
||||
'topologyDescriptionChanged',
|
||||
'commandStarted',
|
||||
'commandSucceeded',
|
||||
'commandFailed',
|
||||
'joined',
|
||||
'left',
|
||||
'ping',
|
||||
'ha'
|
||||
];
|
||||
events.forEach(function(e) {
|
||||
self.s.coreTopology.removeAllListeners(e);
|
||||
});
|
||||
|
||||
// relay the event
|
||||
var relay = function(event) {
|
||||
return function(t, server) {
|
||||
self.emit(event, t, server);
|
||||
};
|
||||
};
|
||||
|
||||
// Replset events relay
|
||||
var replsetRelay = function(event) {
|
||||
return function(t, server) {
|
||||
self.emit(event, t, server.lastIsMaster(), server);
|
||||
};
|
||||
};
|
||||
|
||||
// Relay ha
|
||||
var relayHa = function(t, state) {
|
||||
self.emit('ha', t, state);
|
||||
|
||||
if (t === 'start') {
|
||||
self.emit('ha_connect', t, state);
|
||||
} else if (t === 'end') {
|
||||
self.emit('ha_ismaster', t, state);
|
||||
}
|
||||
};
|
||||
|
||||
// Set up serverConfig listeners
|
||||
self.s.coreTopology.on('joined', replsetRelay('joined'));
|
||||
self.s.coreTopology.on('left', relay('left'));
|
||||
self.s.coreTopology.on('ping', relay('ping'));
|
||||
self.s.coreTopology.on('ha', relayHa);
|
||||
|
||||
// Set up SDAM listeners
|
||||
self.s.coreTopology.on('serverDescriptionChanged', relay('serverDescriptionChanged'));
|
||||
self.s.coreTopology.on('serverHeartbeatStarted', relay('serverHeartbeatStarted'));
|
||||
self.s.coreTopology.on('serverHeartbeatSucceeded', relay('serverHeartbeatSucceeded'));
|
||||
self.s.coreTopology.on('serverHeartbeatFailed', relay('serverHeartbeatFailed'));
|
||||
self.s.coreTopology.on('serverOpening', relay('serverOpening'));
|
||||
self.s.coreTopology.on('serverClosed', relay('serverClosed'));
|
||||
self.s.coreTopology.on('topologyOpening', relay('topologyOpening'));
|
||||
self.s.coreTopology.on('topologyClosed', relay('topologyClosed'));
|
||||
self.s.coreTopology.on('topologyDescriptionChanged', relay('topologyDescriptionChanged'));
|
||||
self.s.coreTopology.on('commandStarted', relay('commandStarted'));
|
||||
self.s.coreTopology.on('commandSucceeded', relay('commandSucceeded'));
|
||||
self.s.coreTopology.on('commandFailed', relay('commandFailed'));
|
||||
|
||||
self.s.coreTopology.on('fullsetup', function() {
|
||||
self.emit('fullsetup', self, self);
|
||||
});
|
||||
|
||||
self.s.coreTopology.on('all', function() {
|
||||
self.emit('all', null, self);
|
||||
});
|
||||
|
||||
// Connect handler
|
||||
var connectHandler = function() {
|
||||
// Set up listeners
|
||||
self.s.coreTopology.once('timeout', errorHandler('timeout'));
|
||||
self.s.coreTopology.once('error', errorHandler('error'));
|
||||
self.s.coreTopology.once('close', errorHandler('close'));
|
||||
|
||||
// Emit open event
|
||||
self.emit('open', null, self);
|
||||
|
||||
// Return correctly
|
||||
try {
|
||||
callback(null, self);
|
||||
} catch (err) {
|
||||
process.nextTick(function() {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Error handler
|
||||
var connectErrorHandler = function() {
|
||||
return function(err) {
|
||||
['timeout', 'error', 'close'].forEach(function(e) {
|
||||
self.s.coreTopology.removeListener(e, connectErrorHandler);
|
||||
});
|
||||
|
||||
self.s.coreTopology.removeListener('connect', connectErrorHandler);
|
||||
// Destroy the replset
|
||||
self.s.coreTopology.destroy();
|
||||
|
||||
// Try to callback
|
||||
try {
|
||||
callback(err);
|
||||
} catch (err) {
|
||||
if (!self.s.coreTopology.isConnected())
|
||||
process.nextTick(function() {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Set up listeners
|
||||
self.s.coreTopology.once('timeout', connectErrorHandler('timeout'));
|
||||
self.s.coreTopology.once('error', connectErrorHandler('error'));
|
||||
self.s.coreTopology.once('close', connectErrorHandler('close'));
|
||||
self.s.coreTopology.once('connect', connectHandler);
|
||||
|
||||
// Start connection
|
||||
self.s.coreTopology.connect(_options);
|
||||
}
|
||||
|
||||
close(forceClosed) {
|
||||
super.close(forceClosed);
|
||||
|
||||
['timeout', 'error', 'close', 'joined', 'left'].forEach(e => this.removeAllListeners(e));
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(ReplSet.prototype, 'haInterval', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.coreTopology.s.haInterval;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* A replset connect event, used to verify that the connection is up and running
|
||||
*
|
||||
* @event ReplSet#connect
|
||||
* @type {ReplSet}
|
||||
*/
|
||||
|
||||
/**
|
||||
* The replset high availability event
|
||||
*
|
||||
* @event ReplSet#ha
|
||||
* @type {function}
|
||||
* @param {string} type The stage in the high availability event (start|end)
|
||||
* @param {boolean} data.norepeat This is a repeating high availability process or a single execution only
|
||||
* @param {number} data.id The id for this high availability request
|
||||
* @param {object} data.state An object containing the information about the current replicaset
|
||||
*/
|
||||
|
||||
/**
|
||||
* A server member left the replicaset
|
||||
*
|
||||
* @event ReplSet#left
|
||||
* @type {function}
|
||||
* @param {string} type The type of member that left (primary|secondary|arbiter)
|
||||
* @param {Server} server The server object that left
|
||||
*/
|
||||
|
||||
/**
|
||||
* A server member joined the replicaset
|
||||
*
|
||||
* @event ReplSet#joined
|
||||
* @type {function}
|
||||
* @param {string} type The type of member that joined (primary|secondary|arbiter)
|
||||
* @param {Server} server The server object that joined
|
||||
*/
|
||||
|
||||
/**
|
||||
* ReplSet open event, emitted when replicaset can start processing commands.
|
||||
*
|
||||
* @event ReplSet#open
|
||||
* @type {Replset}
|
||||
*/
|
||||
|
||||
/**
|
||||
* ReplSet fullsetup event, emitted when all servers in the topology have been connected to.
|
||||
*
|
||||
* @event ReplSet#fullsetup
|
||||
* @type {Replset}
|
||||
*/
|
||||
|
||||
/**
|
||||
* ReplSet close event
|
||||
*
|
||||
* @event ReplSet#close
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* ReplSet error event, emitted if there is an error listener.
|
||||
*
|
||||
* @event ReplSet#error
|
||||
* @type {MongoError}
|
||||
*/
|
||||
|
||||
/**
|
||||
* ReplSet timeout event
|
||||
*
|
||||
* @event ReplSet#timeout
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* ReplSet parseError event
|
||||
*
|
||||
* @event ReplSet#parseError
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An event emitted indicating a command was started, if command monitoring is enabled
|
||||
*
|
||||
* @event ReplSet#commandStarted
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An event emitted indicating a command succeeded, if command monitoring is enabled
|
||||
*
|
||||
* @event ReplSet#commandSucceeded
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An event emitted indicating a command failed, if command monitoring is enabled
|
||||
*
|
||||
* @event ReplSet#commandFailed
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
module.exports = ReplSet;
|
456
ProjectNow/NodeServer/node_modules/mongodb/lib/topologies/server.js
generated
vendored
Normal file
456
ProjectNow/NodeServer/node_modules/mongodb/lib/topologies/server.js
generated
vendored
Normal file
@@ -0,0 +1,456 @@
|
||||
'use strict';
|
||||
|
||||
const CServer = require('mongodb-core').Server;
|
||||
const Cursor = require('../cursor');
|
||||
const TopologyBase = require('./topology_base').TopologyBase;
|
||||
const Store = require('./topology_base').Store;
|
||||
const MongoError = require('mongodb-core').MongoError;
|
||||
const MAX_JS_INT = require('../utils').MAX_JS_INT;
|
||||
const translateOptions = require('../utils').translateOptions;
|
||||
const filterOptions = require('../utils').filterOptions;
|
||||
const mergeOptions = require('../utils').mergeOptions;
|
||||
|
||||
/**
|
||||
* @fileOverview The **Server** class is a class that represents a single server topology and is
|
||||
* used to construct connections.
|
||||
*
|
||||
* **Server Should not be used, use MongoClient.connect**
|
||||
*/
|
||||
|
||||
// Allowed parameters
|
||||
var legalOptionNames = [
|
||||
'ha',
|
||||
'haInterval',
|
||||
'acceptableLatencyMS',
|
||||
'poolSize',
|
||||
'ssl',
|
||||
'checkServerIdentity',
|
||||
'sslValidate',
|
||||
'sslCA',
|
||||
'sslCRL',
|
||||
'sslCert',
|
||||
'ciphers',
|
||||
'ecdhCurve',
|
||||
'sslKey',
|
||||
'sslPass',
|
||||
'socketOptions',
|
||||
'bufferMaxEntries',
|
||||
'store',
|
||||
'auto_reconnect',
|
||||
'autoReconnect',
|
||||
'emitError',
|
||||
'keepAlive',
|
||||
'keepAliveInitialDelay',
|
||||
'noDelay',
|
||||
'connectTimeoutMS',
|
||||
'socketTimeoutMS',
|
||||
'family',
|
||||
'loggerLevel',
|
||||
'logger',
|
||||
'reconnectTries',
|
||||
'reconnectInterval',
|
||||
'monitoring',
|
||||
'appname',
|
||||
'domainsEnabled',
|
||||
'servername',
|
||||
'promoteLongs',
|
||||
'promoteValues',
|
||||
'promoteBuffers',
|
||||
'compression',
|
||||
'promiseLibrary',
|
||||
'monitorCommands'
|
||||
];
|
||||
|
||||
/**
|
||||
* Creates a new Server instance
|
||||
* @class
|
||||
* @deprecated
|
||||
* @param {string} host The host for the server, can be either an IP4, IP6 or domain socket style host.
|
||||
* @param {number} [port] The server port if IP4.
|
||||
* @param {object} [options=null] Optional settings.
|
||||
* @param {number} [options.poolSize=5] Number of connections in the connection pool for each server instance, set to 5 as default for legacy reasons.
|
||||
* @param {boolean} [options.ssl=false] Use ssl connection (needs to have a mongod server with ssl support)
|
||||
* @param {object} [options.sslValidate=true] Validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @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 {array} [options.sslCA=null] Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {array} [options.sslCRL=null] Array of revocation certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {(Buffer|string)} [options.sslCert=null] String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {string} [options.ciphers=null] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
|
||||
* @param {string} [options.ecdhCurve=null] Passed directly through to tls.createSecureContext. See https://nodejs.org/dist/latest-v9.x/docs/api/tls.html#tls_tls_createsecurecontext_options for more info.
|
||||
* @param {(Buffer|string)} [options.sslKey=null] String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {(Buffer|string)} [options.sslPass=null] String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher)
|
||||
* @param {string} [options.servername=null] String containing the server name requested via TLS SNI.
|
||||
* @param {object} [options.socketOptions=null] Socket options
|
||||
* @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.connectTimeoutMS=0] TCP Connection timeout setting
|
||||
* @param {number} [options.socketOptions.socketTimeoutMS=0] TCP Socket timeout setting
|
||||
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
|
||||
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
|
||||
* @param {number} [options.monitoring=true] Triggers the server instance to call ismaster
|
||||
* @param {number} [options.haInterval=10000] The interval of calling ismaster when monitoring is enabled.
|
||||
* @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 Server#connect
|
||||
* @fires Server#close
|
||||
* @fires Server#error
|
||||
* @fires Server#timeout
|
||||
* @fires Server#parseError
|
||||
* @fires Server#reconnect
|
||||
* @fires Server#commandStarted
|
||||
* @fires Server#commandSucceeded
|
||||
* @fires Server#commandFailed
|
||||
* @property {string} parserType the parser type used (c++ or js).
|
||||
* @return {Server} a Server instance.
|
||||
*/
|
||||
class Server extends TopologyBase {
|
||||
constructor(host, port, options) {
|
||||
super();
|
||||
var self = this;
|
||||
|
||||
// Filter the options
|
||||
options = filterOptions(options, legalOptionNames);
|
||||
|
||||
// Promise library
|
||||
const promiseLibrary = options.promiseLibrary;
|
||||
|
||||
// Stored options
|
||||
var storeOptions = {
|
||||
force: false,
|
||||
bufferMaxEntries:
|
||||
typeof options.bufferMaxEntries === 'number' ? options.bufferMaxEntries : MAX_JS_INT
|
||||
};
|
||||
|
||||
// Shared global store
|
||||
var store = options.store || new Store(self, storeOptions);
|
||||
|
||||
// Detect if we have a socket connection
|
||||
if (host.indexOf('/') !== -1) {
|
||||
if (port != null && typeof port === 'object') {
|
||||
options = port;
|
||||
port = null;
|
||||
}
|
||||
} else if (port == null) {
|
||||
throw MongoError.create({ message: 'port must be specified', driver: true });
|
||||
}
|
||||
|
||||
// Get the reconnect option
|
||||
var reconnect = typeof options.auto_reconnect === 'boolean' ? options.auto_reconnect : true;
|
||||
reconnect = typeof options.autoReconnect === 'boolean' ? options.autoReconnect : reconnect;
|
||||
|
||||
// Clone options
|
||||
var clonedOptions = mergeOptions(
|
||||
{},
|
||||
{
|
||||
host: host,
|
||||
port: port,
|
||||
disconnectHandler: store,
|
||||
cursorFactory: Cursor,
|
||||
reconnect: reconnect,
|
||||
emitError: typeof options.emitError === 'boolean' ? options.emitError : true,
|
||||
size: typeof options.poolSize === 'number' ? options.poolSize : 5,
|
||||
monitorCommands:
|
||||
typeof options.monitorCommands === 'boolean' ? options.monitorCommands : false
|
||||
}
|
||||
);
|
||||
|
||||
// Translate any SSL options and other connectivity options
|
||||
clonedOptions = translateOptions(clonedOptions, options);
|
||||
|
||||
// Socket options
|
||||
var socketOptions =
|
||||
options.socketOptions && Object.keys(options.socketOptions).length > 0
|
||||
? options.socketOptions
|
||||
: options;
|
||||
|
||||
// Translate all the options to the mongodb-core ones
|
||||
clonedOptions = translateOptions(clonedOptions, socketOptions);
|
||||
|
||||
// Build default client information
|
||||
clonedOptions.clientInfo = this.clientInfo;
|
||||
// Do we have an application specific string
|
||||
if (options.appname) {
|
||||
clonedOptions.clientInfo.application = { name: options.appname };
|
||||
}
|
||||
|
||||
// Define the internal properties
|
||||
this.s = {
|
||||
// Create an instance of a server instance from mongodb-core
|
||||
coreTopology: new CServer(clonedOptions),
|
||||
// Server capabilities
|
||||
sCapabilities: null,
|
||||
// Cloned options
|
||||
clonedOptions: clonedOptions,
|
||||
// Reconnect
|
||||
reconnect: clonedOptions.reconnect,
|
||||
// Emit error
|
||||
emitError: clonedOptions.emitError,
|
||||
// Pool size
|
||||
poolSize: clonedOptions.size,
|
||||
// Store Options
|
||||
storeOptions: storeOptions,
|
||||
// Store
|
||||
store: store,
|
||||
// Host
|
||||
host: host,
|
||||
// Port
|
||||
port: port,
|
||||
// Options
|
||||
options: options,
|
||||
// Server Session Pool
|
||||
sessionPool: null,
|
||||
// Active client sessions
|
||||
sessions: [],
|
||||
// Promise library
|
||||
promiseLibrary: promiseLibrary || Promise
|
||||
};
|
||||
}
|
||||
|
||||
// Connect
|
||||
connect(_options, callback) {
|
||||
var self = this;
|
||||
if ('function' === typeof _options) (callback = _options), (_options = {});
|
||||
if (_options == null) _options = this.s.clonedOptions;
|
||||
if (!('function' === typeof callback)) callback = null;
|
||||
_options = Object.assign({}, this.s.clonedOptions, _options);
|
||||
self.s.options = _options;
|
||||
|
||||
// Update bufferMaxEntries
|
||||
self.s.storeOptions.bufferMaxEntries =
|
||||
typeof _options.bufferMaxEntries === 'number' ? _options.bufferMaxEntries : -1;
|
||||
|
||||
// Error handler
|
||||
var connectErrorHandler = function() {
|
||||
return function(err) {
|
||||
// Remove all event handlers
|
||||
var events = ['timeout', 'error', 'close'];
|
||||
events.forEach(function(e) {
|
||||
self.s.coreTopology.removeListener(e, connectHandlers[e]);
|
||||
});
|
||||
|
||||
self.s.coreTopology.removeListener('connect', connectErrorHandler);
|
||||
|
||||
// Try to callback
|
||||
try {
|
||||
callback(err);
|
||||
} catch (err) {
|
||||
process.nextTick(function() {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Actual handler
|
||||
var errorHandler = function(event) {
|
||||
return function(err) {
|
||||
if (event !== 'error') {
|
||||
self.emit(event, err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Error handler
|
||||
var reconnectHandler = function() {
|
||||
self.emit('reconnect', self);
|
||||
self.s.store.execute();
|
||||
};
|
||||
|
||||
// Reconnect failed
|
||||
var reconnectFailedHandler = function(err) {
|
||||
self.emit('reconnectFailed', err);
|
||||
self.s.store.flush(err);
|
||||
};
|
||||
|
||||
// Destroy called on topology, perform cleanup
|
||||
var destroyHandler = function() {
|
||||
self.s.store.flush();
|
||||
};
|
||||
|
||||
// relay the event
|
||||
var relay = function(event) {
|
||||
return function(t, server) {
|
||||
self.emit(event, t, server);
|
||||
};
|
||||
};
|
||||
|
||||
// Connect handler
|
||||
var connectHandler = function() {
|
||||
// Clear out all the current handlers left over
|
||||
['timeout', 'error', 'close', 'destroy'].forEach(function(e) {
|
||||
self.s.coreTopology.removeAllListeners(e);
|
||||
});
|
||||
|
||||
// Set up listeners
|
||||
self.s.coreTopology.on('timeout', errorHandler('timeout'));
|
||||
self.s.coreTopology.once('error', errorHandler('error'));
|
||||
self.s.coreTopology.on('close', errorHandler('close'));
|
||||
// Only called on destroy
|
||||
self.s.coreTopology.on('destroy', destroyHandler);
|
||||
|
||||
// Emit open event
|
||||
self.emit('open', null, self);
|
||||
|
||||
// Return correctly
|
||||
try {
|
||||
callback(null, self);
|
||||
} catch (err) {
|
||||
console.log(err.stack);
|
||||
process.nextTick(function() {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Set up listeners
|
||||
var connectHandlers = {
|
||||
timeout: connectErrorHandler('timeout'),
|
||||
error: connectErrorHandler('error'),
|
||||
close: connectErrorHandler('close')
|
||||
};
|
||||
|
||||
// Clear out all the current handlers left over
|
||||
[
|
||||
'timeout',
|
||||
'error',
|
||||
'close',
|
||||
'serverOpening',
|
||||
'serverDescriptionChanged',
|
||||
'serverHeartbeatStarted',
|
||||
'serverHeartbeatSucceeded',
|
||||
'serverHeartbeatFailed',
|
||||
'serverClosed',
|
||||
'topologyOpening',
|
||||
'topologyClosed',
|
||||
'topologyDescriptionChanged',
|
||||
'commandStarted',
|
||||
'commandSucceeded',
|
||||
'commandFailed'
|
||||
].forEach(function(e) {
|
||||
self.s.coreTopology.removeAllListeners(e);
|
||||
});
|
||||
|
||||
// Add the event handlers
|
||||
self.s.coreTopology.once('timeout', connectHandlers.timeout);
|
||||
self.s.coreTopology.once('error', connectHandlers.error);
|
||||
self.s.coreTopology.once('close', connectHandlers.close);
|
||||
self.s.coreTopology.once('connect', connectHandler);
|
||||
// Reconnect server
|
||||
self.s.coreTopology.on('reconnect', reconnectHandler);
|
||||
self.s.coreTopology.on('reconnectFailed', reconnectFailedHandler);
|
||||
|
||||
// Set up SDAM listeners
|
||||
self.s.coreTopology.on('serverDescriptionChanged', relay('serverDescriptionChanged'));
|
||||
self.s.coreTopology.on('serverHeartbeatStarted', relay('serverHeartbeatStarted'));
|
||||
self.s.coreTopology.on('serverHeartbeatSucceeded', relay('serverHeartbeatSucceeded'));
|
||||
self.s.coreTopology.on('serverHeartbeatFailed', relay('serverHeartbeatFailed'));
|
||||
self.s.coreTopology.on('serverOpening', relay('serverOpening'));
|
||||
self.s.coreTopology.on('serverClosed', relay('serverClosed'));
|
||||
self.s.coreTopology.on('topologyOpening', relay('topologyOpening'));
|
||||
self.s.coreTopology.on('topologyClosed', relay('topologyClosed'));
|
||||
self.s.coreTopology.on('topologyDescriptionChanged', relay('topologyDescriptionChanged'));
|
||||
self.s.coreTopology.on('commandStarted', relay('commandStarted'));
|
||||
self.s.coreTopology.on('commandSucceeded', relay('commandSucceeded'));
|
||||
self.s.coreTopology.on('commandFailed', relay('commandFailed'));
|
||||
self.s.coreTopology.on('attemptReconnect', relay('attemptReconnect'));
|
||||
self.s.coreTopology.on('monitoring', relay('monitoring'));
|
||||
|
||||
// Start connection
|
||||
self.s.coreTopology.connect(_options);
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(Server.prototype, 'poolSize', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.coreTopology.connections().length;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Server.prototype, 'autoReconnect', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.reconnect;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Server.prototype, 'host', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.host;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Server.prototype, 'port', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.port;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Server connect event
|
||||
*
|
||||
* @event Server#connect
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Server close event
|
||||
*
|
||||
* @event Server#close
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Server reconnect event
|
||||
*
|
||||
* @event Server#reconnect
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Server error event
|
||||
*
|
||||
* @event Server#error
|
||||
* @type {MongoError}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Server timeout event
|
||||
*
|
||||
* @event Server#timeout
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Server parseError event
|
||||
*
|
||||
* @event Server#parseError
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An event emitted indicating a command was started, if command monitoring is enabled
|
||||
*
|
||||
* @event Server#commandStarted
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An event emitted indicating a command succeeded, if command monitoring is enabled
|
||||
*
|
||||
* @event Server#commandSucceeded
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An event emitted indicating a command failed, if command monitoring is enabled
|
||||
*
|
||||
* @event Server#commandFailed
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
module.exports = Server;
|
457
ProjectNow/NodeServer/node_modules/mongodb/lib/topologies/topology_base.js
generated
vendored
Normal file
457
ProjectNow/NodeServer/node_modules/mongodb/lib/topologies/topology_base.js
generated
vendored
Normal file
@@ -0,0 +1,457 @@
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('events'),
|
||||
MongoError = require('mongodb-core').MongoError,
|
||||
f = require('util').format,
|
||||
os = require('os'),
|
||||
translateReadPreference = require('../utils').translateReadPreference,
|
||||
ClientSession = require('mongodb-core').Sessions.ClientSession;
|
||||
|
||||
// The store of ops
|
||||
var Store = function(topology, storeOptions) {
|
||||
var self = this;
|
||||
var storedOps = [];
|
||||
storeOptions = storeOptions || { force: false, bufferMaxEntries: -1 };
|
||||
|
||||
// Internal state
|
||||
this.s = {
|
||||
storedOps: storedOps,
|
||||
storeOptions: storeOptions,
|
||||
topology: topology
|
||||
};
|
||||
|
||||
Object.defineProperty(this, 'length', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return self.s.storedOps.length;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Store.prototype.add = function(opType, ns, ops, options, callback) {
|
||||
if (this.s.storeOptions.force) {
|
||||
return callback(MongoError.create({ message: 'db closed by application', driver: true }));
|
||||
}
|
||||
|
||||
if (this.s.storeOptions.bufferMaxEntries === 0) {
|
||||
return callback(
|
||||
MongoError.create({
|
||||
message: f(
|
||||
'no connection available for operation and number of stored operation > %s',
|
||||
this.s.storeOptions.bufferMaxEntries
|
||||
),
|
||||
driver: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
this.s.storeOptions.bufferMaxEntries > 0 &&
|
||||
this.s.storedOps.length > this.s.storeOptions.bufferMaxEntries
|
||||
) {
|
||||
while (this.s.storedOps.length > 0) {
|
||||
var op = this.s.storedOps.shift();
|
||||
op.c(
|
||||
MongoError.create({
|
||||
message: f(
|
||||
'no connection available for operation and number of stored operation > %s',
|
||||
this.s.storeOptions.bufferMaxEntries
|
||||
),
|
||||
driver: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.s.storedOps.push({ t: opType, n: ns, o: ops, op: options, c: callback });
|
||||
};
|
||||
|
||||
Store.prototype.addObjectAndMethod = function(opType, object, method, params, callback) {
|
||||
if (this.s.storeOptions.force) {
|
||||
return callback(MongoError.create({ message: 'db closed by application', driver: true }));
|
||||
}
|
||||
|
||||
if (this.s.storeOptions.bufferMaxEntries === 0) {
|
||||
return callback(
|
||||
MongoError.create({
|
||||
message: f(
|
||||
'no connection available for operation and number of stored operation > %s',
|
||||
this.s.storeOptions.bufferMaxEntries
|
||||
),
|
||||
driver: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
this.s.storeOptions.bufferMaxEntries > 0 &&
|
||||
this.s.storedOps.length > this.s.storeOptions.bufferMaxEntries
|
||||
) {
|
||||
while (this.s.storedOps.length > 0) {
|
||||
var op = this.s.storedOps.shift();
|
||||
op.c(
|
||||
MongoError.create({
|
||||
message: f(
|
||||
'no connection available for operation and number of stored operation > %s',
|
||||
this.s.storeOptions.bufferMaxEntries
|
||||
),
|
||||
driver: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.s.storedOps.push({ t: opType, m: method, o: object, p: params, c: callback });
|
||||
};
|
||||
|
||||
Store.prototype.flush = function(err) {
|
||||
while (this.s.storedOps.length > 0) {
|
||||
this.s.storedOps
|
||||
.shift()
|
||||
.c(
|
||||
err ||
|
||||
MongoError.create({ message: f('no connection available for operation'), driver: true })
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
var primaryOptions = ['primary', 'primaryPreferred', 'nearest', 'secondaryPreferred'];
|
||||
var secondaryOptions = ['secondary', 'secondaryPreferred'];
|
||||
|
||||
Store.prototype.execute = function(options) {
|
||||
options = options || {};
|
||||
// Get current ops
|
||||
var ops = this.s.storedOps;
|
||||
// Reset the ops
|
||||
this.s.storedOps = [];
|
||||
|
||||
// Unpack options
|
||||
var executePrimary = typeof options.executePrimary === 'boolean' ? options.executePrimary : true;
|
||||
var executeSecondary =
|
||||
typeof options.executeSecondary === 'boolean' ? options.executeSecondary : true;
|
||||
|
||||
// Execute all the stored ops
|
||||
while (ops.length > 0) {
|
||||
var op = ops.shift();
|
||||
|
||||
if (op.t === 'cursor') {
|
||||
if (executePrimary && executeSecondary) {
|
||||
op.o[op.m].apply(op.o, op.p);
|
||||
} else if (
|
||||
executePrimary &&
|
||||
op.o.options &&
|
||||
op.o.options.readPreference &&
|
||||
primaryOptions.indexOf(op.o.options.readPreference.mode) !== -1
|
||||
) {
|
||||
op.o[op.m].apply(op.o, op.p);
|
||||
} else if (
|
||||
!executePrimary &&
|
||||
executeSecondary &&
|
||||
op.o.options &&
|
||||
op.o.options.readPreference &&
|
||||
secondaryOptions.indexOf(op.o.options.readPreference.mode) !== -1
|
||||
) {
|
||||
op.o[op.m].apply(op.o, op.p);
|
||||
}
|
||||
} else if (op.t === 'auth') {
|
||||
this.s.topology[op.t].apply(this.s.topology, op.o);
|
||||
} else {
|
||||
if (executePrimary && executeSecondary) {
|
||||
this.s.topology[op.t](op.n, op.o, op.op, op.c);
|
||||
} else if (
|
||||
executePrimary &&
|
||||
op.op &&
|
||||
op.op.readPreference &&
|
||||
primaryOptions.indexOf(op.op.readPreference.mode) !== -1
|
||||
) {
|
||||
this.s.topology[op.t](op.n, op.o, op.op, op.c);
|
||||
} else if (
|
||||
!executePrimary &&
|
||||
executeSecondary &&
|
||||
op.op &&
|
||||
op.op.readPreference &&
|
||||
secondaryOptions.indexOf(op.op.readPreference.mode) !== -1
|
||||
) {
|
||||
this.s.topology[op.t](op.n, op.o, op.op, op.c);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Store.prototype.all = function() {
|
||||
return this.s.storedOps;
|
||||
};
|
||||
|
||||
// Server capabilities
|
||||
var ServerCapabilities = function(ismaster) {
|
||||
var setup_get_property = function(object, name, value) {
|
||||
Object.defineProperty(object, name, {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Capabilities
|
||||
var aggregationCursor = false;
|
||||
var writeCommands = false;
|
||||
var textSearch = false;
|
||||
var authCommands = false;
|
||||
var listCollections = false;
|
||||
var listIndexes = false;
|
||||
var maxNumberOfDocsInBatch = ismaster.maxWriteBatchSize || 1000;
|
||||
var commandsTakeWriteConcern = false;
|
||||
var commandsTakeCollation = false;
|
||||
|
||||
if (ismaster.minWireVersion >= 0) {
|
||||
textSearch = true;
|
||||
}
|
||||
|
||||
if (ismaster.maxWireVersion >= 1) {
|
||||
aggregationCursor = true;
|
||||
authCommands = true;
|
||||
}
|
||||
|
||||
if (ismaster.maxWireVersion >= 2) {
|
||||
writeCommands = true;
|
||||
}
|
||||
|
||||
if (ismaster.maxWireVersion >= 3) {
|
||||
listCollections = true;
|
||||
listIndexes = true;
|
||||
}
|
||||
|
||||
if (ismaster.maxWireVersion >= 5) {
|
||||
commandsTakeWriteConcern = true;
|
||||
commandsTakeCollation = true;
|
||||
}
|
||||
|
||||
// If no min or max wire version set to 0
|
||||
if (ismaster.minWireVersion == null) {
|
||||
ismaster.minWireVersion = 0;
|
||||
}
|
||||
|
||||
if (ismaster.maxWireVersion == null) {
|
||||
ismaster.maxWireVersion = 0;
|
||||
}
|
||||
|
||||
// Map up read only parameters
|
||||
setup_get_property(this, 'hasAggregationCursor', aggregationCursor);
|
||||
setup_get_property(this, 'hasWriteCommands', writeCommands);
|
||||
setup_get_property(this, 'hasTextSearch', textSearch);
|
||||
setup_get_property(this, 'hasAuthCommands', authCommands);
|
||||
setup_get_property(this, 'hasListCollectionsCommand', listCollections);
|
||||
setup_get_property(this, 'hasListIndexesCommand', listIndexes);
|
||||
setup_get_property(this, 'minWireVersion', ismaster.minWireVersion);
|
||||
setup_get_property(this, 'maxWireVersion', ismaster.maxWireVersion);
|
||||
setup_get_property(this, 'maxNumberOfDocsInBatch', maxNumberOfDocsInBatch);
|
||||
setup_get_property(this, 'commandsTakeWriteConcern', commandsTakeWriteConcern);
|
||||
setup_get_property(this, 'commandsTakeCollation', commandsTakeCollation);
|
||||
};
|
||||
|
||||
// Get package.json variable
|
||||
const driverVersion = require('../../package.json').version,
|
||||
nodejsversion = f('Node.js %s, %s', process.version, os.endianness()),
|
||||
type = os.type(),
|
||||
name = process.platform,
|
||||
architecture = process.arch,
|
||||
release = os.release();
|
||||
|
||||
class TopologyBase extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// Build default client information
|
||||
this.clientInfo = {
|
||||
driver: {
|
||||
name: 'nodejs',
|
||||
version: driverVersion
|
||||
},
|
||||
os: {
|
||||
type: type,
|
||||
name: name,
|
||||
architecture: architecture,
|
||||
version: release
|
||||
},
|
||||
platform: nodejsversion
|
||||
};
|
||||
|
||||
this.setMaxListeners(Infinity);
|
||||
}
|
||||
|
||||
// Sessions related methods
|
||||
hasSessionSupport() {
|
||||
return this.logicalSessionTimeoutMinutes != null;
|
||||
}
|
||||
|
||||
startSession(options, clientOptions) {
|
||||
const session = new ClientSession(this, this.s.sessionPool, options, clientOptions);
|
||||
session.once('ended', () => {
|
||||
this.s.sessions = this.s.sessions.filter(s => !s.equals(session));
|
||||
});
|
||||
|
||||
this.s.sessions.push(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
endSessions(sessions, callback) {
|
||||
return this.s.coreTopology.endSessions(sessions, callback);
|
||||
}
|
||||
|
||||
// Server capabilities
|
||||
capabilities() {
|
||||
if (this.s.sCapabilities) return this.s.sCapabilities;
|
||||
if (this.s.coreTopology.lastIsMaster() == null) return null;
|
||||
this.s.sCapabilities = new ServerCapabilities(this.s.coreTopology.lastIsMaster());
|
||||
return this.s.sCapabilities;
|
||||
}
|
||||
|
||||
// Command
|
||||
command(ns, cmd, options, callback) {
|
||||
this.s.coreTopology.command(ns, cmd, translateReadPreference(options), callback);
|
||||
}
|
||||
|
||||
// Insert
|
||||
insert(ns, ops, options, callback) {
|
||||
this.s.coreTopology.insert(ns, ops, options, callback);
|
||||
}
|
||||
|
||||
// Update
|
||||
update(ns, ops, options, callback) {
|
||||
this.s.coreTopology.update(ns, ops, options, callback);
|
||||
}
|
||||
|
||||
// Remove
|
||||
remove(ns, ops, options, callback) {
|
||||
this.s.coreTopology.remove(ns, ops, options, callback);
|
||||
}
|
||||
|
||||
// IsConnected
|
||||
isConnected(options) {
|
||||
options = options || {};
|
||||
options = translateReadPreference(options);
|
||||
|
||||
return this.s.coreTopology.isConnected(options);
|
||||
}
|
||||
|
||||
// IsDestroyed
|
||||
isDestroyed() {
|
||||
return this.s.coreTopology.isDestroyed();
|
||||
}
|
||||
|
||||
// Cursor
|
||||
cursor(ns, cmd, options) {
|
||||
options = options || {};
|
||||
options = translateReadPreference(options);
|
||||
options.disconnectHandler = this.s.store;
|
||||
options.topology = this;
|
||||
|
||||
return this.s.coreTopology.cursor(ns, cmd, options);
|
||||
}
|
||||
|
||||
lastIsMaster() {
|
||||
return this.s.coreTopology.lastIsMaster();
|
||||
}
|
||||
|
||||
getServer(options) {
|
||||
return this.s.coreTopology.getServer(options);
|
||||
}
|
||||
|
||||
getConnection(options) {
|
||||
return this.s.coreTopology.getConnection(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unref all sockets
|
||||
* @method
|
||||
*/
|
||||
unref() {
|
||||
return this.s.coreTopology.unref();
|
||||
}
|
||||
|
||||
auth() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
this.s.coreTopology.auth.apply(this.s.coreTopology, args);
|
||||
}
|
||||
|
||||
logout() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
this.s.coreTopology.logout.apply(this.s.coreTopology, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* All raw connections
|
||||
* @method
|
||||
* @return {array}
|
||||
*/
|
||||
connections() {
|
||||
return this.s.coreTopology.connections();
|
||||
}
|
||||
|
||||
close(forceClosed) {
|
||||
// If we have sessions, we want to individually move them to the session pool,
|
||||
// and then send a single endSessions call.
|
||||
if (this.s.sessions.length) {
|
||||
this.s.sessions.forEach(session => session.endSession());
|
||||
}
|
||||
|
||||
if (this.s.sessionPool) {
|
||||
this.s.sessionPool.endAllPooledSessions();
|
||||
}
|
||||
|
||||
this.s.coreTopology.destroy({
|
||||
force: typeof forceClosed === 'boolean' ? forceClosed : false
|
||||
});
|
||||
|
||||
// We need to wash out all stored processes
|
||||
if (forceClosed === true) {
|
||||
this.s.storeOptions.force = forceClosed;
|
||||
this.s.store.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Properties
|
||||
Object.defineProperty(TopologyBase.prototype, 'isMasterDoc', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.coreTopology.lastIsMaster();
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(TopologyBase.prototype, 'bson', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.coreTopology.s.bson;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(TopologyBase.prototype, 'parserType', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.coreTopology.parserType;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(TopologyBase.prototype, 'logicalSessionTimeoutMinutes', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.coreTopology.logicalSessionTimeoutMinutes;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(TopologyBase.prototype, 'type', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.s.coreTopology.type;
|
||||
}
|
||||
});
|
||||
|
||||
exports.Store = Store;
|
||||
exports.ServerCapabilities = ServerCapabilities;
|
||||
exports.TopologyBase = TopologyBase;
|
621
ProjectNow/NodeServer/node_modules/mongodb/lib/url_parser.js
generated
vendored
Normal file
621
ProjectNow/NodeServer/node_modules/mongodb/lib/url_parser.js
generated
vendored
Normal file
@@ -0,0 +1,621 @@
|
||||
'use strict';
|
||||
|
||||
const ReadPreference = require('mongodb-core').ReadPreference,
|
||||
parser = require('url'),
|
||||
f = require('util').format,
|
||||
Logger = require('mongodb-core').Logger,
|
||||
dns = require('dns');
|
||||
|
||||
module.exports = function(url, options, callback) {
|
||||
if (typeof options === 'function') (callback = options), (options = {});
|
||||
options = options || {};
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = parser.parse(url, true);
|
||||
} catch (e) {
|
||||
return callback(new Error('URL malformed, cannot be parsed'));
|
||||
}
|
||||
|
||||
if (result.protocol !== 'mongodb:' && result.protocol !== 'mongodb+srv:') {
|
||||
return callback(new Error('Invalid schema, expected `mongodb` or `mongodb+srv`'));
|
||||
}
|
||||
|
||||
if (result.protocol === 'mongodb:') {
|
||||
return parseHandler(url, options, callback);
|
||||
}
|
||||
|
||||
// Otherwise parse this as an SRV record
|
||||
if (result.hostname.split('.').length < 3) {
|
||||
return callback(new Error('URI does not have hostname, domain name and tld'));
|
||||
}
|
||||
|
||||
result.domainLength = result.hostname.split('.').length;
|
||||
|
||||
if (result.pathname && result.pathname.match(',')) {
|
||||
return callback(new Error('Invalid URI, cannot contain multiple hostnames'));
|
||||
}
|
||||
|
||||
if (result.port) {
|
||||
return callback(new Error('Ports not accepted with `mongodb+srv` URIs'));
|
||||
}
|
||||
|
||||
let srvAddress = `_mongodb._tcp.${result.host}`;
|
||||
dns.resolveSrv(srvAddress, function(err, addresses) {
|
||||
if (err) return callback(err);
|
||||
|
||||
if (addresses.length === 0) {
|
||||
return callback(new Error('No addresses found at host'));
|
||||
}
|
||||
|
||||
for (let i = 0; i < addresses.length; i++) {
|
||||
if (!matchesParentDomain(addresses[i].name, result.hostname, result.domainLength)) {
|
||||
return callback(new Error('Server record does not share hostname with parent URI'));
|
||||
}
|
||||
}
|
||||
|
||||
let base = result.auth ? `mongodb://${result.auth}@` : `mongodb://`;
|
||||
let connectionStrings = addresses.map(function(address, i) {
|
||||
if (i === 0) return `${base}${address.name}:${address.port}`;
|
||||
else return `${address.name}:${address.port}`;
|
||||
});
|
||||
|
||||
let connectionString = connectionStrings.join(',') + '/';
|
||||
let connectionStringOptions = [];
|
||||
|
||||
// Add the default database if needed
|
||||
if (result.path) {
|
||||
let defaultDb = result.path.slice(1);
|
||||
if (defaultDb.indexOf('?') !== -1) {
|
||||
defaultDb = defaultDb.slice(0, defaultDb.indexOf('?'));
|
||||
}
|
||||
|
||||
connectionString += defaultDb;
|
||||
}
|
||||
|
||||
// Default to SSL true
|
||||
if (!options.ssl && !result.search) {
|
||||
connectionStringOptions.push('ssl=true');
|
||||
} else if (!options.ssl && result.search && !result.search.match('ssl')) {
|
||||
connectionStringOptions.push('ssl=true');
|
||||
}
|
||||
|
||||
// Keep original uri options
|
||||
if (result.search) {
|
||||
connectionStringOptions.push(result.search.replace('?', ''));
|
||||
}
|
||||
|
||||
dns.resolveTxt(result.host, function(err, record) {
|
||||
if (err && err.code !== 'ENODATA') 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'));
|
||||
}
|
||||
|
||||
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`'));
|
||||
}
|
||||
|
||||
connectionStringOptions.push(record);
|
||||
}
|
||||
|
||||
// Add any options to the connection string
|
||||
if (connectionStringOptions.length) {
|
||||
connectionString += `?${connectionStringOptions.join('&')}`;
|
||||
}
|
||||
|
||||
parseHandler(connectionString, options, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function matchesParentDomain(srvAddress, parentDomain) {
|
||||
let regex = /^.*?\./;
|
||||
let srv = `.${srvAddress.replace(regex, '')}`;
|
||||
let parent = `.${parentDomain.replace(regex, '')}`;
|
||||
if (srv.endsWith(parent)) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
function parseHandler(address, options, callback) {
|
||||
let result, err;
|
||||
try {
|
||||
result = parseConnectionString(address, options);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
return err ? callback(err, null) : callback(null, result);
|
||||
}
|
||||
|
||||
function parseConnectionString(url, options) {
|
||||
// Variables
|
||||
let connection_part = '';
|
||||
let auth_part = '';
|
||||
let query_string_part = '';
|
||||
let dbName = 'admin';
|
||||
|
||||
// Url parser result
|
||||
let result = parser.parse(url, true);
|
||||
if ((result.hostname == null || result.hostname === '') && url.indexOf('.sock') === -1) {
|
||||
throw new Error('No hostname or hostnames provided in connection string');
|
||||
}
|
||||
|
||||
if (result.port === '0') {
|
||||
throw new Error('Invalid port (zero) with hostname');
|
||||
}
|
||||
|
||||
if (!isNaN(parseInt(result.port, 10)) && parseInt(result.port, 10) > 65535) {
|
||||
throw new Error('Invalid port (larger than 65535) with hostname');
|
||||
}
|
||||
|
||||
if (
|
||||
result.path &&
|
||||
result.path.length > 0 &&
|
||||
result.path[0] !== '/' &&
|
||||
url.indexOf('.sock') === -1
|
||||
) {
|
||||
throw new Error('Missing delimiting slash between hosts and options');
|
||||
}
|
||||
|
||||
if (result.query) {
|
||||
for (let name in result.query) {
|
||||
if (name.indexOf('::') !== -1) {
|
||||
throw new Error('Double colon in host identifier');
|
||||
}
|
||||
|
||||
if (result.query[name] === '') {
|
||||
throw new Error('Query parameter ' + name + ' is an incomplete value pair');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.auth) {
|
||||
let parts = result.auth.split(':');
|
||||
if (url.indexOf(result.auth) !== -1 && parts.length > 2) {
|
||||
throw new Error('Username with password containing an unescaped colon');
|
||||
}
|
||||
|
||||
if (url.indexOf(result.auth) !== -1 && result.auth.indexOf('@') !== -1) {
|
||||
throw new Error('Username containing an unescaped at-sign');
|
||||
}
|
||||
}
|
||||
|
||||
// Remove query
|
||||
let clean = url.split('?').shift();
|
||||
|
||||
// Extract the list of hosts
|
||||
let strings = clean.split(',');
|
||||
let hosts = [];
|
||||
|
||||
for (let i = 0; i < strings.length; i++) {
|
||||
let hostString = strings[i];
|
||||
|
||||
if (hostString.indexOf('mongodb') !== -1) {
|
||||
if (hostString.indexOf('@') !== -1) {
|
||||
hosts.push(hostString.split('@').pop());
|
||||
} else {
|
||||
hosts.push(hostString.substr('mongodb://'.length));
|
||||
}
|
||||
} else if (hostString.indexOf('/') !== -1) {
|
||||
hosts.push(hostString.split('/').shift());
|
||||
} else if (hostString.indexOf('/') === -1) {
|
||||
hosts.push(hostString.trim());
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < hosts.length; i++) {
|
||||
let r = parser.parse(f('mongodb://%s', hosts[i].trim()));
|
||||
if (r.path && r.path.indexOf(':') !== -1) {
|
||||
// Not connecting to a socket so check for an extra slash in the hostname.
|
||||
// Using String#split as perf is better than match.
|
||||
if (r.path.split('/').length > 1 && r.path.indexOf('::') === -1) {
|
||||
throw new Error('Slash in host identifier');
|
||||
} else {
|
||||
throw new Error('Double colon in host identifier');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a ? mark cut the query elements off
|
||||
if (url.indexOf('?') !== -1) {
|
||||
query_string_part = url.substr(url.indexOf('?') + 1);
|
||||
connection_part = url.substring('mongodb://'.length, url.indexOf('?'));
|
||||
} else {
|
||||
connection_part = url.substring('mongodb://'.length);
|
||||
}
|
||||
|
||||
// Check if we have auth params
|
||||
if (connection_part.indexOf('@') !== -1) {
|
||||
auth_part = connection_part.split('@')[0];
|
||||
connection_part = connection_part.split('@')[1];
|
||||
}
|
||||
|
||||
// Check there is not more than one unescaped slash
|
||||
if (connection_part.split('/').length > 2) {
|
||||
throw new Error(
|
||||
"Unsupported host '" +
|
||||
connection_part.split('?')[0] +
|
||||
"', hosts must be URL encoded and contain at most one unencoded slash"
|
||||
);
|
||||
}
|
||||
|
||||
// Check if the connection string has a db
|
||||
if (connection_part.indexOf('.sock') !== -1) {
|
||||
if (connection_part.indexOf('.sock/') !== -1) {
|
||||
dbName = connection_part.split('.sock/')[1];
|
||||
// Check if multiple database names provided, or just an illegal trailing backslash
|
||||
if (dbName.indexOf('/') !== -1) {
|
||||
if (dbName.split('/').length === 2 && dbName.split('/')[1].length === 0) {
|
||||
throw new Error('Illegal trailing backslash after database name');
|
||||
}
|
||||
throw new Error('More than 1 database name in URL');
|
||||
}
|
||||
connection_part = connection_part.split(
|
||||
'/',
|
||||
connection_part.indexOf('.sock') + '.sock'.length
|
||||
);
|
||||
}
|
||||
} else if (connection_part.indexOf('/') !== -1) {
|
||||
// Check if multiple database names provided, or just an illegal trailing backslash
|
||||
if (connection_part.split('/').length > 2) {
|
||||
if (connection_part.split('/')[2].length === 0) {
|
||||
throw new Error('Illegal trailing backslash after database name');
|
||||
}
|
||||
throw new Error('More than 1 database name in URL');
|
||||
}
|
||||
dbName = connection_part.split('/')[1];
|
||||
connection_part = connection_part.split('/')[0];
|
||||
}
|
||||
|
||||
// URI decode the host information
|
||||
connection_part = decodeURIComponent(connection_part);
|
||||
|
||||
// Result object
|
||||
let object = {};
|
||||
|
||||
// Pick apart the authentication part of the string
|
||||
let authPart = auth_part || '';
|
||||
let auth = authPart.split(':', 2);
|
||||
|
||||
// Decode the authentication URI components and verify integrity
|
||||
let user = decodeURIComponent(auth[0]);
|
||||
if (auth[0] !== encodeURIComponent(user)) {
|
||||
throw new Error('Username contains an illegal unescaped character');
|
||||
}
|
||||
auth[0] = user;
|
||||
|
||||
if (auth[1]) {
|
||||
let pass = decodeURIComponent(auth[1]);
|
||||
if (auth[1] !== encodeURIComponent(pass)) {
|
||||
throw new Error('Password contains an illegal unescaped character');
|
||||
}
|
||||
auth[1] = pass;
|
||||
}
|
||||
|
||||
// Add auth to final object if we have 2 elements
|
||||
if (auth.length === 2) object.auth = { user: auth[0], password: auth[1] };
|
||||
// if user provided auth options, use that
|
||||
if (options && options.auth != null) object.auth = options.auth;
|
||||
|
||||
// Variables used for temporary storage
|
||||
let hostPart;
|
||||
let urlOptions;
|
||||
let servers;
|
||||
let compression;
|
||||
let serverOptions = { socketOptions: {} };
|
||||
let dbOptions = { read_preference_tags: [] };
|
||||
let replSetServersOptions = { socketOptions: {} };
|
||||
let mongosOptions = { socketOptions: {} };
|
||||
// Add server options to final object
|
||||
object.server_options = serverOptions;
|
||||
object.db_options = dbOptions;
|
||||
object.rs_options = replSetServersOptions;
|
||||
object.mongos_options = mongosOptions;
|
||||
|
||||
// Let's check if we are using a domain socket
|
||||
if (url.match(/\.sock/)) {
|
||||
// Split out the socket part
|
||||
let domainSocket = url.substring(
|
||||
url.indexOf('mongodb://') + 'mongodb://'.length,
|
||||
url.lastIndexOf('.sock') + '.sock'.length
|
||||
);
|
||||
// Clean out any auth stuff if any
|
||||
if (domainSocket.indexOf('@') !== -1) domainSocket = domainSocket.split('@')[1];
|
||||
domainSocket = decodeURIComponent(domainSocket);
|
||||
servers = [{ domain_socket: domainSocket }];
|
||||
} else {
|
||||
// Split up the db
|
||||
hostPart = connection_part;
|
||||
// Deduplicate servers
|
||||
let deduplicatedServers = {};
|
||||
|
||||
// Parse all server results
|
||||
servers = hostPart
|
||||
.split(',')
|
||||
.map(function(h) {
|
||||
let _host, _port, ipv6match;
|
||||
//check if it matches [IPv6]:port, where the port number is optional
|
||||
if ((ipv6match = /\[([^\]]+)\](?::(.+))?/.exec(h))) {
|
||||
_host = ipv6match[1];
|
||||
_port = parseInt(ipv6match[2], 10) || 27017;
|
||||
} else {
|
||||
//otherwise assume it's IPv4, or plain hostname
|
||||
let hostPort = h.split(':', 2);
|
||||
_host = hostPort[0] || 'localhost';
|
||||
_port = hostPort[1] != null ? parseInt(hostPort[1], 10) : 27017;
|
||||
// Check for localhost?safe=true style case
|
||||
if (_host.indexOf('?') !== -1) _host = _host.split(/\?/)[0];
|
||||
}
|
||||
|
||||
// No entry returned for duplicate servr
|
||||
if (deduplicatedServers[_host + '_' + _port]) return null;
|
||||
deduplicatedServers[_host + '_' + _port] = 1;
|
||||
|
||||
// Return the mapped object
|
||||
return { host: _host, port: _port };
|
||||
})
|
||||
.filter(function(x) {
|
||||
return x != null;
|
||||
});
|
||||
}
|
||||
|
||||
// Get the db name
|
||||
object.dbName = dbName || 'admin';
|
||||
// Split up all the options
|
||||
urlOptions = (query_string_part || '').split(/[&;]/);
|
||||
// Ugh, we have to figure out which options go to which constructor manually.
|
||||
urlOptions.forEach(function(opt) {
|
||||
if (!opt) return;
|
||||
var splitOpt = opt.split('='),
|
||||
name = splitOpt[0],
|
||||
value = splitOpt[1];
|
||||
|
||||
// Options implementations
|
||||
switch (name) {
|
||||
case 'slaveOk':
|
||||
case 'slave_ok':
|
||||
serverOptions.slave_ok = value === 'true';
|
||||
dbOptions.slaveOk = value === 'true';
|
||||
break;
|
||||
case 'maxPoolSize':
|
||||
case 'poolSize':
|
||||
serverOptions.poolSize = parseInt(value, 10);
|
||||
replSetServersOptions.poolSize = parseInt(value, 10);
|
||||
break;
|
||||
case 'appname':
|
||||
object.appname = decodeURIComponent(value);
|
||||
break;
|
||||
case 'autoReconnect':
|
||||
case 'auto_reconnect':
|
||||
serverOptions.auto_reconnect = value === 'true';
|
||||
break;
|
||||
case 'ssl':
|
||||
if (value === 'prefer') {
|
||||
serverOptions.ssl = value;
|
||||
replSetServersOptions.ssl = value;
|
||||
mongosOptions.ssl = value;
|
||||
break;
|
||||
}
|
||||
serverOptions.ssl = value === 'true';
|
||||
replSetServersOptions.ssl = value === 'true';
|
||||
mongosOptions.ssl = value === 'true';
|
||||
break;
|
||||
case 'sslValidate':
|
||||
serverOptions.sslValidate = value === 'true';
|
||||
replSetServersOptions.sslValidate = value === 'true';
|
||||
mongosOptions.sslValidate = value === 'true';
|
||||
break;
|
||||
case 'replicaSet':
|
||||
case 'rs_name':
|
||||
replSetServersOptions.rs_name = value;
|
||||
break;
|
||||
case 'reconnectWait':
|
||||
replSetServersOptions.reconnectWait = parseInt(value, 10);
|
||||
break;
|
||||
case 'retries':
|
||||
replSetServersOptions.retries = parseInt(value, 10);
|
||||
break;
|
||||
case 'readSecondary':
|
||||
case 'read_secondary':
|
||||
replSetServersOptions.read_secondary = value === 'true';
|
||||
break;
|
||||
case 'fsync':
|
||||
dbOptions.fsync = value === 'true';
|
||||
break;
|
||||
case 'journal':
|
||||
dbOptions.j = value === 'true';
|
||||
break;
|
||||
case 'safe':
|
||||
dbOptions.safe = value === 'true';
|
||||
break;
|
||||
case 'nativeParser':
|
||||
case 'native_parser':
|
||||
dbOptions.native_parser = value === 'true';
|
||||
break;
|
||||
case 'readConcernLevel':
|
||||
dbOptions.readConcern = { level: value };
|
||||
break;
|
||||
case 'connectTimeoutMS':
|
||||
serverOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
|
||||
replSetServersOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
|
||||
mongosOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
|
||||
break;
|
||||
case 'socketTimeoutMS':
|
||||
serverOptions.socketOptions.socketTimeoutMS = parseInt(value, 10);
|
||||
replSetServersOptions.socketOptions.socketTimeoutMS = parseInt(value, 10);
|
||||
mongosOptions.socketOptions.socketTimeoutMS = parseInt(value, 10);
|
||||
break;
|
||||
case 'w':
|
||||
dbOptions.w = parseInt(value, 10);
|
||||
if (isNaN(dbOptions.w)) dbOptions.w = value;
|
||||
break;
|
||||
case 'authSource':
|
||||
dbOptions.authSource = value;
|
||||
break;
|
||||
case 'gssapiServiceName':
|
||||
dbOptions.gssapiServiceName = value;
|
||||
break;
|
||||
case 'authMechanism':
|
||||
if (value === 'GSSAPI') {
|
||||
// If no password provided decode only the principal
|
||||
if (object.auth == null) {
|
||||
let urlDecodeAuthPart = decodeURIComponent(authPart);
|
||||
if (urlDecodeAuthPart.indexOf('@') === -1)
|
||||
throw new Error('GSSAPI requires a provided principal');
|
||||
object.auth = { user: urlDecodeAuthPart, password: null };
|
||||
} else {
|
||||
object.auth.user = decodeURIComponent(object.auth.user);
|
||||
}
|
||||
} else if (value === 'MONGODB-X509') {
|
||||
object.auth = { user: decodeURIComponent(authPart) };
|
||||
}
|
||||
|
||||
// Only support GSSAPI or MONGODB-CR for now
|
||||
if (
|
||||
value !== 'GSSAPI' &&
|
||||
value !== 'MONGODB-X509' &&
|
||||
value !== 'MONGODB-CR' &&
|
||||
value !== 'DEFAULT' &&
|
||||
value !== 'SCRAM-SHA-1' &&
|
||||
value !== 'SCRAM-SHA-256' &&
|
||||
value !== 'PLAIN'
|
||||
)
|
||||
throw new Error(
|
||||
'Only DEFAULT, GSSAPI, PLAIN, MONGODB-X509, or SCRAM-SHA-1 is supported by authMechanism'
|
||||
);
|
||||
|
||||
// Authentication mechanism
|
||||
dbOptions.authMechanism = value;
|
||||
break;
|
||||
case 'authMechanismProperties':
|
||||
{
|
||||
// Split up into key, value pairs
|
||||
let values = value.split(',');
|
||||
let o = {};
|
||||
// For each value split into key, value
|
||||
values.forEach(function(x) {
|
||||
let v = x.split(':');
|
||||
o[v[0]] = v[1];
|
||||
});
|
||||
|
||||
// Set all authMechanismProperties
|
||||
dbOptions.authMechanismProperties = o;
|
||||
// Set the service name value
|
||||
if (typeof o.SERVICE_NAME === 'string') dbOptions.gssapiServiceName = o.SERVICE_NAME;
|
||||
if (typeof o.SERVICE_REALM === 'string') dbOptions.gssapiServiceRealm = o.SERVICE_REALM;
|
||||
if (typeof o.CANONICALIZE_HOST_NAME === 'string')
|
||||
dbOptions.gssapiCanonicalizeHostName =
|
||||
o.CANONICALIZE_HOST_NAME === 'true' ? true : false;
|
||||
}
|
||||
break;
|
||||
case 'wtimeoutMS':
|
||||
dbOptions.wtimeout = parseInt(value, 10);
|
||||
break;
|
||||
case 'readPreference':
|
||||
if (!ReadPreference.isValid(value))
|
||||
throw new Error(
|
||||
'readPreference must be either primary/primaryPreferred/secondary/secondaryPreferred/nearest'
|
||||
);
|
||||
dbOptions.readPreference = value;
|
||||
break;
|
||||
case 'maxStalenessSeconds':
|
||||
dbOptions.maxStalenessSeconds = parseInt(value, 10);
|
||||
break;
|
||||
case 'readPreferenceTags':
|
||||
{
|
||||
// Decode the value
|
||||
value = decodeURIComponent(value);
|
||||
// Contains the tag object
|
||||
let tagObject = {};
|
||||
if (value == null || value === '') {
|
||||
dbOptions.read_preference_tags.push(tagObject);
|
||||
break;
|
||||
}
|
||||
|
||||
// Split up the tags
|
||||
let tags = value.split(/,/);
|
||||
for (let i = 0; i < tags.length; i++) {
|
||||
let parts = tags[i].trim().split(/:/);
|
||||
tagObject[parts[0]] = parts[1];
|
||||
}
|
||||
|
||||
// Set the preferences tags
|
||||
dbOptions.read_preference_tags.push(tagObject);
|
||||
}
|
||||
break;
|
||||
case 'compressors':
|
||||
{
|
||||
compression = serverOptions.compression || {};
|
||||
let compressors = value.split(',');
|
||||
if (
|
||||
!compressors.every(function(compressor) {
|
||||
return compressor === 'snappy' || compressor === 'zlib';
|
||||
})
|
||||
) {
|
||||
throw new Error('Compressors must be at least one of snappy or zlib');
|
||||
}
|
||||
|
||||
compression.compressors = compressors;
|
||||
serverOptions.compression = compression;
|
||||
}
|
||||
break;
|
||||
case 'zlibCompressionLevel':
|
||||
{
|
||||
compression = serverOptions.compression || {};
|
||||
let zlibCompressionLevel = parseInt(value, 10);
|
||||
if (zlibCompressionLevel < -1 || zlibCompressionLevel > 9) {
|
||||
throw new Error('zlibCompressionLevel must be an integer between -1 and 9');
|
||||
}
|
||||
|
||||
compression.zlibCompressionLevel = zlibCompressionLevel;
|
||||
serverOptions.compression = compression;
|
||||
}
|
||||
break;
|
||||
case 'retryWrites':
|
||||
dbOptions.retryWrites = value === 'true';
|
||||
break;
|
||||
case 'minSize':
|
||||
dbOptions.minSize = parseInt(value, 10);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
let logger = Logger('URL Parser');
|
||||
logger.warn(`${name} is not supported as a connection string option`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// No tags: should be null (not [])
|
||||
if (dbOptions.read_preference_tags.length === 0) {
|
||||
dbOptions.read_preference_tags = null;
|
||||
}
|
||||
|
||||
// Validate if there are an invalid write concern combinations
|
||||
if (
|
||||
(dbOptions.w === -1 || dbOptions.w === 0) &&
|
||||
(dbOptions.journal === true || dbOptions.fsync === true || dbOptions.safe === true)
|
||||
)
|
||||
throw new Error('w set to -1 or 0 cannot be combined with safe/w/journal/fsync');
|
||||
|
||||
// If no read preference set it to primary
|
||||
if (!dbOptions.readPreference) {
|
||||
dbOptions.readPreference = 'primary';
|
||||
}
|
||||
|
||||
// make sure that user-provided options are applied with priority
|
||||
dbOptions = Object.assign(dbOptions, options);
|
||||
|
||||
// Add servers to result
|
||||
object.servers = servers;
|
||||
|
||||
// Returned parsed object
|
||||
return object;
|
||||
}
|
527
ProjectNow/NodeServer/node_modules/mongodb/lib/utils.js
generated
vendored
Normal file
527
ProjectNow/NodeServer/node_modules/mongodb/lib/utils.js
generated
vendored
Normal file
@@ -0,0 +1,527 @@
|
||||
'use strict';
|
||||
|
||||
const MongoError = require('mongodb-core').MongoError;
|
||||
const ReadPreference = require('mongodb-core').ReadPreference;
|
||||
|
||||
var shallowClone = function(obj) {
|
||||
var copy = {};
|
||||
for (var name in obj) copy[name] = obj[name];
|
||||
return copy;
|
||||
};
|
||||
|
||||
// Figure out the read preference
|
||||
var translateReadPreference = function(options) {
|
||||
var r = null;
|
||||
if (options.readPreference) {
|
||||
r = options.readPreference;
|
||||
} else {
|
||||
return options;
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
// Set simple property
|
||||
var getSingleProperty = function(obj, name, value) {
|
||||
Object.defineProperty(obj, name, {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var formatSortValue = (exports.formatSortValue = function(sortDirection) {
|
||||
var value = ('' + sortDirection).toLowerCase();
|
||||
|
||||
switch (value) {
|
||||
case 'ascending':
|
||||
case 'asc':
|
||||
case '1':
|
||||
return 1;
|
||||
case 'descending':
|
||||
case 'desc':
|
||||
case '-1':
|
||||
return -1;
|
||||
default:
|
||||
throw new Error(
|
||||
'Illegal sort clause, must be of the form ' +
|
||||
"[['field1', '(ascending|descending)'], " +
|
||||
"['field2', '(ascending|descending)']]"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var formattedOrderClause = (exports.formattedOrderClause = function(sortValue) {
|
||||
var orderBy = {};
|
||||
if (sortValue == null) return null;
|
||||
if (Array.isArray(sortValue)) {
|
||||
if (sortValue.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (var i = 0; i < sortValue.length; i++) {
|
||||
if (sortValue[i].constructor === String) {
|
||||
orderBy[sortValue[i]] = 1;
|
||||
} else {
|
||||
orderBy[sortValue[i][0]] = formatSortValue(sortValue[i][1]);
|
||||
}
|
||||
}
|
||||
} else if (sortValue != null && typeof sortValue === 'object') {
|
||||
orderBy = sortValue;
|
||||
} else if (typeof sortValue === 'string') {
|
||||
orderBy[sortValue] = 1;
|
||||
} else {
|
||||
throw new Error(
|
||||
'Illegal sort clause, must be of the form ' +
|
||||
"[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]"
|
||||
);
|
||||
}
|
||||
|
||||
return orderBy;
|
||||
});
|
||||
|
||||
var checkCollectionName = function checkCollectionName(collectionName) {
|
||||
if ('string' !== typeof collectionName) {
|
||||
throw new MongoError('collection name must be a String');
|
||||
}
|
||||
|
||||
if (!collectionName || collectionName.indexOf('..') !== -1) {
|
||||
throw new MongoError('collection names cannot be empty');
|
||||
}
|
||||
|
||||
if (
|
||||
collectionName.indexOf('$') !== -1 &&
|
||||
collectionName.match(/((^\$cmd)|(oplog\.\$main))/) == null
|
||||
) {
|
||||
throw new MongoError("collection names must not contain '$'");
|
||||
}
|
||||
|
||||
if (collectionName.match(/^\.|\.$/) != null) {
|
||||
throw new MongoError("collection names must not start or end with '.'");
|
||||
}
|
||||
|
||||
// Validate that we are not passing 0x00 in the colletion name
|
||||
if (collectionName.indexOf('\x00') !== -1) {
|
||||
throw new MongoError('collection names cannot contain a null character');
|
||||
}
|
||||
};
|
||||
|
||||
var handleCallback = function(callback, err, value1, value2) {
|
||||
try {
|
||||
if (callback == null) return;
|
||||
|
||||
if (callback) {
|
||||
return value2 ? callback(err, value1, value2) : callback(err, value1);
|
||||
}
|
||||
} catch (err) {
|
||||
process.nextTick(function() {
|
||||
throw err;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap a Mongo error document in an Error instance
|
||||
* @ignore
|
||||
* @api private
|
||||
*/
|
||||
var toError = function(error) {
|
||||
if (error instanceof Error) return error;
|
||||
|
||||
var msg = error.err || error.errmsg || error.errMessage || error;
|
||||
var e = MongoError.create({ message: msg, driver: true });
|
||||
|
||||
// Get all object keys
|
||||
var keys = typeof error === 'object' ? Object.keys(error) : [];
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
try {
|
||||
e[keys[i]] = error[keys[i]];
|
||||
} catch (err) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
|
||||
return e;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
var normalizeHintField = function normalizeHintField(hint) {
|
||||
var finalHint = null;
|
||||
|
||||
if (typeof hint === 'string') {
|
||||
finalHint = hint;
|
||||
} else if (Array.isArray(hint)) {
|
||||
finalHint = {};
|
||||
|
||||
hint.forEach(function(param) {
|
||||
finalHint[param] = 1;
|
||||
});
|
||||
} else if (hint != null && typeof hint === 'object') {
|
||||
finalHint = {};
|
||||
for (var name in hint) {
|
||||
finalHint[name] = hint[name];
|
||||
}
|
||||
}
|
||||
|
||||
return finalHint;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create index name based on field spec
|
||||
*
|
||||
* @ignore
|
||||
* @api private
|
||||
*/
|
||||
var parseIndexOptions = function(fieldOrSpec) {
|
||||
var fieldHash = {};
|
||||
var indexes = [];
|
||||
var keys;
|
||||
|
||||
// Get all the fields accordingly
|
||||
if ('string' === typeof fieldOrSpec) {
|
||||
// 'type'
|
||||
indexes.push(fieldOrSpec + '_' + 1);
|
||||
fieldHash[fieldOrSpec] = 1;
|
||||
} else if (Array.isArray(fieldOrSpec)) {
|
||||
fieldOrSpec.forEach(function(f) {
|
||||
if ('string' === typeof f) {
|
||||
// [{location:'2d'}, 'type']
|
||||
indexes.push(f + '_' + 1);
|
||||
fieldHash[f] = 1;
|
||||
} else if (Array.isArray(f)) {
|
||||
// [['location', '2d'],['type', 1]]
|
||||
indexes.push(f[0] + '_' + (f[1] || 1));
|
||||
fieldHash[f[0]] = f[1] || 1;
|
||||
} else if (isObject(f)) {
|
||||
// [{location:'2d'}, {type:1}]
|
||||
keys = Object.keys(f);
|
||||
keys.forEach(function(k) {
|
||||
indexes.push(k + '_' + f[k]);
|
||||
fieldHash[k] = f[k];
|
||||
});
|
||||
} else {
|
||||
// undefined (ignore)
|
||||
}
|
||||
});
|
||||
} else if (isObject(fieldOrSpec)) {
|
||||
// {location:'2d', type:1}
|
||||
keys = Object.keys(fieldOrSpec);
|
||||
keys.forEach(function(key) {
|
||||
indexes.push(key + '_' + fieldOrSpec[key]);
|
||||
fieldHash[key] = fieldOrSpec[key];
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
name: indexes.join('_'),
|
||||
keys: keys,
|
||||
fieldHash: fieldHash
|
||||
};
|
||||
};
|
||||
|
||||
var isObject = (exports.isObject = function(arg) {
|
||||
return '[object Object]' === Object.prototype.toString.call(arg);
|
||||
});
|
||||
|
||||
var debugOptions = function(debugFields, options) {
|
||||
var finaloptions = {};
|
||||
debugFields.forEach(function(n) {
|
||||
finaloptions[n] = options[n];
|
||||
});
|
||||
|
||||
return finaloptions;
|
||||
};
|
||||
|
||||
var decorateCommand = function(command, options, exclude) {
|
||||
for (var name in options) {
|
||||
if (exclude[name] == null) command[name] = options[name];
|
||||
}
|
||||
|
||||
return command;
|
||||
};
|
||||
|
||||
var mergeOptions = function(target, source) {
|
||||
for (var name in source) {
|
||||
target[name] = source[name];
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
||||
|
||||
// Merge options with translation
|
||||
var translateOptions = function(target, source) {
|
||||
var translations = {
|
||||
// SSL translation options
|
||||
sslCA: 'ca',
|
||||
sslCRL: 'crl',
|
||||
sslValidate: 'rejectUnauthorized',
|
||||
sslKey: 'key',
|
||||
sslCert: 'cert',
|
||||
sslPass: 'passphrase',
|
||||
// SocketTimeout translation options
|
||||
socketTimeoutMS: 'socketTimeout',
|
||||
connectTimeoutMS: 'connectionTimeout',
|
||||
// Replicaset options
|
||||
replicaSet: 'setName',
|
||||
rs_name: 'setName',
|
||||
secondaryAcceptableLatencyMS: 'acceptableLatency',
|
||||
connectWithNoPrimary: 'secondaryOnlyConnectionAllowed',
|
||||
// Mongos options
|
||||
acceptableLatencyMS: 'localThresholdMS'
|
||||
};
|
||||
|
||||
for (var name in source) {
|
||||
if (translations[name]) {
|
||||
target[translations[name]] = source[name];
|
||||
} else {
|
||||
target[name] = source[name];
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
||||
|
||||
var filterOptions = function(options, names) {
|
||||
var filterOptions = {};
|
||||
|
||||
for (var name in options) {
|
||||
if (names.indexOf(name) !== -1) filterOptions[name] = options[name];
|
||||
}
|
||||
|
||||
// Filtered options
|
||||
return filterOptions;
|
||||
};
|
||||
|
||||
// Write concern keys
|
||||
var writeConcernKeys = ['w', 'j', 'wtimeout', 'fsync'];
|
||||
|
||||
// Merge the write concern options
|
||||
var mergeOptionsAndWriteConcern = function(targetOptions, sourceOptions, keys, mergeWriteConcern) {
|
||||
// Mix in any allowed options
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (!targetOptions[keys[i]] && sourceOptions[keys[i]] !== undefined) {
|
||||
targetOptions[keys[i]] = sourceOptions[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
// No merging of write concern
|
||||
if (!mergeWriteConcern) return targetOptions;
|
||||
|
||||
// Found no write Concern options
|
||||
var found = false;
|
||||
for (i = 0; i < writeConcernKeys.length; i++) {
|
||||
if (targetOptions[writeConcernKeys[i]]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
for (i = 0; i < writeConcernKeys.length; i++) {
|
||||
if (sourceOptions[writeConcernKeys[i]]) {
|
||||
targetOptions[writeConcernKeys[i]] = sourceOptions[writeConcernKeys[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return targetOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Executes the given operation with provided arguments.
|
||||
*
|
||||
* This method reduces large amounts of duplication in the entire codebase by providing
|
||||
* a single point for determining whether callbacks or promises should be used. Additionally
|
||||
* it allows for a single point of entry to provide features such as implicit sessions, which
|
||||
* are required by the Driver Sessions specification in the event that a ClientSession is
|
||||
* not provided
|
||||
*
|
||||
* @param {object} topology The topology to execute this operation on
|
||||
* @param {function} operation The operation to execute
|
||||
* @param {array} args Arguments to apply the provided operation
|
||||
* @param {object} [options] Options that modify the behavior of the method
|
||||
* @param {function]} [options.resultMutator] Allows for the result of the operation to be changed for custom return types
|
||||
*/
|
||||
const executeOperation = (topology, operation, args, options) => {
|
||||
if (topology == null) {
|
||||
throw new TypeError('This method requires a valid topology instance');
|
||||
}
|
||||
|
||||
if (!Array.isArray(args)) {
|
||||
throw new TypeError('This method requires an array of arguments to apply');
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
const Promise = topology.s.promiseLibrary;
|
||||
let resultMutator = options.resultMutator;
|
||||
let callback = args[args.length - 1];
|
||||
|
||||
// The driver sessions spec mandates that we implicitly create sessions for operations
|
||||
// that are not explicitly provided with a session.
|
||||
let session, opOptions, owner;
|
||||
if (!options.skipSessions && topology.hasSessionSupport()) {
|
||||
opOptions = args[args.length - 2];
|
||||
if (opOptions == null || opOptions.session == null) {
|
||||
owner = Symbol();
|
||||
session = topology.startSession({ owner });
|
||||
const optionsIndex = args.length - 2;
|
||||
args[optionsIndex] = Object.assign({}, args[optionsIndex], { session: session });
|
||||
} else if (opOptions.session && opOptions.session.hasEnded) {
|
||||
throw new MongoError('Use of expired sessions is not permitted');
|
||||
}
|
||||
}
|
||||
|
||||
const makeExecuteCallback = (resolve, reject) =>
|
||||
function executeCallback(err, result) {
|
||||
if (session && session.owner === owner && !options.returnsCursor) {
|
||||
session.endSession(() => {
|
||||
delete opOptions.session;
|
||||
if (err) return reject(err);
|
||||
if (resultMutator) return resolve(resultMutator(result));
|
||||
resolve(result);
|
||||
});
|
||||
} else {
|
||||
if (err) return reject(err);
|
||||
if (resultMutator) return resolve(resultMutator(result));
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
|
||||
// Execute using callback
|
||||
if (typeof callback === 'function') {
|
||||
callback = args.pop();
|
||||
const handler = makeExecuteCallback(
|
||||
result => callback(null, result),
|
||||
err => callback(err, null)
|
||||
);
|
||||
args.push(handler);
|
||||
|
||||
try {
|
||||
return operation.apply(null, args);
|
||||
} catch (e) {
|
||||
handler(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Return a Promise
|
||||
if (args[args.length - 1] != null) {
|
||||
throw new TypeError('final argument to `executeOperation` must be a callback');
|
||||
}
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
const handler = makeExecuteCallback(resolve, reject);
|
||||
args[args.length - 1] = handler;
|
||||
|
||||
try {
|
||||
return operation.apply(null, args);
|
||||
} catch (e) {
|
||||
handler(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Applies a write concern to a command based on well defined inheritance rules, optionally
|
||||
* detecting support for the write concern in the first place.
|
||||
*
|
||||
* @param {Object} target the target command we will be applying the write concern to
|
||||
* @param {Object} sources sources where we can inherit default write concerns from
|
||||
* @param {Object} [options] optional settings passed into a command for write concern overrides
|
||||
* @returns {Object} the (now) decorated target
|
||||
*/
|
||||
function applyWriteConcern(target, sources, options) {
|
||||
options = options || {};
|
||||
const db = sources.db;
|
||||
const coll = sources.collection;
|
||||
|
||||
if (options.session && options.session.inTransaction()) {
|
||||
// writeConcern is not allowed within a multi-statement transaction
|
||||
if (target.writeConcern) {
|
||||
delete target.writeConcern;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
// NOTE: there is probably a much better place for this
|
||||
if (db && db.s.options.retryWrites) {
|
||||
target.retryWrites = true;
|
||||
}
|
||||
|
||||
if (options.w != null || options.j != null || options.fsync != null) {
|
||||
const writeConcern = {};
|
||||
if (options.w != null) writeConcern.w = options.w;
|
||||
if (options.wtimeout != null) writeConcern.wtimeout = options.wtimeout;
|
||||
if (options.j != null) writeConcern.j = options.j;
|
||||
if (options.fsync != null) writeConcern.fsync = options.fsync;
|
||||
return Object.assign(target, { writeConcern });
|
||||
}
|
||||
|
||||
if (
|
||||
coll &&
|
||||
(coll.writeConcern.w != null || coll.writeConcern.j != null || coll.writeConcern.fsync != null)
|
||||
) {
|
||||
return Object.assign(target, { writeConcern: Object.assign({}, coll.writeConcern) });
|
||||
}
|
||||
|
||||
if (
|
||||
db &&
|
||||
(db.writeConcern.w != null || db.writeConcern.j != null || db.writeConcern.fsync != null)
|
||||
) {
|
||||
return Object.assign(target, { writeConcern: Object.assign({}, db.writeConcern) });
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given value is a Promise
|
||||
*
|
||||
* @param {*} maybePromise
|
||||
* @return true if the provided value is a Promise
|
||||
*/
|
||||
function isPromiseLike(maybePromise) {
|
||||
return maybePromise && typeof maybePromise.then === 'function';
|
||||
}
|
||||
|
||||
exports.filterOptions = filterOptions;
|
||||
exports.mergeOptions = mergeOptions;
|
||||
exports.translateOptions = translateOptions;
|
||||
exports.shallowClone = shallowClone;
|
||||
exports.getSingleProperty = getSingleProperty;
|
||||
exports.checkCollectionName = checkCollectionName;
|
||||
exports.toError = toError;
|
||||
exports.formattedOrderClause = formattedOrderClause;
|
||||
exports.parseIndexOptions = parseIndexOptions;
|
||||
exports.normalizeHintField = normalizeHintField;
|
||||
exports.handleCallback = handleCallback;
|
||||
exports.decorateCommand = decorateCommand;
|
||||
exports.isObject = isObject;
|
||||
exports.debugOptions = debugOptions;
|
||||
exports.MAX_JS_INT = 0x20000000000000;
|
||||
exports.mergeOptionsAndWriteConcern = mergeOptionsAndWriteConcern;
|
||||
exports.translateReadPreference = translateReadPreference;
|
||||
exports.executeOperation = executeOperation;
|
||||
exports.applyWriteConcern = applyWriteConcern;
|
||||
exports.isPromiseLike = isPromiseLike;
|
Reference in New Issue
Block a user