Cleanup
This commit is contained in:
322
node_modules/mongodb/lib/utils.js
generated
vendored
322
node_modules/mongodb/lib/utils.js
generated
vendored
@@ -1,6 +1,5 @@
|
||||
'use strict';
|
||||
const MongoError = require('./core/error').MongoError;
|
||||
const ReadPreference = require('./core/topologies/read_preference');
|
||||
const WriteConcern = require('./write_concern');
|
||||
|
||||
var shallowClone = function(obj) {
|
||||
@@ -9,31 +8,6 @@ var shallowClone = function(obj) {
|
||||
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, {
|
||||
@@ -66,7 +40,7 @@ var formatSortValue = (exports.formatSortValue = function(sortDirection) {
|
||||
});
|
||||
|
||||
var formattedOrderClause = (exports.formattedOrderClause = function(sortValue) {
|
||||
var orderBy = {};
|
||||
var orderBy = new Map();
|
||||
if (sortValue == null) return null;
|
||||
if (Array.isArray(sortValue)) {
|
||||
if (sortValue.length === 0) {
|
||||
@@ -75,15 +49,22 @@ var formattedOrderClause = (exports.formattedOrderClause = function(sortValue) {
|
||||
|
||||
for (var i = 0; i < sortValue.length; i++) {
|
||||
if (sortValue[i].constructor === String) {
|
||||
orderBy[sortValue[i]] = 1;
|
||||
orderBy.set(`${sortValue[i]}`, 1);
|
||||
} else {
|
||||
orderBy[sortValue[i][0]] = formatSortValue(sortValue[i][1]);
|
||||
orderBy.set(`${sortValue[i][0]}`, formatSortValue(sortValue[i][1]));
|
||||
}
|
||||
}
|
||||
} else if (sortValue != null && typeof sortValue === 'object') {
|
||||
orderBy = sortValue;
|
||||
if (sortValue instanceof Map) {
|
||||
orderBy = sortValue;
|
||||
} else {
|
||||
var sortKeys = Object.keys(sortValue);
|
||||
for (var k of sortKeys) {
|
||||
orderBy.set(k, sortValue[k]);
|
||||
}
|
||||
}
|
||||
} else if (typeof sortValue === 'string') {
|
||||
orderBy[sortValue] = 1;
|
||||
orderBy.set(`${sortValue}`, 1);
|
||||
} else {
|
||||
throw new Error(
|
||||
'Illegal sort clause, must be of the form ' +
|
||||
@@ -313,39 +294,38 @@ var filterOptions = function(options, names) {
|
||||
};
|
||||
|
||||
// Write concern keys
|
||||
var writeConcernKeys = ['w', 'j', 'wtimeout', 'fsync'];
|
||||
const WRITE_CONCERN_KEYS = ['w', 'j', 'wtimeout', 'fsync', 'writeConcern'];
|
||||
|
||||
// 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]]) {
|
||||
/**
|
||||
* If there is no WriteConcern related options defined on target then inherit from source.
|
||||
* Otherwise, do not inherit **any** options from source.
|
||||
* @internal
|
||||
* @param {object} target - options object conditionally receiving the writeConcern options
|
||||
* @param {object} source - options object containing the potentially inherited writeConcern options
|
||||
*/
|
||||
function conditionallyMergeWriteConcern(target, source) {
|
||||
let found = false;
|
||||
for (const wcKey of WRITE_CONCERN_KEYS) {
|
||||
if (wcKey in target) {
|
||||
// Found a writeConcern option
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
for (i = 0; i < writeConcernKeys.length; i++) {
|
||||
if (sourceOptions[writeConcernKeys[i]]) {
|
||||
targetOptions[writeConcernKeys[i]] = sourceOptions[writeConcernKeys[i]];
|
||||
for (const wcKey of WRITE_CONCERN_KEYS) {
|
||||
if (source[wcKey]) {
|
||||
if (!('writeConcern' in target)) {
|
||||
target.writeConcern = {};
|
||||
}
|
||||
target.writeConcern[wcKey] = source[wcKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return targetOptions;
|
||||
};
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given operation with provided arguments.
|
||||
@@ -490,37 +470,6 @@ function applyWriteConcern(target, sources, options) {
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a read preference based on well-defined inheritance rules. This method will not only
|
||||
* determine the read preference (if there is one), but will also ensure the returned value is a
|
||||
* properly constructed instance of `ReadPreference`.
|
||||
*
|
||||
* @param {Collection|Db|MongoClient} parent The parent of the operation on which to determine the read
|
||||
* preference, used for determining the inherited read preference.
|
||||
* @param {Object} options The options passed into the method, potentially containing a read preference
|
||||
* @returns {(ReadPreference|null)} The resolved read preference
|
||||
*/
|
||||
function resolveReadPreference(parent, options) {
|
||||
options = options || {};
|
||||
const session = options.session;
|
||||
|
||||
const inheritedReadPreference = parent.readPreference;
|
||||
|
||||
let readPreference;
|
||||
if (options.readPreference) {
|
||||
readPreference = ReadPreference.fromOptions(options);
|
||||
} else if (session && session.inTransaction() && session.transaction.options.readPreference) {
|
||||
// The transaction’s read preference MUST override all other user configurable read preferences.
|
||||
readPreference = session.transaction.options.readPreference;
|
||||
} else if (inheritedReadPreference != null) {
|
||||
readPreference = inheritedReadPreference;
|
||||
} else {
|
||||
throw new Error('No readPreference was provided or inherited.');
|
||||
}
|
||||
|
||||
return typeof readPreference === 'string' ? new ReadPreference(readPreference) : readPreference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given value is a Promise
|
||||
*
|
||||
@@ -575,7 +524,28 @@ function decorateWithReadConcern(command, coll, options) {
|
||||
}
|
||||
}
|
||||
|
||||
const emitProcessWarning = msg => process.emitWarning(msg, 'DeprecationWarning');
|
||||
/**
|
||||
* Applies an explain to a given command.
|
||||
* @internal
|
||||
*
|
||||
* @param {object} command - the command on which to apply the explain
|
||||
* @param {Explain} explain - the options containing the explain verbosity
|
||||
* @return the new command
|
||||
*/
|
||||
function decorateWithExplain(command, explain) {
|
||||
if (command.explain) {
|
||||
return command;
|
||||
}
|
||||
|
||||
return { explain: command, verbosity: explain.verbosity };
|
||||
}
|
||||
|
||||
const nodejsMajorVersion = +process.version.split('.')[0].substring(1);
|
||||
const emitProcessWarning = msg =>
|
||||
nodejsMajorVersion <= 6
|
||||
? process.emitWarning(msg, 'DeprecationWarning', MONGODB_WARNING_CODE)
|
||||
: process.emitWarning(msg, { type: 'DeprecationWarning', code: MONGODB_WARNING_CODE });
|
||||
// eslint-disable-next-line no-console
|
||||
const emitConsoleWarning = msg => console.error(msg);
|
||||
const emitDeprecationWarning = process.emitWarning ? emitProcessWarning : emitConsoleWarning;
|
||||
|
||||
@@ -622,7 +592,10 @@ function deprecateOptions(config, fn) {
|
||||
}
|
||||
|
||||
config.deprecatedOptions.forEach(deprecatedOption => {
|
||||
if (options.hasOwnProperty(deprecatedOption) && !optionsWarned.has(deprecatedOption)) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(options, deprecatedOption) &&
|
||||
!optionsWarned.has(deprecatedOption)
|
||||
) {
|
||||
optionsWarned.add(deprecatedOption);
|
||||
const msg = msgHandler(config.name, deprecatedOption);
|
||||
emitDeprecationWarning(msg);
|
||||
@@ -770,14 +743,21 @@ function makeInterruptableAsyncInterval(fn, options) {
|
||||
const interval = options.interval || 1000;
|
||||
const minInterval = options.minInterval || 500;
|
||||
const immediate = typeof options.immediate === 'boolean' ? options.immediate : false;
|
||||
const clock = typeof options.clock === 'function' ? options.clock : now;
|
||||
|
||||
function wake() {
|
||||
const currentTime = now();
|
||||
const currentTime = clock();
|
||||
const timeSinceLastWake = currentTime - lastWakeTime;
|
||||
const timeSinceLastCall = currentTime - lastCallTime;
|
||||
const timeUntilNextCall = Math.max(interval - timeSinceLastCall, 0);
|
||||
const timeUntilNextCall = interval - timeSinceLastCall;
|
||||
lastWakeTime = currentTime;
|
||||
|
||||
// For the streaming protocol: there is nothing obviously stopping this
|
||||
// interval from being woken up again while we are waiting "infinitely"
|
||||
// for `fn` to be called again`. Since the function effectively
|
||||
// never completes, the `timeUntilNextCall` will continue to grow
|
||||
// negatively unbounded, so it will never trigger a reschedule here.
|
||||
|
||||
// debounce multiple calls to wake within the `minInterval`
|
||||
if (timeSinceLastWake < minInterval) {
|
||||
return;
|
||||
@@ -788,6 +768,14 @@ function makeInterruptableAsyncInterval(fn, options) {
|
||||
if (timeUntilNextCall > minInterval) {
|
||||
reschedule(minInterval);
|
||||
}
|
||||
|
||||
// This is possible in virtualized environments like AWS Lambda where our
|
||||
// clock is unreliable. In these cases the timer is "running" but never
|
||||
// actually completes, so we want to execute immediately and then attempt
|
||||
// to reschedule.
|
||||
if (timeUntilNextCall < 0) {
|
||||
executeAndReschedule();
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
@@ -809,7 +797,8 @@ function makeInterruptableAsyncInterval(fn, options) {
|
||||
|
||||
function executeAndReschedule() {
|
||||
lastWakeTime = 0;
|
||||
lastCallTime = now();
|
||||
lastCallTime = clock();
|
||||
|
||||
fn(err => {
|
||||
if (err) throw err;
|
||||
reschedule(interval);
|
||||
@@ -819,13 +808,153 @@ function makeInterruptableAsyncInterval(fn, options) {
|
||||
if (immediate) {
|
||||
executeAndReschedule();
|
||||
} else {
|
||||
lastCallTime = now();
|
||||
lastCallTime = clock();
|
||||
reschedule();
|
||||
}
|
||||
|
||||
return { wake, stop };
|
||||
}
|
||||
|
||||
function hasAtomicOperators(doc) {
|
||||
if (Array.isArray(doc)) {
|
||||
return doc.reduce((err, u) => err || hasAtomicOperators(u), null);
|
||||
}
|
||||
|
||||
return (
|
||||
Object.keys(typeof doc.toBSON !== 'function' ? doc : doc.toBSON())
|
||||
.map(k => k[0])
|
||||
.indexOf('$') >= 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the driver used emitWarning the code will be equal to this.
|
||||
* @public
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* process.on('warning', (warning) => {
|
||||
* if (warning.code === MONGODB_WARNING_CODE) console.error('Ah an important warning! :)')
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
const MONGODB_WARNING_CODE = 'MONGODB DRIVER';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param {string} message - message to warn about
|
||||
*/
|
||||
function emitWarning(message) {
|
||||
if (process.emitWarning) {
|
||||
return nodejsMajorVersion <= 6
|
||||
? process.emitWarning(message, undefined, MONGODB_WARNING_CODE)
|
||||
: process.emitWarning(message, { code: MONGODB_WARNING_CODE });
|
||||
} else {
|
||||
// Approximate the style of print out on node versions pre 8.x
|
||||
// eslint-disable-next-line no-console
|
||||
return console.error(`[${MONGODB_WARNING_CODE}] Warning:`, message);
|
||||
}
|
||||
}
|
||||
|
||||
const emittedWarnings = new Set();
|
||||
/**
|
||||
* Will emit a warning once for the duration of the application.
|
||||
* Uses the message to identify if it has already been emitted
|
||||
* so using string interpolation can cause multiple emits
|
||||
* @internal
|
||||
* @param {string} message - message to warn about
|
||||
*/
|
||||
function emitWarningOnce(message) {
|
||||
if (!emittedWarnings.has(message)) {
|
||||
emittedWarnings.add(message);
|
||||
return emitWarning(message);
|
||||
}
|
||||
}
|
||||
|
||||
function isSuperset(set, subset) {
|
||||
set = Array.isArray(set) ? new Set(set) : set;
|
||||
subset = Array.isArray(subset) ? new Set(subset) : subset;
|
||||
for (const elem of subset) {
|
||||
if (!set.has(elem)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function isRecord(value, requiredKeys) {
|
||||
const toString = Object.prototype.toString;
|
||||
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
const isObject = v => toString.call(v) === '[object Object]';
|
||||
if (!isObject(value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ctor = value.constructor;
|
||||
if (ctor && ctor.prototype) {
|
||||
if (!isObject(ctor.prototype)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if some method exists from the Object exists
|
||||
if (!hasOwnProperty.call(ctor.prototype, 'isPrototypeOf')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredKeys) {
|
||||
const keys = Object.keys(value);
|
||||
return isSuperset(keys, requiredKeys);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a deep copy of an object
|
||||
*
|
||||
* NOTE: This is not meant to be the perfect implementation of a deep copy,
|
||||
* but instead something that is good enough for the purposes of
|
||||
* command monitoring.
|
||||
*/
|
||||
function deepCopy(value) {
|
||||
if (value == null) {
|
||||
return value;
|
||||
} else if (Array.isArray(value)) {
|
||||
return value.map(item => deepCopy(item));
|
||||
} else if (isRecord(value)) {
|
||||
const res = {};
|
||||
for (const key in value) {
|
||||
res[key] = deepCopy(value[key]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const ctor = value.constructor;
|
||||
if (ctor) {
|
||||
switch (ctor.name.toLowerCase()) {
|
||||
case 'date':
|
||||
return new ctor(Number(value));
|
||||
case 'map':
|
||||
return new Map(value);
|
||||
case 'set':
|
||||
return new Set(value);
|
||||
case 'buffer':
|
||||
return Buffer.from(value);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* @param {{version: string}} pkg
|
||||
* @returns {{ major: number; minor: number; patch: number }}
|
||||
*/
|
||||
function parsePackageVersion(pkg) {
|
||||
const versionParts = pkg.version.split('.').map(n => Number.parseInt(n, 10));
|
||||
return { major: versionParts[0], minor: versionParts[1], patch: versionParts[2] };
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
filterOptions,
|
||||
mergeOptions,
|
||||
@@ -842,22 +971,27 @@ module.exports = {
|
||||
isObject,
|
||||
debugOptions,
|
||||
MAX_JS_INT: Number.MAX_SAFE_INTEGER + 1,
|
||||
mergeOptionsAndWriteConcern,
|
||||
translateReadPreference,
|
||||
conditionallyMergeWriteConcern,
|
||||
executeLegacyOperation,
|
||||
applyRetryableWrites,
|
||||
applyWriteConcern,
|
||||
isPromiseLike,
|
||||
decorateWithCollation,
|
||||
decorateWithReadConcern,
|
||||
decorateWithExplain,
|
||||
deprecateOptions,
|
||||
SUPPORTS,
|
||||
MongoDBNamespace,
|
||||
resolveReadPreference,
|
||||
emitDeprecationWarning,
|
||||
makeCounter,
|
||||
maybePromise,
|
||||
now,
|
||||
calculateDurationInMs,
|
||||
makeInterruptableAsyncInterval
|
||||
makeInterruptableAsyncInterval,
|
||||
hasAtomicOperators,
|
||||
MONGODB_WARNING_CODE,
|
||||
emitWarning,
|
||||
emitWarningOnce,
|
||||
deepCopy,
|
||||
parsePackageVersion
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user