summaryrefslogtreecommitdiffstats
path: root/node_modules/mongoose/lib/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/mongoose/lib/helpers')
-rw-r--r--node_modules/mongoose/lib/helpers/aggregate/stringifyAccumulatorOptions.js38
-rw-r--r--node_modules/mongoose/lib/helpers/arrayDepth.js30
-rw-r--r--node_modules/mongoose/lib/helpers/clone.js143
-rw-r--r--node_modules/mongoose/lib/helpers/common.js106
-rw-r--r--node_modules/mongoose/lib/helpers/cursor/eachAsync.js121
-rw-r--r--node_modules/mongoose/lib/helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection.js12
-rw-r--r--node_modules/mongoose/lib/helpers/discriminator/getConstructor.js25
-rw-r--r--node_modules/mongoose/lib/helpers/discriminator/getDiscriminatorByValue.js27
-rw-r--r--node_modules/mongoose/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js24
-rw-r--r--node_modules/mongoose/lib/helpers/document/cleanModifiedSubpaths.js28
-rw-r--r--node_modules/mongoose/lib/helpers/document/compile.js204
-rw-r--r--node_modules/mongoose/lib/helpers/document/getEmbeddedDiscriminatorPath.js43
-rw-r--r--node_modules/mongoose/lib/helpers/document/handleSpreadDoc.js17
-rw-r--r--node_modules/mongoose/lib/helpers/each.js25
-rw-r--r--node_modules/mongoose/lib/helpers/get.js39
-rw-r--r--node_modules/mongoose/lib/helpers/getDefaultBulkwriteResult.js27
-rw-r--r--node_modules/mongoose/lib/helpers/getFunctionName.js8
-rw-r--r--node_modules/mongoose/lib/helpers/immediate.js12
-rw-r--r--node_modules/mongoose/lib/helpers/indexes/isDefaultIdIndex.js18
-rw-r--r--node_modules/mongoose/lib/helpers/indexes/isIndexEqual.js95
-rw-r--r--node_modules/mongoose/lib/helpers/isBsonType.js13
-rw-r--r--node_modules/mongoose/lib/helpers/isMongooseObject.js21
-rw-r--r--node_modules/mongoose/lib/helpers/isObject.js16
-rw-r--r--node_modules/mongoose/lib/helpers/isPromise.js6
-rw-r--r--node_modules/mongoose/lib/helpers/model/applyHooks.js135
-rw-r--r--node_modules/mongoose/lib/helpers/model/applyMethods.js56
-rw-r--r--node_modules/mongoose/lib/helpers/model/applyStaticHooks.js71
-rw-r--r--node_modules/mongoose/lib/helpers/model/applyStatics.js12
-rw-r--r--node_modules/mongoose/lib/helpers/model/castBulkWrite.js224
-rw-r--r--node_modules/mongoose/lib/helpers/model/discriminator.js205
-rw-r--r--node_modules/mongoose/lib/helpers/once.js12
-rw-r--r--node_modules/mongoose/lib/helpers/parallelLimit.js55
-rw-r--r--node_modules/mongoose/lib/helpers/populate/SkipPopulateValue.js10
-rw-r--r--node_modules/mongoose/lib/helpers/populate/assignRawDocsToIdStructure.js98
-rw-r--r--node_modules/mongoose/lib/helpers/populate/assignVals.js274
-rw-r--r--node_modules/mongoose/lib/helpers/populate/getModelsMapForPopulate.js522
-rw-r--r--node_modules/mongoose/lib/helpers/populate/getSchemaTypes.js198
-rw-r--r--node_modules/mongoose/lib/helpers/populate/getVirtual.js72
-rw-r--r--node_modules/mongoose/lib/helpers/populate/leanPopulateMap.js7
-rw-r--r--node_modules/mongoose/lib/helpers/populate/lookupLocalFields.js26
-rw-r--r--node_modules/mongoose/lib/helpers/populate/normalizeRefPath.js45
-rw-r--r--node_modules/mongoose/lib/helpers/populate/removeDeselectedForeignField.js31
-rw-r--r--node_modules/mongoose/lib/helpers/populate/validateRef.js19
-rw-r--r--node_modules/mongoose/lib/helpers/printJestWarning.js8
-rw-r--r--node_modules/mongoose/lib/helpers/projection/isDefiningProjection.js18
-rw-r--r--node_modules/mongoose/lib/helpers/projection/isExclusive.js28
-rw-r--r--node_modules/mongoose/lib/helpers/projection/isInclusive.js34
-rw-r--r--node_modules/mongoose/lib/helpers/projection/isPathExcluded.js35
-rw-r--r--node_modules/mongoose/lib/helpers/projection/isPathSelectedInclusive.js28
-rw-r--r--node_modules/mongoose/lib/helpers/projection/parseProjection.js33
-rw-r--r--node_modules/mongoose/lib/helpers/promiseOrCallback.js45
-rw-r--r--node_modules/mongoose/lib/helpers/query/applyGlobalMaxTimeMS.js15
-rw-r--r--node_modules/mongoose/lib/helpers/query/applyQueryMiddleware.js90
-rw-r--r--node_modules/mongoose/lib/helpers/query/castFilterPath.js55
-rw-r--r--node_modules/mongoose/lib/helpers/query/castUpdate.js538
-rw-r--r--node_modules/mongoose/lib/helpers/query/completeMany.js47
-rw-r--r--node_modules/mongoose/lib/helpers/query/getEmbeddedDiscriminatorPath.js68
-rw-r--r--node_modules/mongoose/lib/helpers/query/handleImmutable.js28
-rw-r--r--node_modules/mongoose/lib/helpers/query/hasDollarKeys.js19
-rw-r--r--node_modules/mongoose/lib/helpers/query/isOperator.js11
-rw-r--r--node_modules/mongoose/lib/helpers/query/selectPopulatedFields.js46
-rw-r--r--node_modules/mongoose/lib/helpers/query/wrapThunk.js18
-rw-r--r--node_modules/mongoose/lib/helpers/schema/addAutoId.js7
-rw-r--r--node_modules/mongoose/lib/helpers/schema/applyPlugins.js44
-rw-r--r--node_modules/mongoose/lib/helpers/schema/applyWriteConcern.js16
-rw-r--r--node_modules/mongoose/lib/helpers/schema/cleanPositionalOperators.js12
-rw-r--r--node_modules/mongoose/lib/helpers/schema/getIndexes.js155
-rw-r--r--node_modules/mongoose/lib/helpers/schema/getPath.js35
-rw-r--r--node_modules/mongoose/lib/helpers/schema/handleIdOption.js20
-rw-r--r--node_modules/mongoose/lib/helpers/schema/handleTimestampOption.js24
-rw-r--r--node_modules/mongoose/lib/helpers/schema/merge.js19
-rw-r--r--node_modules/mongoose/lib/helpers/schematype/handleImmutable.js45
-rw-r--r--node_modules/mongoose/lib/helpers/setDefaultsOnInsert.js127
-rw-r--r--node_modules/mongoose/lib/helpers/specialProperties.js3
-rw-r--r--node_modules/mongoose/lib/helpers/symbols.js19
-rw-r--r--node_modules/mongoose/lib/helpers/timestamps/setupTimestamps.js104
-rw-r--r--node_modules/mongoose/lib/helpers/topology/allServersUnknown.js11
-rw-r--r--node_modules/mongoose/lib/helpers/topology/isAtlas.js12
-rw-r--r--node_modules/mongoose/lib/helpers/topology/isSSLError.js15
-rw-r--r--node_modules/mongoose/lib/helpers/update/applyTimestampsToChildren.js172
-rw-r--r--node_modules/mongoose/lib/helpers/update/applyTimestampsToUpdate.js119
-rw-r--r--node_modules/mongoose/lib/helpers/update/castArrayFilters.js78
-rw-r--r--node_modules/mongoose/lib/helpers/update/modifiedPaths.js33
-rw-r--r--node_modules/mongoose/lib/helpers/update/moveImmutableProperties.js53
-rw-r--r--node_modules/mongoose/lib/helpers/update/removeUnusedArrayFilters.js18
-rw-r--r--node_modules/mongoose/lib/helpers/updateValidators.js257
86 files changed, 5732 insertions, 0 deletions
diff --git a/node_modules/mongoose/lib/helpers/aggregate/stringifyAccumulatorOptions.js b/node_modules/mongoose/lib/helpers/aggregate/stringifyAccumulatorOptions.js
new file mode 100644
index 0000000..7362514
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/aggregate/stringifyAccumulatorOptions.js
@@ -0,0 +1,38 @@
+'use strict';
+
+module.exports = function stringifyAccumulatorOptions(pipeline) {
+ if (!Array.isArray(pipeline)) {
+ return;
+ }
+
+ for (const stage of pipeline) {
+ if (stage == null) {
+ continue;
+ }
+
+ const canHaveAccumulator = stage.$group || stage.$bucket || stage.$bucketAuto;
+ if (canHaveAccumulator != null) {
+ for (const key of Object.keys(canHaveAccumulator)) {
+ handleAccumulator(canHaveAccumulator[key]);
+ }
+ }
+
+ if (stage.$facet != null) {
+ for (const key of Object.keys(stage.$facet)) {
+ stringifyAccumulatorOptions(stage.$facet[key]);
+ }
+ }
+ }
+};
+
+function handleAccumulator(operator) {
+ if (operator == null || operator.$accumulator == null) {
+ return;
+ }
+
+ for (const key of ['init', 'accumulate', 'merge', 'finalize']) {
+ if (typeof operator.$accumulator[key] === 'function') {
+ operator.$accumulator[key] = String(operator.$accumulator[key]);
+ }
+ }
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/arrayDepth.js b/node_modules/mongoose/lib/helpers/arrayDepth.js
new file mode 100644
index 0000000..2c6f2e5
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/arrayDepth.js
@@ -0,0 +1,30 @@
+'use strict';
+
+module.exports = arrayDepth;
+
+function arrayDepth(arr) {
+ if (!Array.isArray(arr)) {
+ return { min: 0, max: 0, containsNonArrayItem: true };
+ }
+ if (arr.length === 0) {
+ return { min: 1, max: 1, containsNonArrayItem: false };
+ }
+
+ const res = arrayDepth(arr[0]);
+
+ for (let i = 1; i < arr.length; ++i) {
+ const _res = arrayDepth(arr[i]);
+ if (_res.min < res.min) {
+ res.min = _res.min;
+ }
+ if (_res.max > res.max) {
+ res.max = _res.max;
+ }
+ res.containsNonArrayItem = res.containsNonArrayItem || _res.containsNonArrayItem;
+ }
+
+ res.min = res.min + 1;
+ res.max = res.max + 1;
+
+ return res;
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/clone.js b/node_modules/mongoose/lib/helpers/clone.js
new file mode 100644
index 0000000..5f0b2c9
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/clone.js
@@ -0,0 +1,143 @@
+'use strict';
+
+
+const cloneRegExp = require('regexp-clone');
+const Decimal = require('../types/decimal128');
+const ObjectId = require('../types/objectid');
+const specialProperties = require('./specialProperties');
+const isMongooseObject = require('./isMongooseObject');
+const getFunctionName = require('./getFunctionName');
+const isBsonType = require('./isBsonType');
+const isObject = require('./isObject');
+const symbols = require('./symbols');
+const utils = require('../utils');
+
+
+/*!
+ * Object clone with Mongoose natives support.
+ *
+ * If options.minimize is true, creates a minimal data object. Empty objects and undefined values will not be cloned. This makes the data payload sent to MongoDB as small as possible.
+ *
+ * Functions are never cloned.
+ *
+ * @param {Object} obj the object to clone
+ * @param {Object} options
+ * @param {Boolean} isArrayChild true if cloning immediately underneath an array. Special case for minimize.
+ * @return {Object} the cloned object
+ * @api private
+ */
+
+function clone(obj, options, isArrayChild) {
+ if (obj == null) {
+ return obj;
+ }
+
+ if (Array.isArray(obj)) {
+ return cloneArray(obj, options);
+ }
+
+ if (isMongooseObject(obj)) {
+ // Single nested subdocs should apply getters later in `applyGetters()`
+ // when calling `toObject()`. See gh-7442, gh-8295
+ if (options && options._skipSingleNestedGetters && obj.$isSingleNested) {
+ options = Object.assign({}, options, { getters: false });
+ }
+
+ if (utils.isPOJO(obj) && obj.$__ != null && obj._doc != null) {
+ return obj._doc;
+ }
+
+ if (options && options.json && typeof obj.toJSON === 'function') {
+ return obj.toJSON(options);
+ }
+ return obj.toObject(options);
+ }
+
+ if (obj.constructor) {
+ switch (getFunctionName(obj.constructor)) {
+ case 'Object':
+ return cloneObject(obj, options, isArrayChild);
+ case 'Date':
+ return new obj.constructor(+obj);
+ case 'RegExp':
+ return cloneRegExp(obj);
+ default:
+ // ignore
+ break;
+ }
+ }
+
+ if (obj instanceof ObjectId) {
+ return new ObjectId(obj.id);
+ }
+
+ if (isBsonType(obj, 'Decimal128')) {
+ if (options && options.flattenDecimals) {
+ return obj.toJSON();
+ }
+ return Decimal.fromString(obj.toString());
+ }
+
+ if (!obj.constructor && isObject(obj)) {
+ // object created with Object.create(null)
+ return cloneObject(obj, options, isArrayChild);
+ }
+
+ if (obj[symbols.schemaTypeSymbol]) {
+ return obj.clone();
+ }
+
+ // If we're cloning this object to go into a MongoDB command,
+ // and there's a `toBSON()` function, assume this object will be
+ // stored as a primitive in MongoDB and doesn't need to be cloned.
+ if (options && options.bson && typeof obj.toBSON === 'function') {
+ return obj;
+ }
+
+ if (obj.valueOf != null) {
+ return obj.valueOf();
+ }
+
+ return cloneObject(obj, options, isArrayChild);
+}
+module.exports = clone;
+
+/*!
+ * ignore
+ */
+
+function cloneObject(obj, options, isArrayChild) {
+ const minimize = options && options.minimize;
+ const ret = {};
+ let hasKeys;
+
+ for (const k in obj) {
+ if (specialProperties.has(k)) {
+ continue;
+ }
+
+ // Don't pass `isArrayChild` down
+ const val = clone(obj[k], options);
+
+ if (!minimize || (typeof val !== 'undefined')) {
+ if (minimize === false && typeof val === 'undefined') {
+ delete ret[k];
+ } else {
+ hasKeys || (hasKeys = true);
+ ret[k] = val;
+ }
+ }
+ }
+
+ return minimize && !isArrayChild ? hasKeys && ret : ret;
+}
+
+function cloneArray(arr, options) {
+ const ret = [];
+
+ for (const item of arr) {
+ ret.push(clone(item, options, true));
+ }
+
+ return ret;
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/common.js b/node_modules/mongoose/lib/helpers/common.js
new file mode 100644
index 0000000..ed7dc42
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/common.js
@@ -0,0 +1,106 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const Binary = require('../driver').get().Binary;
+const Decimal128 = require('../types/decimal128');
+const ObjectId = require('../types/objectid');
+const isMongooseObject = require('./isMongooseObject');
+
+exports.flatten = flatten;
+exports.modifiedPaths = modifiedPaths;
+
+/*!
+ * ignore
+ */
+
+function flatten(update, path, options, schema) {
+ let keys;
+ if (update && isMongooseObject(update) && !Buffer.isBuffer(update)) {
+ keys = Object.keys(update.toObject({ transform: false, virtuals: false }));
+ } else {
+ keys = Object.keys(update || {});
+ }
+
+ const numKeys = keys.length;
+ const result = {};
+ path = path ? path + '.' : '';
+
+ for (let i = 0; i < numKeys; ++i) {
+ const key = keys[i];
+ const val = update[key];
+ result[path + key] = val;
+
+ // Avoid going into mixed paths if schema is specified
+ const keySchema = schema && schema.path && schema.path(path + key);
+ const isNested = schema && schema.nested && schema.nested[path + key];
+ if (keySchema && keySchema.instance === 'Mixed') continue;
+
+ if (shouldFlatten(val)) {
+ if (options && options.skipArrays && Array.isArray(val)) {
+ continue;
+ }
+ const flat = flatten(val, path + key, options, schema);
+ for (const k in flat) {
+ result[k] = flat[k];
+ }
+ if (Array.isArray(val)) {
+ result[path + key] = val;
+ }
+ }
+
+ if (isNested) {
+ const paths = Object.keys(schema.paths);
+ for (const p of paths) {
+ if (p.startsWith(path + key + '.') && !result.hasOwnProperty(p)) {
+ result[p] = void 0;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * ignore
+ */
+
+function modifiedPaths(update, path, result) {
+ const keys = Object.keys(update || {});
+ const numKeys = keys.length;
+ result = result || {};
+ path = path ? path + '.' : '';
+
+ for (let i = 0; i < numKeys; ++i) {
+ const key = keys[i];
+ let val = update[key];
+
+ result[path + key] = true;
+ if (isMongooseObject(val) && !Buffer.isBuffer(val)) {
+ val = val.toObject({ transform: false, virtuals: false });
+ }
+ if (shouldFlatten(val)) {
+ modifiedPaths(val, path + key, result);
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * ignore
+ */
+
+function shouldFlatten(val) {
+ return val &&
+ typeof val === 'object' &&
+ !(val instanceof Date) &&
+ !(val instanceof ObjectId) &&
+ (!Array.isArray(val) || val.length > 0) &&
+ !(val instanceof Buffer) &&
+ !(val instanceof Decimal128) &&
+ !(val instanceof Binary);
+}
diff --git a/node_modules/mongoose/lib/helpers/cursor/eachAsync.js b/node_modules/mongoose/lib/helpers/cursor/eachAsync.js
new file mode 100644
index 0000000..4afff03
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/cursor/eachAsync.js
@@ -0,0 +1,121 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const promiseOrCallback = require('../promiseOrCallback');
+
+/**
+ * Execute `fn` for every document in the cursor. If `fn` returns a promise,
+ * will wait for the promise to resolve before iterating on to the next one.
+ * Returns a promise that resolves when done.
+ *
+ * @param {Function} next the thunk to call to get the next document
+ * @param {Function} fn
+ * @param {Object} options
+ * @param {Function} [callback] executed when all docs have been processed
+ * @return {Promise}
+ * @api public
+ * @method eachAsync
+ */
+
+module.exports = function eachAsync(next, fn, options, callback) {
+ const parallel = options.parallel || 1;
+ const enqueue = asyncQueue();
+
+ return promiseOrCallback(callback, cb => {
+ iterate(cb);
+ });
+
+ function iterate(finalCallback) {
+ let drained = false;
+ let handleResultsInProgress = 0;
+ let currentDocumentIndex = 0;
+
+ let error = null;
+ for (let i = 0; i < parallel; ++i) {
+ enqueue(fetch);
+ }
+
+ function fetch(done) {
+ if (drained || error) {
+ return done();
+ }
+
+ next(function(err, doc) {
+ if (drained || error != null) {
+ return done();
+ }
+ if (err != null) {
+ error = err;
+ finalCallback(err);
+ return done();
+ }
+ if (doc == null) {
+ drained = true;
+ if (handleResultsInProgress <= 0) {
+ finalCallback(null);
+ }
+ return done();
+ }
+
+ ++handleResultsInProgress;
+
+ // Kick off the subsequent `next()` before handling the result, but
+ // make sure we know that we still have a result to handle re: #8422
+ process.nextTick(() => done());
+
+ handleNextResult(doc, currentDocumentIndex++, function(err) {
+ --handleResultsInProgress;
+ if (err != null) {
+ error = err;
+ return finalCallback(err);
+ }
+ if (drained && handleResultsInProgress <= 0) {
+ return finalCallback(null);
+ }
+
+ setTimeout(() => enqueue(fetch), 0);
+ });
+ });
+ }
+ }
+
+ function handleNextResult(doc, i, callback) {
+ const promise = fn(doc, i);
+ if (promise && typeof promise.then === 'function') {
+ promise.then(
+ function() { callback(null); },
+ function(error) { callback(error || new Error('`eachAsync()` promise rejected without error')); });
+ } else {
+ callback(null);
+ }
+ }
+};
+
+// `next()` can only execute one at a time, so make sure we always execute
+// `next()` in series, while still allowing multiple `fn()` instances to run
+// in parallel.
+function asyncQueue() {
+ const _queue = [];
+ let inProgress = null;
+ let id = 0;
+
+ return function enqueue(fn) {
+ if (_queue.length === 0 && inProgress == null) {
+ inProgress = id++;
+ return fn(_step);
+ }
+ _queue.push(fn);
+ };
+
+ function _step() {
+ inProgress = null;
+ if (_queue.length > 0) {
+ inProgress = id++;
+ const fn = _queue.shift();
+ fn(_step);
+ }
+ }
+}
diff --git a/node_modules/mongoose/lib/helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection.js b/node_modules/mongoose/lib/helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection.js
new file mode 100644
index 0000000..755de88
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection.js
@@ -0,0 +1,12 @@
+'use strict';
+
+module.exports = function checkEmbeddedDiscriminatorKeyProjection(userProjection, path, schema, selected, addedPaths) {
+ const userProjectedInPath = Object.keys(userProjection).
+ reduce((cur, key) => cur || key.startsWith(path + '.'), false);
+ const _discriminatorKey = path + '.' + schema.options.discriminatorKey;
+ if (!userProjectedInPath &&
+ addedPaths.length === 1 &&
+ addedPaths[0] === _discriminatorKey) {
+ selected.splice(selected.indexOf(_discriminatorKey), 1);
+ }
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/discriminator/getConstructor.js b/node_modules/mongoose/lib/helpers/discriminator/getConstructor.js
new file mode 100644
index 0000000..04a3ded
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/discriminator/getConstructor.js
@@ -0,0 +1,25 @@
+'use strict';
+
+const getDiscriminatorByValue = require('./getDiscriminatorByValue');
+
+/*!
+ * Find the correct constructor, taking into account discriminators
+ */
+
+module.exports = function getConstructor(Constructor, value) {
+ const discriminatorKey = Constructor.schema.options.discriminatorKey;
+ if (value != null &&
+ Constructor.discriminators &&
+ value[discriminatorKey] != null) {
+ if (Constructor.discriminators[value[discriminatorKey]]) {
+ Constructor = Constructor.discriminators[value[discriminatorKey]];
+ } else {
+ const constructorByValue = getDiscriminatorByValue(Constructor, value[discriminatorKey]);
+ if (constructorByValue) {
+ Constructor = constructorByValue;
+ }
+ }
+ }
+
+ return Constructor;
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/discriminator/getDiscriminatorByValue.js b/node_modules/mongoose/lib/helpers/discriminator/getDiscriminatorByValue.js
new file mode 100644
index 0000000..a107a91
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/discriminator/getDiscriminatorByValue.js
@@ -0,0 +1,27 @@
+'use strict';
+
+/*!
+* returns discriminator by discriminatorMapping.value
+*
+* @param {Model} model
+* @param {string} value
+*/
+
+module.exports = function getDiscriminatorByValue(model, value) {
+ let discriminator = null;
+ if (!model.discriminators) {
+ return discriminator;
+ }
+ for (const name in model.discriminators) {
+ const it = model.discriminators[name];
+ if (
+ it.schema &&
+ it.schema.discriminatorMapping &&
+ it.schema.discriminatorMapping.value == value
+ ) {
+ discriminator = it;
+ break;
+ }
+ }
+ return discriminator;
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js b/node_modules/mongoose/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js
new file mode 100644
index 0000000..f3e71a0
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js
@@ -0,0 +1,24 @@
+'use strict';
+
+/*!
+* returns discriminator by discriminatorMapping.value
+*
+* @param {Schema} schema
+* @param {string} value
+*/
+
+module.exports = function getSchemaDiscriminatorByValue(schema, value) {
+ if (schema == null || schema.discriminators == null) {
+ return null;
+ }
+ for (const key of Object.keys(schema.discriminators)) {
+ const discriminatorSchema = schema.discriminators[key];
+ if (discriminatorSchema.discriminatorMapping == null) {
+ continue;
+ }
+ if (discriminatorSchema.discriminatorMapping.value === value) {
+ return discriminatorSchema;
+ }
+ }
+ return null;
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/document/cleanModifiedSubpaths.js b/node_modules/mongoose/lib/helpers/document/cleanModifiedSubpaths.js
new file mode 100644
index 0000000..252d348
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/document/cleanModifiedSubpaths.js
@@ -0,0 +1,28 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function cleanModifiedSubpaths(doc, path, options) {
+ options = options || {};
+ const skipDocArrays = options.skipDocArrays;
+
+ let deleted = 0;
+ if (!doc) {
+ return deleted;
+ }
+ for (const modifiedPath of Object.keys(doc.$__.activePaths.states.modify)) {
+ if (skipDocArrays) {
+ const schemaType = doc.schema.path(modifiedPath);
+ if (schemaType && schemaType.$isMongooseDocumentArray) {
+ continue;
+ }
+ }
+ if (modifiedPath.startsWith(path + '.')) {
+ delete doc.$__.activePaths.states.modify[modifiedPath];
+ ++deleted;
+ }
+ }
+ return deleted;
+};
diff --git a/node_modules/mongoose/lib/helpers/document/compile.js b/node_modules/mongoose/lib/helpers/document/compile.js
new file mode 100644
index 0000000..def45e6
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/document/compile.js
@@ -0,0 +1,204 @@
+'use strict';
+
+const documentSchemaSymbol = require('../../helpers/symbols').documentSchemaSymbol;
+const get = require('../../helpers/get');
+const internalToObjectOptions = require('../../options').internalToObjectOptions;
+const utils = require('../../utils');
+
+let Document;
+const getSymbol = require('../../helpers/symbols').getSymbol;
+const scopeSymbol = require('../../helpers/symbols').scopeSymbol;
+
+/*!
+ * exports
+ */
+
+exports.compile = compile;
+exports.defineKey = defineKey;
+
+/*!
+ * Compiles schemas.
+ */
+
+function compile(tree, proto, prefix, options) {
+ Document = Document || require('../../document');
+ const keys = Object.keys(tree);
+ const len = keys.length;
+ let limb;
+ let key;
+
+ for (let i = 0; i < len; ++i) {
+ key = keys[i];
+ limb = tree[key];
+
+ const hasSubprops = utils.isPOJO(limb) && Object.keys(limb).length &&
+ (!limb[options.typeKey] || (options.typeKey === 'type' && limb.type.type));
+ const subprops = hasSubprops ? limb : null;
+
+ defineKey(key, subprops, proto, prefix, keys, options);
+ }
+}
+
+/*!
+ * Defines the accessor named prop on the incoming prototype.
+ */
+
+function defineKey(prop, subprops, prototype, prefix, keys, options) {
+ Document = Document || require('../../document');
+ const path = (prefix ? prefix + '.' : '') + prop;
+ prefix = prefix || '';
+
+ if (subprops) {
+ Object.defineProperty(prototype, prop, {
+ enumerable: true,
+ configurable: true,
+ get: function() {
+ const _this = this;
+ if (!this.$__.getters) {
+ this.$__.getters = {};
+ }
+
+ if (!this.$__.getters[path]) {
+ const nested = Object.create(Document.prototype, getOwnPropertyDescriptors(this));
+
+ // save scope for nested getters/setters
+ if (!prefix) {
+ nested.$__[scopeSymbol] = this;
+ }
+ nested.$__.nestedPath = path;
+
+ Object.defineProperty(nested, 'schema', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: prototype.schema
+ });
+
+ Object.defineProperty(nested, documentSchemaSymbol, {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: prototype.schema
+ });
+
+ Object.defineProperty(nested, 'toObject', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: function() {
+ return utils.clone(_this.get(path, null, {
+ virtuals: get(this, 'schema.options.toObject.virtuals', null)
+ }));
+ }
+ });
+
+ Object.defineProperty(nested, '$__get', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: function() {
+ return _this.get(path, null, {
+ virtuals: get(this, 'schema.options.toObject.virtuals', null)
+ });
+ }
+ });
+
+ Object.defineProperty(nested, 'toJSON', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: function() {
+ return _this.get(path, null, {
+ virtuals: get(_this, 'schema.options.toJSON.virtuals', null)
+ });
+ }
+ });
+
+ Object.defineProperty(nested, '$__isNested', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: true
+ });
+
+ const _isEmptyOptions = Object.freeze({
+ minimize: true,
+ virtuals: false,
+ getters: false,
+ transform: false
+ });
+ Object.defineProperty(nested, '$isEmpty', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: function() {
+ return Object.keys(this.get(path, null, _isEmptyOptions) || {}).length === 0;
+ }
+ });
+
+ Object.defineProperty(nested, '$__parent', {
+ enumerable: false,
+ configurable: true,
+ writable: false,
+ value: this
+ });
+
+ compile(subprops, nested, path, options);
+ this.$__.getters[path] = nested;
+ }
+
+ return this.$__.getters[path];
+ },
+ set: function(v) {
+ if (v != null && v.$__isNested) {
+ // Convert top-level to POJO, but leave subdocs hydrated so `$set`
+ // can handle them. See gh-9293.
+ v = v.$__get();
+ } else if (v instanceof Document && !v.$__isNested) {
+ v = v.toObject(internalToObjectOptions);
+ }
+ const doc = this.$__[scopeSymbol] || this;
+ doc.$set(path, v);
+ }
+ });
+ } else {
+ Object.defineProperty(prototype, prop, {
+ enumerable: true,
+ configurable: true,
+ get: function() {
+ return this[getSymbol].call(this.$__[scopeSymbol] || this, path);
+ },
+ set: function(v) {
+ this.$set.call(this.$__[scopeSymbol] || this, path, v);
+ }
+ });
+ }
+}
+
+// gets descriptors for all properties of `object`
+// makes all properties non-enumerable to match previous behavior to #2211
+function getOwnPropertyDescriptors(object) {
+ const result = {};
+
+ Object.getOwnPropertyNames(object).forEach(function(key) {
+ result[key] = Object.getOwnPropertyDescriptor(object, key);
+ // Assume these are schema paths, ignore them re: #5470
+ if (result[key].get) {
+ delete result[key];
+ return;
+ }
+ result[key].enumerable = [
+ 'isNew',
+ '$__',
+ 'errors',
+ '_doc',
+ '$locals',
+ '$op',
+ '__parentArray',
+ '__index',
+ '$isDocumentArrayElement'
+ ].indexOf(key) === -1;
+ });
+
+ return result;
+}
diff --git a/node_modules/mongoose/lib/helpers/document/getEmbeddedDiscriminatorPath.js b/node_modules/mongoose/lib/helpers/document/getEmbeddedDiscriminatorPath.js
new file mode 100644
index 0000000..a2784e3
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/document/getEmbeddedDiscriminatorPath.js
@@ -0,0 +1,43 @@
+'use strict';
+
+const get = require('../get');
+
+/*!
+ * Like `schema.path()`, except with a document, because impossible to
+ * determine path type without knowing the embedded discriminator key.
+ */
+
+module.exports = function getEmbeddedDiscriminatorPath(doc, path, options) {
+ options = options || {};
+ const typeOnly = options.typeOnly;
+ const parts = path.split('.');
+ let schema = null;
+ let type = 'adhocOrUndefined';
+
+ for (let i = 0; i < parts.length; ++i) {
+ const subpath = parts.slice(0, i + 1).join('.');
+ schema = doc.schema.path(subpath);
+ if (schema == null) {
+ type = 'adhocOrUndefined';
+ continue;
+ }
+ if (schema.instance === 'Mixed') {
+ return typeOnly ? 'real' : schema;
+ }
+ type = doc.schema.pathType(subpath);
+ if ((schema.$isSingleNested || schema.$isMongooseDocumentArrayElement) &&
+ schema.schema.discriminators != null) {
+ const discriminators = schema.schema.discriminators;
+ const discriminatorKey = doc.get(subpath + '.' +
+ get(schema, 'schema.options.discriminatorKey'));
+ if (discriminatorKey == null || discriminators[discriminatorKey] == null) {
+ continue;
+ }
+ const rest = parts.slice(i + 1).join('.');
+ return getEmbeddedDiscriminatorPath(doc.get(subpath), rest, options);
+ }
+ }
+
+ // Are we getting the whole schema or just the type, 'real', 'nested', etc.
+ return typeOnly ? type : schema;
+};
diff --git a/node_modules/mongoose/lib/helpers/document/handleSpreadDoc.js b/node_modules/mongoose/lib/helpers/document/handleSpreadDoc.js
new file mode 100644
index 0000000..d3075e4
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/document/handleSpreadDoc.js
@@ -0,0 +1,17 @@
+'use strict';
+
+const utils = require('../../utils');
+
+/**
+ * Using spread operator on a Mongoose document gives you a
+ * POJO that has a tendency to cause infinite recursion. So
+ * we use this function on `set()` to prevent that.
+ */
+
+module.exports = function handleSpreadDoc(v) {
+ if (utils.isPOJO(v) && v.$__ != null && v._doc != null) {
+ return v._doc;
+ }
+
+ return v;
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/each.js b/node_modules/mongoose/lib/helpers/each.js
new file mode 100644
index 0000000..fe70069
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/each.js
@@ -0,0 +1,25 @@
+'use strict';
+
+module.exports = function each(arr, cb, done) {
+ if (arr.length === 0) {
+ return done();
+ }
+
+ let remaining = arr.length;
+ let err = null;
+ for (const v of arr) {
+ cb(v, function(_err) {
+ if (err != null) {
+ return;
+ }
+ if (_err != null) {
+ err = _err;
+ return done(err);
+ }
+
+ if (--remaining <= 0) {
+ return done();
+ }
+ });
+ }
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/get.js b/node_modules/mongoose/lib/helpers/get.js
new file mode 100644
index 0000000..dcb3881
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/get.js
@@ -0,0 +1,39 @@
+'use strict';
+
+/*!
+ * Simplified lodash.get to work around the annoying null quirk. See:
+ * https://github.com/lodash/lodash/issues/3659
+ */
+
+module.exports = function get(obj, path, def) {
+ const parts = path.split('.');
+ let rest = path;
+ let cur = obj;
+ for (const part of parts) {
+ if (cur == null) {
+ return def;
+ }
+
+ // `lib/cast.js` depends on being able to get dotted paths in updates,
+ // like `{ $set: { 'a.b': 42 } }`
+ if (cur[rest] != null) {
+ return cur[rest];
+ }
+
+ cur = getProperty(cur, part);
+
+ rest = rest.substr(part.length + 1);
+ }
+
+ return cur == null ? def : cur;
+};
+
+function getProperty(obj, prop) {
+ if (obj == null) {
+ return obj;
+ }
+ if (obj instanceof Map) {
+ return obj.get(prop);
+ }
+ return obj[prop];
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/getDefaultBulkwriteResult.js b/node_modules/mongoose/lib/helpers/getDefaultBulkwriteResult.js
new file mode 100644
index 0000000..7d10f17
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/getDefaultBulkwriteResult.js
@@ -0,0 +1,27 @@
+'use strict';
+function getDefaultBulkwriteResult() {
+ return {
+ result: {
+ ok: 1,
+ writeErrors: [],
+ writeConcernErrors: [],
+ insertedIds: [],
+ nInserted: 0,
+ nUpserted: 0,
+ nMatched: 0,
+ nModified: 0,
+ nRemoved: 0,
+ upserted: []
+ },
+ insertedCount: 0,
+ matchedCount: 0,
+ modifiedCount: 0,
+ deletedCount: 0,
+ upsertedCount: 0,
+ upsertedIds: {},
+ insertedIds: {},
+ n: 0
+ };
+}
+
+module.exports = getDefaultBulkwriteResult; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/getFunctionName.js b/node_modules/mongoose/lib/helpers/getFunctionName.js
new file mode 100644
index 0000000..87a2c69
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/getFunctionName.js
@@ -0,0 +1,8 @@
+'use strict';
+
+module.exports = function(fn) {
+ if (fn.name) {
+ return fn.name;
+ }
+ return (fn.toString().trim().match(/^function\s*([^\s(]+)/) || [])[1];
+};
diff --git a/node_modules/mongoose/lib/helpers/immediate.js b/node_modules/mongoose/lib/helpers/immediate.js
new file mode 100644
index 0000000..ddb7060
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/immediate.js
@@ -0,0 +1,12 @@
+/*!
+ * Centralize this so we can more easily work around issues with people
+ * stubbing out `process.nextTick()` in tests using sinon:
+ * https://github.com/sinonjs/lolex#automatically-incrementing-mocked-time
+ * See gh-6074
+ */
+
+'use strict';
+
+module.exports = function immediate(cb) {
+ return process.nextTick(cb);
+};
diff --git a/node_modules/mongoose/lib/helpers/indexes/isDefaultIdIndex.js b/node_modules/mongoose/lib/helpers/indexes/isDefaultIdIndex.js
new file mode 100644
index 0000000..c975dcf
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/indexes/isDefaultIdIndex.js
@@ -0,0 +1,18 @@
+'use strict';
+
+const get = require('../get');
+
+module.exports = function isDefaultIdIndex(index) {
+ if (Array.isArray(index)) {
+ // Mongoose syntax
+ const keys = Object.keys(index[0]);
+ return keys.length === 1 && keys[0] === '_id' && index[0]._id !== 'hashed';
+ }
+
+ if (typeof index !== 'object') {
+ return false;
+ }
+
+ const key = get(index, 'key', {});
+ return Object.keys(key).length === 1 && key.hasOwnProperty('_id');
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/indexes/isIndexEqual.js b/node_modules/mongoose/lib/helpers/indexes/isIndexEqual.js
new file mode 100644
index 0000000..d59d734
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/indexes/isIndexEqual.js
@@ -0,0 +1,95 @@
+'use strict';
+
+const get = require('../get');
+const utils = require('../../utils');
+
+/**
+ * Given a Mongoose index definition (key + options objects) and a MongoDB server
+ * index definition, determine if the two indexes are equal.
+ *
+ * @param {Object} key the Mongoose index spec
+ * @param {Object} options the Mongoose index definition's options
+ * @param {Object} dbIndex the index in MongoDB as returned by `listIndexes()`
+ * @api private
+ */
+
+module.exports = function isIndexEqual(key, options, dbIndex) {
+ // Special case: text indexes have a special format in the db. For example,
+ // `{ name: 'text' }` becomes:
+ // {
+ // v: 2,
+ // key: { _fts: 'text', _ftsx: 1 },
+ // name: 'name_text',
+ // ns: 'test.tests',
+ // background: true,
+ // weights: { name: 1 },
+ // default_language: 'english',
+ // language_override: 'language',
+ // textIndexVersion: 3
+ // }
+ if (dbIndex.textIndexVersion != null) {
+ const weights = dbIndex.weights;
+ if (Object.keys(weights).length !== Object.keys(key).length) {
+ return false;
+ }
+ for (const prop of Object.keys(weights)) {
+ if (!(prop in key)) {
+ return false;
+ }
+ const weight = weights[prop];
+ if (weight !== get(options, 'weights.' + prop) && !(weight === 1 && get(options, 'weights.' + prop) == null)) {
+ return false;
+ }
+ }
+
+ if (options['default_language'] !== dbIndex['default_language']) {
+ return dbIndex['default_language'] === 'english' && options['default_language'] == null;
+ }
+
+ return true;
+ }
+
+ const optionKeys = [
+ 'unique',
+ 'partialFilterExpression',
+ 'sparse',
+ 'expireAfterSeconds',
+ 'collation'
+ ];
+ for (const key of optionKeys) {
+ if (!(key in options) && !(key in dbIndex)) {
+ continue;
+ }
+ if (key === 'collation') {
+ if (options[key] == null || dbIndex[key] == null) {
+ return options[key] == null && dbIndex[key] == null;
+ }
+ const definedKeys = Object.keys(options.collation);
+ const schemaCollation = options.collation;
+ const dbCollation = dbIndex.collation;
+ for (const opt of definedKeys) {
+ if (get(schemaCollation, opt) !== get(dbCollation, opt)) {
+ return false;
+ }
+ }
+ } else if (!utils.deepEqual(options[key], dbIndex[key])) {
+ return false;
+ }
+ }
+
+ const schemaIndexKeys = Object.keys(key);
+ const dbIndexKeys = Object.keys(dbIndex.key);
+ if (schemaIndexKeys.length !== dbIndexKeys.length) {
+ return false;
+ }
+ for (let i = 0; i < schemaIndexKeys.length; ++i) {
+ if (schemaIndexKeys[i] !== dbIndexKeys[i]) {
+ return false;
+ }
+ if (!utils.deepEqual(key[schemaIndexKeys[i]], dbIndex.key[dbIndexKeys[i]])) {
+ return false;
+ }
+ }
+
+ return true;
+};
diff --git a/node_modules/mongoose/lib/helpers/isBsonType.js b/node_modules/mongoose/lib/helpers/isBsonType.js
new file mode 100644
index 0000000..01435d3
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/isBsonType.js
@@ -0,0 +1,13 @@
+'use strict';
+
+const get = require('./get');
+
+/*!
+ * Get the bson type, if it exists
+ */
+
+function isBsonType(obj, typename) {
+ return get(obj, '_bsontype', void 0) === typename;
+}
+
+module.exports = isBsonType;
diff --git a/node_modules/mongoose/lib/helpers/isMongooseObject.js b/node_modules/mongoose/lib/helpers/isMongooseObject.js
new file mode 100644
index 0000000..016f9e6
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/isMongooseObject.js
@@ -0,0 +1,21 @@
+'use strict';
+
+/*!
+ * Returns if `v` is a mongoose object that has a `toObject()` method we can use.
+ *
+ * This is for compatibility with libs like Date.js which do foolish things to Natives.
+ *
+ * @param {any} v
+ * @api private
+ */
+
+module.exports = function(v) {
+ if (v == null) {
+ return false;
+ }
+
+ return v.$__ != null || // Document
+ v.isMongooseArray || // Array or Document Array
+ v.isMongooseBuffer || // Buffer
+ v.$isMongooseMap; // Map
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/isObject.js b/node_modules/mongoose/lib/helpers/isObject.js
new file mode 100644
index 0000000..f8ac313
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/isObject.js
@@ -0,0 +1,16 @@
+'use strict';
+
+/*!
+ * Determines if `arg` is an object.
+ *
+ * @param {Object|Array|String|Function|RegExp|any} arg
+ * @api private
+ * @return {Boolean}
+ */
+
+module.exports = function(arg) {
+ if (Buffer.isBuffer(arg)) {
+ return true;
+ }
+ return Object.prototype.toString.call(arg) === '[object Object]';
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/isPromise.js b/node_modules/mongoose/lib/helpers/isPromise.js
new file mode 100644
index 0000000..d6db260
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/isPromise.js
@@ -0,0 +1,6 @@
+'use strict';
+function isPromise(val) {
+ return !!val && (typeof val === 'object' || typeof val === 'function') && typeof val.then === 'function';
+}
+
+module.exports = isPromise; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/model/applyHooks.js b/node_modules/mongoose/lib/helpers/model/applyHooks.js
new file mode 100644
index 0000000..9570a36
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyHooks.js
@@ -0,0 +1,135 @@
+'use strict';
+
+const symbols = require('../../schema/symbols');
+const promiseOrCallback = require('../promiseOrCallback');
+
+/*!
+ * ignore
+ */
+
+module.exports = applyHooks;
+
+/*!
+ * ignore
+ */
+
+applyHooks.middlewareFunctions = [
+ 'deleteOne',
+ 'save',
+ 'validate',
+ 'remove',
+ 'updateOne',
+ 'init'
+];
+
+/*!
+ * Register hooks for this model
+ *
+ * @param {Model} model
+ * @param {Schema} schema
+ */
+
+function applyHooks(model, schema, options) {
+ options = options || {};
+
+ const kareemOptions = {
+ useErrorHandlers: true,
+ numCallbackParams: 1,
+ nullResultByDefault: true,
+ contextParameter: true
+ };
+ const objToDecorate = options.decorateDoc ? model : model.prototype;
+
+ model.$appliedHooks = true;
+ for (const key of Object.keys(schema.paths)) {
+ const type = schema.paths[key];
+ let childModel = null;
+ if (type.$isSingleNested) {
+ childModel = type.caster;
+ } else if (type.$isMongooseDocumentArray) {
+ childModel = type.Constructor;
+ } else {
+ continue;
+ }
+
+ if (childModel.$appliedHooks) {
+ continue;
+ }
+
+ applyHooks(childModel, type.schema, options);
+ if (childModel.discriminators != null) {
+ const keys = Object.keys(childModel.discriminators);
+ for (const key of keys) {
+ applyHooks(childModel.discriminators[key],
+ childModel.discriminators[key].schema, options);
+ }
+ }
+ }
+
+ // Built-in hooks rely on hooking internal functions in order to support
+ // promises and make it so that `doc.save.toString()` provides meaningful
+ // information.
+
+ const middleware = schema.s.hooks.
+ filter(hook => {
+ if (hook.name === 'updateOne' || hook.name === 'deleteOne') {
+ return !!hook['document'];
+ }
+ if (hook.name === 'remove' || hook.name === 'init') {
+ return hook['document'] == null || !!hook['document'];
+ }
+ return true;
+ }).
+ filter(hook => {
+ // If user has overwritten the method, don't apply built-in middleware
+ if (schema.methods[hook.name]) {
+ return !hook.fn[symbols.builtInMiddleware];
+ }
+
+ return true;
+ });
+
+ model._middleware = middleware;
+
+ objToDecorate.$__originalValidate = objToDecorate.$__originalValidate || objToDecorate.$__validate;
+
+ for (const method of ['save', 'validate', 'remove', 'deleteOne']) {
+ const toWrap = method === 'validate' ? '$__originalValidate' : `$__${method}`;
+ const wrapped = middleware.
+ createWrapper(method, objToDecorate[toWrap], null, kareemOptions);
+ objToDecorate[`$__${method}`] = wrapped;
+ }
+ objToDecorate.$__init = middleware.
+ createWrapperSync('init', objToDecorate.$__init, null, kareemOptions);
+
+ // Support hooks for custom methods
+ const customMethods = Object.keys(schema.methods);
+ const customMethodOptions = Object.assign({}, kareemOptions, {
+ // Only use `checkForPromise` for custom methods, because mongoose
+ // query thunks are not as consistent as I would like about returning
+ // a nullish value rather than the query. If a query thunk returns
+ // a query, `checkForPromise` causes infinite recursion
+ checkForPromise: true
+ });
+ for (const method of customMethods) {
+ if (!middleware.hasHooks(method)) {
+ // Don't wrap if there are no hooks for the custom method to avoid
+ // surprises. Also, `createWrapper()` enforces consistent async,
+ // so wrapping a sync method would break it.
+ continue;
+ }
+ const originalMethod = objToDecorate[method];
+ objToDecorate[method] = function() {
+ const args = Array.prototype.slice.call(arguments);
+ const cb = args.slice(-1).pop();
+ const argsWithoutCallback = typeof cb === 'function' ?
+ args.slice(0, args.length - 1) : args;
+ return promiseOrCallback(cb, callback => {
+ return this[`$__${method}`].apply(this,
+ argsWithoutCallback.concat([callback]));
+ }, model.events);
+ };
+ objToDecorate[`$__${method}`] = middleware.
+ createWrapper(method, originalMethod, null, customMethodOptions);
+ }
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/model/applyMethods.js b/node_modules/mongoose/lib/helpers/model/applyMethods.js
new file mode 100644
index 0000000..912f3aa
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyMethods.js
@@ -0,0 +1,56 @@
+'use strict';
+
+const get = require('../get');
+
+/*!
+ * Register methods for this model
+ *
+ * @param {Model} model
+ * @param {Schema} schema
+ */
+
+module.exports = function applyMethods(model, schema) {
+ function apply(method, schema) {
+ Object.defineProperty(model.prototype, method, {
+ get: function() {
+ const h = {};
+ for (const k in schema.methods[method]) {
+ h[k] = schema.methods[method][k].bind(this);
+ }
+ return h;
+ },
+ configurable: true
+ });
+ }
+ for (const method of Object.keys(schema.methods)) {
+ const fn = schema.methods[method];
+ if (schema.tree.hasOwnProperty(method)) {
+ throw new Error('You have a method and a property in your schema both ' +
+ 'named "' + method + '"');
+ }
+ if (schema.reserved[method] &&
+ !get(schema, `methodOptions.${method}.suppressWarning`, false)) {
+ console.warn(`mongoose: the method name "${method}" is used by mongoose ` +
+ 'internally, overwriting it may cause bugs. If you\'re sure you know ' +
+ 'what you\'re doing, you can suppress this error by using ' +
+ `\`schema.method('${method}', fn, { suppressWarning: true })\`.`);
+ }
+ if (typeof fn === 'function') {
+ model.prototype[method] = fn;
+ } else {
+ apply(method, schema);
+ }
+ }
+
+ // Recursively call `applyMethods()` on child schemas
+ model.$appliedMethods = true;
+ for (const key of Object.keys(schema.paths)) {
+ const type = schema.paths[key];
+ if (type.$isSingleNested && !type.caster.$appliedMethods) {
+ applyMethods(type.caster, type.schema);
+ }
+ if (type.$isMongooseDocumentArray && !type.Constructor.$appliedMethods) {
+ applyMethods(type.Constructor, type.schema);
+ }
+ }
+};
diff --git a/node_modules/mongoose/lib/helpers/model/applyStaticHooks.js b/node_modules/mongoose/lib/helpers/model/applyStaticHooks.js
new file mode 100644
index 0000000..219e289
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyStaticHooks.js
@@ -0,0 +1,71 @@
+'use strict';
+
+const middlewareFunctions = require('../query/applyQueryMiddleware').middlewareFunctions;
+const promiseOrCallback = require('../promiseOrCallback');
+
+module.exports = function applyStaticHooks(model, hooks, statics) {
+ const kareemOptions = {
+ useErrorHandlers: true,
+ numCallbackParams: 1
+ };
+
+ hooks = hooks.filter(hook => {
+ // If the custom static overwrites an existing query middleware, don't apply
+ // middleware to it by default. This avoids a potential backwards breaking
+ // change with plugins like `mongoose-delete` that use statics to overwrite
+ // built-in Mongoose functions.
+ if (middlewareFunctions.indexOf(hook.name) !== -1) {
+ return !!hook.model;
+ }
+ return hook.model !== false;
+ });
+
+ model.$__insertMany = hooks.createWrapper('insertMany',
+ model.$__insertMany, model, kareemOptions);
+
+ for (const key of Object.keys(statics)) {
+ if (hooks.hasHooks(key)) {
+ const original = model[key];
+
+ model[key] = function() {
+ const numArgs = arguments.length;
+ const lastArg = numArgs > 0 ? arguments[numArgs - 1] : null;
+ const cb = typeof lastArg === 'function' ? lastArg : null;
+ const args = Array.prototype.slice.
+ call(arguments, 0, cb == null ? numArgs : numArgs - 1);
+ // Special case: can't use `Kareem#wrap()` because it doesn't currently
+ // support wrapped functions that return a promise.
+ return promiseOrCallback(cb, callback => {
+ hooks.execPre(key, model, args, function(err) {
+ if (err != null) {
+ return callback(err);
+ }
+
+ let postCalled = 0;
+ const ret = original.apply(model, args.concat(post));
+ if (ret != null && typeof ret.then === 'function') {
+ ret.then(res => post(null, res), err => post(err));
+ }
+
+ function post(error, res) {
+ if (postCalled++ > 0) {
+ return;
+ }
+
+ if (error != null) {
+ return callback(error);
+ }
+
+ hooks.execPost(key, model, [res], function(error) {
+ if (error != null) {
+ return callback(error);
+ }
+ callback(null, res);
+ });
+ }
+ });
+ }, model.events);
+ };
+ }
+ }
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/model/applyStatics.js b/node_modules/mongoose/lib/helpers/model/applyStatics.js
new file mode 100644
index 0000000..3b9501e
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyStatics.js
@@ -0,0 +1,12 @@
+'use strict';
+
+/*!
+ * Register statics for this model
+ * @param {Model} model
+ * @param {Schema} schema
+ */
+module.exports = function applyStatics(model, schema) {
+ for (const i in schema.statics) {
+ model[i] = schema.statics[i];
+ }
+};
diff --git a/node_modules/mongoose/lib/helpers/model/castBulkWrite.js b/node_modules/mongoose/lib/helpers/model/castBulkWrite.js
new file mode 100644
index 0000000..6e7a830
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/castBulkWrite.js
@@ -0,0 +1,224 @@
+'use strict';
+
+const getDiscriminatorByValue = require('../../helpers/discriminator/getDiscriminatorByValue');
+const applyTimestampsToChildren = require('../update/applyTimestampsToChildren');
+const applyTimestampsToUpdate = require('../update/applyTimestampsToUpdate');
+const cast = require('../../cast');
+const castUpdate = require('../query/castUpdate');
+const setDefaultsOnInsert = require('../setDefaultsOnInsert');
+
+/*!
+ * Given a model and a bulkWrite op, return a thunk that handles casting and
+ * validating the individual op.
+ */
+
+module.exports = function castBulkWrite(originalModel, op, options) {
+ const now = originalModel.base.now();
+
+ if (op['insertOne']) {
+ return (callback) => {
+ const model = decideModelByObject(originalModel, op['insertOne']['document']);
+
+ const doc = new model(op['insertOne']['document']);
+ if (model.schema.options.timestamps != null) {
+ doc.initializeTimestamps();
+ }
+ if (options.session != null) {
+ doc.$session(options.session);
+ }
+ op['insertOne']['document'] = doc;
+ op['insertOne']['document'].validate({ __noPromise: true }, function(error) {
+ if (error) {
+ return callback(error, null);
+ }
+ callback(null);
+ });
+ };
+ } else if (op['updateOne']) {
+ return (callback) => {
+ try {
+ if (!op['updateOne']['filter']) {
+ throw new Error('Must provide a filter object.');
+ }
+ if (!op['updateOne']['update']) {
+ throw new Error('Must provide an update object.');
+ }
+
+ const model = decideModelByObject(originalModel, op['updateOne']['filter']);
+ const schema = model.schema;
+ const strict = options.strict != null ? options.strict : model.schema.options.strict;
+
+ _addDiscriminatorToObject(schema, op['updateOne']['filter']);
+
+ if (model.schema.$timestamps != null && op['updateOne'].timestamps !== false) {
+ const createdAt = model.schema.$timestamps.createdAt;
+ const updatedAt = model.schema.$timestamps.updatedAt;
+ applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateOne']['update'], {});
+ }
+
+ applyTimestampsToChildren(now, op['updateOne']['update'], model.schema);
+
+ if (op['updateOne'].setDefaultsOnInsert) {
+ setDefaultsOnInsert(op['updateOne']['filter'], model.schema, op['updateOne']['update'], {
+ setDefaultsOnInsert: true,
+ upsert: op['updateOne'].upsert
+ });
+ }
+
+ op['updateOne']['filter'] = cast(model.schema, op['updateOne']['filter'], {
+ strict: strict,
+ upsert: op['updateOne'].upsert
+ });
+
+ op['updateOne']['update'] = castUpdate(model.schema, op['updateOne']['update'], {
+ strict: strict,
+ overwrite: false,
+ upsert: op['updateOne'].upsert
+ }, model, op['updateOne']['filter']);
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else if (op['updateMany']) {
+ return (callback) => {
+ try {
+ if (!op['updateMany']['filter']) {
+ throw new Error('Must provide a filter object.');
+ }
+ if (!op['updateMany']['update']) {
+ throw new Error('Must provide an update object.');
+ }
+
+ const model = decideModelByObject(originalModel, op['updateMany']['filter']);
+ const schema = model.schema;
+ const strict = options.strict != null ? options.strict : model.schema.options.strict;
+
+ if (op['updateMany'].setDefaultsOnInsert) {
+ setDefaultsOnInsert(op['updateMany']['filter'], model.schema, op['updateMany']['update'], {
+ setDefaultsOnInsert: true,
+ upsert: op['updateMany'].upsert
+ });
+ }
+
+ if (model.schema.$timestamps != null && op['updateMany'].timestamps !== false) {
+ const createdAt = model.schema.$timestamps.createdAt;
+ const updatedAt = model.schema.$timestamps.updatedAt;
+ applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateMany']['update'], {});
+ }
+
+ applyTimestampsToChildren(now, op['updateMany']['update'], model.schema);
+
+ _addDiscriminatorToObject(schema, op['updateMany']['filter']);
+
+ op['updateMany']['filter'] = cast(model.schema, op['updateMany']['filter'], {
+ strict: strict,
+ upsert: op['updateMany'].upsert
+ });
+
+ op['updateMany']['update'] = castUpdate(model.schema, op['updateMany']['update'], {
+ strict: strict,
+ overwrite: false,
+ upsert: op['updateMany'].upsert
+ }, model, op['updateMany']['filter']);
+
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else if (op['replaceOne']) {
+ return (callback) => {
+ const model = decideModelByObject(originalModel, op['replaceOne']['filter']);
+ const schema = model.schema;
+ const strict = options.strict != null ? options.strict : model.schema.options.strict;
+
+ _addDiscriminatorToObject(schema, op['replaceOne']['filter']);
+ try {
+ op['replaceOne']['filter'] = cast(model.schema, op['replaceOne']['filter'], {
+ strict: strict,
+ upsert: op['replaceOne'].upsert
+ });
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ // set `skipId`, otherwise we get "_id field cannot be changed"
+ const doc = new model(op['replaceOne']['replacement'], strict, true);
+ if (model.schema.options.timestamps != null) {
+ doc.initializeTimestamps();
+ }
+ if (options.session != null) {
+ doc.$session(options.session);
+ }
+ op['replaceOne']['replacement'] = doc;
+
+ op['replaceOne']['replacement'].validate({ __noPromise: true }, function(error) {
+ if (error) {
+ return callback(error, null);
+ }
+ op['replaceOne']['replacement'] = op['replaceOne']['replacement'].toBSON();
+ callback(null);
+ });
+ };
+ } else if (op['deleteOne']) {
+ return (callback) => {
+ const model = decideModelByObject(originalModel, op['deleteOne']['filter']);
+ const schema = model.schema;
+
+ _addDiscriminatorToObject(schema, op['deleteOne']['filter']);
+
+ try {
+ op['deleteOne']['filter'] = cast(model.schema,
+ op['deleteOne']['filter']);
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else if (op['deleteMany']) {
+ return (callback) => {
+ const model = decideModelByObject(originalModel, op['deleteMany']['filter']);
+ const schema = model.schema;
+
+ _addDiscriminatorToObject(schema, op['deleteMany']['filter']);
+
+ try {
+ op['deleteMany']['filter'] = cast(model.schema,
+ op['deleteMany']['filter']);
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else {
+ return (callback) => {
+ callback(new Error('Invalid op passed to `bulkWrite()`'), null);
+ };
+ }
+};
+
+function _addDiscriminatorToObject(schema, obj) {
+ if (schema == null) {
+ return;
+ }
+ if (schema.discriminatorMapping && !schema.discriminatorMapping.isRoot) {
+ obj[schema.discriminatorMapping.key] = schema.discriminatorMapping.value;
+ }
+}
+
+/*!
+ * gets discriminator model if discriminator key is present in object
+ */
+
+function decideModelByObject(model, object) {
+ const discriminatorKey = model.schema.options.discriminatorKey;
+ if (object != null && object.hasOwnProperty(discriminatorKey)) {
+ model = getDiscriminatorByValue(model, object[discriminatorKey]) || model;
+ }
+ return model;
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/model/discriminator.js b/node_modules/mongoose/lib/helpers/model/discriminator.js
new file mode 100644
index 0000000..2ad4c5e
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/discriminator.js
@@ -0,0 +1,205 @@
+'use strict';
+
+const Mixed = require('../../schema/mixed');
+const defineKey = require('../document/compile').defineKey;
+const get = require('../get');
+const utils = require('../../utils');
+
+const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
+ toJSON: true,
+ toObject: true,
+ _id: true,
+ id: true
+};
+
+/*!
+ * ignore
+ */
+
+module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins) {
+ if (!(schema && schema.instanceOfSchema)) {
+ throw new Error('You must pass a valid discriminator Schema');
+ }
+
+ if (model.schema.discriminatorMapping &&
+ !model.schema.discriminatorMapping.isRoot) {
+ throw new Error('Discriminator "' + name +
+ '" can only be a discriminator of the root model');
+ }
+
+ if (applyPlugins) {
+ const applyPluginsToDiscriminators = get(model.base,
+ 'options.applyPluginsToDiscriminators', false);
+ // Even if `applyPluginsToDiscriminators` isn't set, we should still apply
+ // global plugins to schemas embedded in the discriminator schema (gh-7370)
+ model.base._applyPlugins(schema, {
+ skipTopLevel: !applyPluginsToDiscriminators
+ });
+ }
+
+ const key = model.schema.options.discriminatorKey;
+
+ const existingPath = model.schema.path(key);
+ if (existingPath != null) {
+ if (!utils.hasUserDefinedProperty(existingPath.options, 'select')) {
+ existingPath.options.select = true;
+ }
+ existingPath.options.$skipDiscriminatorCheck = true;
+ } else {
+ const baseSchemaAddition = {};
+ baseSchemaAddition[key] = {
+ default: void 0,
+ select: true,
+ $skipDiscriminatorCheck: true
+ };
+ baseSchemaAddition[key][model.schema.options.typeKey] = String;
+ model.schema.add(baseSchemaAddition);
+ defineKey(key, null, model.prototype, null, [key], model.schema.options);
+ }
+
+ if (schema.path(key) && schema.path(key).options.$skipDiscriminatorCheck !== true) {
+ throw new Error('Discriminator "' + name +
+ '" cannot have field with name "' + key + '"');
+ }
+
+ let value = name;
+ if (typeof tiedValue == 'string' && tiedValue.length) {
+ value = tiedValue;
+ }
+
+ function merge(schema, baseSchema) {
+ // Retain original schema before merging base schema
+ schema._baseSchema = baseSchema;
+ if (baseSchema.paths._id &&
+ baseSchema.paths._id.options &&
+ !baseSchema.paths._id.options.auto) {
+ schema.remove('_id');
+ }
+
+ // Find conflicting paths: if something is a path in the base schema
+ // and a nested path in the child schema, overwrite the base schema path.
+ // See gh-6076
+ const baseSchemaPaths = Object.keys(baseSchema.paths);
+ const conflictingPaths = [];
+
+ for (const path of baseSchemaPaths) {
+ if (schema.nested[path]) {
+ conflictingPaths.push(path);
+ continue;
+ }
+
+ if (path.indexOf('.') === -1) {
+ continue;
+ }
+ const sp = path.split('.').slice(0, -1);
+ let cur = '';
+ for (const piece of sp) {
+ cur += (cur.length ? '.' : '') + piece;
+ if (schema.paths[cur] instanceof Mixed ||
+ schema.singleNestedPaths[cur] instanceof Mixed) {
+ conflictingPaths.push(path);
+ }
+ }
+ }
+
+ utils.merge(schema, baseSchema, {
+ isDiscriminatorSchemaMerge: true,
+ omit: { discriminators: true, base: true },
+ omitNested: conflictingPaths.reduce((cur, path) => {
+ cur['tree.' + path] = true;
+ return cur;
+ }, {})
+ });
+
+ // Clean up conflicting paths _after_ merging re: gh-6076
+ for (const conflictingPath of conflictingPaths) {
+ delete schema.paths[conflictingPath];
+ }
+
+ // Rebuild schema models because schemas may have been merged re: #7884
+ schema.childSchemas.forEach(obj => {
+ obj.model.prototype.$__setSchema(obj.schema);
+ });
+
+ const obj = {};
+ obj[key] = {
+ default: value,
+ select: true,
+ set: function(newName) {
+ if (newName === value) {
+ return value;
+ }
+ throw new Error('Can\'t set discriminator key "' + key + '"');
+ },
+ $skipDiscriminatorCheck: true
+ };
+ obj[key][schema.options.typeKey] = existingPath ?
+ existingPath.instance :
+ String;
+ schema.add(obj);
+ schema.discriminatorMapping = { key: key, value: value, isRoot: false };
+
+ if (baseSchema.options.collection) {
+ schema.options.collection = baseSchema.options.collection;
+ }
+
+ const toJSON = schema.options.toJSON;
+ const toObject = schema.options.toObject;
+ const _id = schema.options._id;
+ const id = schema.options.id;
+
+ const keys = Object.keys(schema.options);
+ schema.options.discriminatorKey = baseSchema.options.discriminatorKey;
+
+ for (const _key of keys) {
+ if (!CUSTOMIZABLE_DISCRIMINATOR_OPTIONS[_key]) {
+ // Special case: compiling a model sets `pluralization = true` by default. Avoid throwing an error
+ // for that case. See gh-9238
+ if (_key === 'pluralization' && schema.options[_key] == true && baseSchema.options[_key] == null) {
+ continue;
+ }
+
+ if (!utils.deepEqual(schema.options[_key], baseSchema.options[_key])) {
+ throw new Error('Can\'t customize discriminator option ' + _key +
+ ' (can only modify ' +
+ Object.keys(CUSTOMIZABLE_DISCRIMINATOR_OPTIONS).join(', ') +
+ ')');
+ }
+ }
+ }
+ schema.options = utils.clone(baseSchema.options);
+ if (toJSON) schema.options.toJSON = toJSON;
+ if (toObject) schema.options.toObject = toObject;
+ if (typeof _id !== 'undefined') {
+ schema.options._id = _id;
+ }
+ schema.options.id = id;
+ schema.s.hooks = model.schema.s.hooks.merge(schema.s.hooks);
+
+ schema.plugins = Array.prototype.slice.call(baseSchema.plugins);
+ schema.callQueue = baseSchema.callQueue.concat(schema.callQueue);
+ delete schema._requiredpaths; // reset just in case Schema#requiredPaths() was called on either schema
+ }
+
+ // merges base schema into new discriminator schema and sets new type field.
+ merge(schema, model.schema);
+
+ if (!model.discriminators) {
+ model.discriminators = {};
+ }
+
+ if (!model.schema.discriminatorMapping) {
+ model.schema.discriminatorMapping = { key: key, value: null, isRoot: true };
+ }
+ if (!model.schema.discriminators) {
+ model.schema.discriminators = {};
+ }
+
+ model.schema.discriminators[name] = schema;
+
+ if (model.discriminators[name]) {
+ throw new Error('Discriminator with name "' + name + '" already exists');
+ }
+
+ return schema;
+};
diff --git a/node_modules/mongoose/lib/helpers/once.js b/node_modules/mongoose/lib/helpers/once.js
new file mode 100644
index 0000000..0267579
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/once.js
@@ -0,0 +1,12 @@
+'use strict';
+
+module.exports = function once(fn) {
+ let called = false;
+ return function() {
+ if (called) {
+ return;
+ }
+ called = true;
+ return fn.apply(null, arguments);
+ };
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/parallelLimit.js b/node_modules/mongoose/lib/helpers/parallelLimit.js
new file mode 100644
index 0000000..9b07c02
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/parallelLimit.js
@@ -0,0 +1,55 @@
+'use strict';
+
+module.exports = parallelLimit;
+
+/*!
+ * ignore
+ */
+
+function parallelLimit(fns, limit, callback) {
+ let numInProgress = 0;
+ let numFinished = 0;
+ let error = null;
+
+ if (limit <= 0) {
+ throw new Error('Limit must be positive');
+ }
+
+ if (fns.length === 0) {
+ return callback(null, []);
+ }
+
+ for (let i = 0; i < fns.length && i < limit; ++i) {
+ _start();
+ }
+
+ function _start() {
+ fns[numFinished + numInProgress](_done(numFinished + numInProgress));
+ ++numInProgress;
+ }
+
+ const results = [];
+
+ function _done(index) {
+ return (err, res) => {
+ --numInProgress;
+ ++numFinished;
+
+ if (error != null) {
+ return;
+ }
+ if (err != null) {
+ error = err;
+ return callback(error);
+ }
+
+ results[index] = res;
+
+ if (numFinished === fns.length) {
+ return callback(null, results);
+ } else if (numFinished + numInProgress < fns.length) {
+ _start();
+ }
+ };
+ }
+}
diff --git a/node_modules/mongoose/lib/helpers/populate/SkipPopulateValue.js b/node_modules/mongoose/lib/helpers/populate/SkipPopulateValue.js
new file mode 100644
index 0000000..5d46cfd
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/SkipPopulateValue.js
@@ -0,0 +1,10 @@
+'use strict';
+
+module.exports = function SkipPopulateValue(val) {
+ if (!(this instanceof SkipPopulateValue)) {
+ return new SkipPopulateValue(val);
+ }
+
+ this.val = val;
+ return this;
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/assignRawDocsToIdStructure.js b/node_modules/mongoose/lib/helpers/populate/assignRawDocsToIdStructure.js
new file mode 100644
index 0000000..843c148
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/assignRawDocsToIdStructure.js
@@ -0,0 +1,98 @@
+'use strict';
+
+const leanPopulateMap = require('./leanPopulateMap');
+const modelSymbol = require('../symbols').modelSymbol;
+const utils = require('../../utils');
+
+module.exports = assignRawDocsToIdStructure;
+
+/*!
+ * Assign `vals` returned by mongo query to the `rawIds`
+ * structure returned from utils.getVals() honoring
+ * query sort order if specified by user.
+ *
+ * This can be optimized.
+ *
+ * Rules:
+ *
+ * if the value of the path is not an array, use findOne rules, else find.
+ * for findOne the results are assigned directly to doc path (including null results).
+ * for find, if user specified sort order, results are assigned directly
+ * else documents are put back in original order of array if found in results
+ *
+ * @param {Array} rawIds
+ * @param {Array} vals
+ * @param {Boolean} sort
+ * @api private
+ */
+
+function assignRawDocsToIdStructure(rawIds, resultDocs, resultOrder, options, recursed) {
+ // honor user specified sort order
+ const newOrder = [];
+ const sorting = options.sort && rawIds.length > 1;
+ const nullIfNotFound = options.$nullIfNotFound;
+ let doc;
+ let sid;
+ let id;
+
+ for (let i = 0; i < rawIds.length; ++i) {
+ id = rawIds[i];
+
+ if (Array.isArray(id)) {
+ // handle [ [id0, id2], [id3] ]
+ assignRawDocsToIdStructure(id, resultDocs, resultOrder, options, true);
+ newOrder.push(id);
+ continue;
+ }
+
+ if (id === null && !sorting) {
+ // keep nulls for findOne unless sorting, which always
+ // removes them (backward compat)
+ newOrder.push(id);
+ continue;
+ }
+
+ sid = String(id);
+
+ doc = resultDocs[sid];
+ // If user wants separate copies of same doc, use this option
+ if (options.clone && doc != null) {
+ if (options.lean) {
+ const _model = leanPopulateMap.get(doc);
+ doc = utils.clone(doc);
+ leanPopulateMap.set(doc, _model);
+ } else {
+ doc = doc.constructor.hydrate(doc._doc);
+ }
+ }
+
+ if (recursed) {
+ if (doc) {
+ if (sorting) {
+ newOrder[resultOrder[sid]] = doc;
+ } else {
+ newOrder.push(doc);
+ }
+ } else if (id != null && id[modelSymbol] != null) {
+ newOrder.push(id);
+ } else {
+ newOrder.push(options.retainNullValues || nullIfNotFound ? null : id);
+ }
+ } else {
+ // apply findOne behavior - if document in results, assign, else assign null
+ newOrder[i] = doc || null;
+ }
+ }
+
+ rawIds.length = 0;
+ if (newOrder.length) {
+ // reassign the documents based on corrected order
+
+ // forEach skips over sparse entries in arrays so we
+ // can safely use this to our advantage dealing with sorted
+ // result sets too.
+ newOrder.forEach(function(doc, i) {
+ rawIds[i] = doc;
+ });
+ }
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/assignVals.js b/node_modules/mongoose/lib/helpers/populate/assignVals.js
new file mode 100644
index 0000000..9fd51d8
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/assignVals.js
@@ -0,0 +1,274 @@
+'use strict';
+
+const SkipPopulateValue = require('./SkipPopulateValue');
+const assignRawDocsToIdStructure = require('./assignRawDocsToIdStructure');
+const get = require('../get');
+const getVirtual = require('./getVirtual');
+const leanPopulateMap = require('./leanPopulateMap');
+const lookupLocalFields = require('./lookupLocalFields');
+const mpath = require('mpath');
+const sift = require('sift').default;
+const utils = require('../../utils');
+
+module.exports = function assignVals(o) {
+ // Options that aren't explicitly listed in `populateOptions`
+ const userOptions = get(o, 'allOptions.options.options');
+ // `o.options` contains options explicitly listed in `populateOptions`, like
+ // `match` and `limit`.
+ const populateOptions = Object.assign({}, o.options, userOptions, {
+ justOne: o.justOne
+ });
+ populateOptions.$nullIfNotFound = o.isVirtual;
+ const populatedModel = o.populatedModel;
+
+ const originalIds = [].concat(o.rawIds);
+
+ // replace the original ids in our intermediate _ids structure
+ // with the documents found by query
+ assignRawDocsToIdStructure(o.rawIds, o.rawDocs, o.rawOrder, populateOptions);
+
+ // now update the original documents being populated using the
+ // result structure that contains real documents.
+ const docs = o.docs;
+ const rawIds = o.rawIds;
+ const options = o.options;
+ const count = o.count && o.isVirtual;
+
+ function setValue(val) {
+ if (count) {
+ return val;
+ }
+ if (val instanceof SkipPopulateValue) {
+ return val.val;
+ }
+
+ if (o.justOne === true && Array.isArray(val)) {
+ // Might be an embedded discriminator (re: gh-9244) with multiple models, so make sure to pick the right
+ // model before assigning.
+ const ret = [];
+ for (const doc of val) {
+ const _docPopulatedModel = leanPopulateMap.get(doc);
+ if (_docPopulatedModel == null || _docPopulatedModel === populatedModel) {
+ ret.push(doc);
+ }
+ }
+ // Since we don't want to have to create a new mongoosearray, make sure to
+ // modify the array in place
+ while (val.length > ret.length) {
+ Array.prototype.pop.apply(val, []);
+ }
+ for (let i = 0; i < ret.length; ++i) {
+ val[i] = ret[i];
+ }
+
+ return valueFilter(val[0], options, populateOptions, populatedModel);
+ } else if (o.justOne === false && !Array.isArray(val)) {
+ return valueFilter([val], options, populateOptions, populatedModel);
+ }
+ return valueFilter(val, options, populateOptions, populatedModel);
+ }
+
+ for (let i = 0; i < docs.length; ++i) {
+ const existingVal = mpath.get(o.path, docs[i], lookupLocalFields);
+ if (existingVal == null && !getVirtual(o.originalModel.schema, o.path)) {
+ continue;
+ }
+
+ let valueToSet;
+ if (count) {
+ valueToSet = numDocs(rawIds[i]);
+ } else if (Array.isArray(o.match)) {
+ valueToSet = Array.isArray(rawIds[i]) ?
+ sift(o.match[i], rawIds[i]) :
+ sift(o.match[i], [rawIds[i]])[0];
+ } else {
+ valueToSet = rawIds[i];
+ }
+
+ // If we're populating a map, the existing value will be an object, so
+ // we need to transform again
+ const originalSchema = o.originalModel.schema;
+ const isDoc = get(docs[i], '$__', null) != null;
+ let isMap = isDoc ?
+ existingVal instanceof Map :
+ utils.isPOJO(existingVal);
+ // If we pass the first check, also make sure the local field's schematype
+ // is map (re: gh-6460)
+ isMap = isMap && get(originalSchema._getSchema(o.path), '$isSchemaMap');
+ if (!o.isVirtual && isMap) {
+ const _keys = existingVal instanceof Map ?
+ Array.from(existingVal.keys()) :
+ Object.keys(existingVal);
+ valueToSet = valueToSet.reduce((cur, v, i) => {
+ cur.set(_keys[i], v);
+ return cur;
+ }, new Map());
+ }
+
+ if (isDoc && Array.isArray(valueToSet)) {
+ for (const val of valueToSet) {
+ if (val != null && val.$__ != null) {
+ val.$__.parent = docs[i];
+ }
+ }
+ } else if (isDoc && valueToSet != null && valueToSet.$__ != null) {
+ valueToSet.$__.parent = docs[i];
+ }
+
+ if (o.isVirtual && isDoc) {
+ docs[i].populated(o.path, o.justOne ? originalIds[0] : originalIds, o.allOptions);
+ // If virtual populate and doc is already init-ed, need to walk through
+ // the actual doc to set rather than setting `_doc` directly
+ mpath.set(o.path, valueToSet, docs[i], setValue);
+ continue;
+ }
+
+ const parts = o.path.split('.');
+ let cur = docs[i];
+ const curPath = parts[0];
+ for (let j = 0; j < parts.length - 1; ++j) {
+ // If we get to an array with a dotted path, like `arr.foo`, don't set
+ // `foo` on the array.
+ if (Array.isArray(cur) && !utils.isArrayIndex(parts[j])) {
+ break;
+ }
+
+ if (parts[j] === '$*') {
+ break;
+ }
+
+ if (cur[parts[j]] == null) {
+ // If nothing to set, avoid creating an unnecessary array. Otherwise
+ // we'll end up with a single doc in the array with only defaults.
+ // See gh-8342, gh-8455
+ const schematype = originalSchema._getSchema(curPath);
+ if (valueToSet == null && schematype != null && schematype.$isMongooseArray) {
+ return;
+ }
+ cur[parts[j]] = {};
+ }
+ cur = cur[parts[j]];
+ // If the property in MongoDB is a primitive, we won't be able to populate
+ // the nested path, so skip it. See gh-7545
+ if (typeof cur !== 'object') {
+ return;
+ }
+ }
+ if (docs[i].$__) {
+ docs[i].populated(o.path, o.allIds[i], o.allOptions);
+ }
+
+ // If lean, need to check that each individual virtual respects
+ // `justOne`, because you may have a populated virtual with `justOne`
+ // underneath an array. See gh-6867
+ mpath.set(o.path, valueToSet, docs[i], lookupLocalFields, setValue, false);
+ }
+};
+
+function numDocs(v) {
+ if (Array.isArray(v)) {
+ // If setting underneath an array of populated subdocs, we may have an
+ // array of arrays. See gh-7573
+ if (v.some(el => Array.isArray(el))) {
+ return v.map(el => numDocs(el));
+ }
+ return v.length;
+ }
+ return v == null ? 0 : 1;
+}
+
+/*!
+ * 1) Apply backwards compatible find/findOne behavior to sub documents
+ *
+ * find logic:
+ * a) filter out non-documents
+ * b) remove _id from sub docs when user specified
+ *
+ * findOne
+ * a) if no doc found, set to null
+ * b) remove _id from sub docs when user specified
+ *
+ * 2) Remove _ids when specified by users query.
+ *
+ * background:
+ * _ids are left in the query even when user excludes them so
+ * that population mapping can occur.
+ */
+
+function valueFilter(val, assignmentOpts, populateOptions) {
+ if (Array.isArray(val)) {
+ // find logic
+ const ret = [];
+ const numValues = val.length;
+ for (let i = 0; i < numValues; ++i) {
+ const subdoc = val[i];
+ if (!isPopulatedObject(subdoc) && (!populateOptions.retainNullValues || subdoc != null)) {
+ continue;
+ }
+ maybeRemoveId(subdoc, assignmentOpts);
+ ret.push(subdoc);
+ if (assignmentOpts.originalLimit &&
+ ret.length >= assignmentOpts.originalLimit) {
+ break;
+ }
+ }
+
+ // Since we don't want to have to create a new mongoosearray, make sure to
+ // modify the array in place
+ while (val.length > ret.length) {
+ Array.prototype.pop.apply(val, []);
+ }
+ for (let i = 0; i < ret.length; ++i) {
+ val[i] = ret[i];
+ }
+ return val;
+ }
+
+ // findOne
+ if (isPopulatedObject(val)) {
+ maybeRemoveId(val, assignmentOpts);
+ return val;
+ }
+
+ if (val instanceof Map) {
+ return val;
+ }
+
+ if (populateOptions.justOne === true) {
+ return (val == null ? val : null);
+ }
+ if (populateOptions.justOne === false) {
+ return [];
+ }
+ return val;
+}
+
+/*!
+ * Remove _id from `subdoc` if user specified "lean" query option
+ */
+
+function maybeRemoveId(subdoc, assignmentOpts) {
+ if (subdoc != null && assignmentOpts.excludeId) {
+ if (typeof subdoc.$__setValue === 'function') {
+ delete subdoc._doc._id;
+ } else {
+ delete subdoc._id;
+ }
+ }
+}
+
+/*!
+ * Determine if `obj` is something we can set a populated path to. Can be a
+ * document, a lean document, or an array/map that contains docs.
+ */
+
+function isPopulatedObject(obj) {
+ if (obj == null) {
+ return false;
+ }
+
+ return Array.isArray(obj) ||
+ obj.$isMongooseMap ||
+ obj.$__ != null ||
+ leanPopulateMap.has(obj);
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/getModelsMapForPopulate.js b/node_modules/mongoose/lib/helpers/populate/getModelsMapForPopulate.js
new file mode 100644
index 0000000..66baf19
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/getModelsMapForPopulate.js
@@ -0,0 +1,522 @@
+'use strict';
+
+const MongooseError = require('../../error/index');
+const SkipPopulateValue = require('./SkipPopulateValue');
+const get = require('../get');
+const getDiscriminatorByValue = require('../discriminator/getDiscriminatorByValue');
+const isPathExcluded = require('../projection/isPathExcluded');
+const getSchemaTypes = require('./getSchemaTypes');
+const getVirtual = require('./getVirtual');
+const lookupLocalFields = require('./lookupLocalFields');
+const mpath = require('mpath');
+const normalizeRefPath = require('./normalizeRefPath');
+const util = require('util');
+const utils = require('../../utils');
+
+const modelSymbol = require('../symbols').modelSymbol;
+const populateModelSymbol = require('../symbols').populateModelSymbol;
+const schemaMixedSymbol = require('../../schema/symbols').schemaMixedSymbol;
+
+module.exports = function getModelsMapForPopulate(model, docs, options) {
+ let i;
+ let doc;
+ const len = docs.length;
+ const available = {};
+ const map = [];
+ const modelNameFromQuery = options.model && options.model.modelName || options.model;
+ let schema;
+ let refPath;
+ let Model;
+ let currentOptions;
+ let modelNames;
+ let modelName;
+ let modelForFindSchema;
+
+ const originalModel = options.model;
+ let isVirtual = false;
+ const modelSchema = model.schema;
+
+ let allSchemaTypes = getSchemaTypes(modelSchema, null, options.path);
+ allSchemaTypes = Array.isArray(allSchemaTypes) ? allSchemaTypes : [allSchemaTypes].filter(v => v != null);
+ const _firstWithRefPath = allSchemaTypes.find(schematype => get(schematype, 'options.refPath', null) != null);
+
+ for (i = 0; i < len; i++) {
+ doc = docs[i];
+ let justOne = null;
+
+ schema = getSchemaTypes(modelSchema, doc, options.path);
+ // Special case: populating a path that's a DocumentArray unless
+ // there's an explicit `ref` or `refPath` re: gh-8946
+ if (schema != null &&
+ schema.$isMongooseDocumentArray &&
+ schema.options.ref == null &&
+ schema.options.refPath == null) {
+ continue;
+ }
+ // Populating a nested path should always be a no-op re: #9073.
+ // People shouldn't do this, but apparently they do.
+ if (modelSchema.nested[options.path]) {
+ continue;
+ }
+ const isUnderneathDocArray = schema && schema.$isUnderneathDocArray;
+ if (isUnderneathDocArray && get(options, 'options.sort') != null) {
+ return new MongooseError('Cannot populate with `sort` on path ' + options.path +
+ ' because it is a subproperty of a document array');
+ }
+
+ modelNames = null;
+ let isRefPath = !!_firstWithRefPath;
+ let normalizedRefPath = _firstWithRefPath ? get(_firstWithRefPath, 'options.refPath', null) : null;
+
+ if (Array.isArray(schema)) {
+ const schemasArray = schema;
+ for (const _schema of schemasArray) {
+ let _modelNames;
+ let res;
+ try {
+ res = _getModelNames(doc, _schema);
+ _modelNames = res.modelNames;
+ isRefPath = isRefPath || res.isRefPath;
+ normalizedRefPath = normalizeRefPath(normalizedRefPath, doc, options.path) ||
+ res.refPath;
+ justOne = res.justOne;
+ } catch (error) {
+ return error;
+ }
+
+ if (isRefPath && !res.isRefPath) {
+ continue;
+ }
+ if (!_modelNames) {
+ continue;
+ }
+ modelNames = modelNames || [];
+ for (const modelName of _modelNames) {
+ if (modelNames.indexOf(modelName) === -1) {
+ modelNames.push(modelName);
+ }
+ }
+ }
+ } else {
+ try {
+ const res = _getModelNames(doc, schema);
+ modelNames = res.modelNames;
+ isRefPath = res.isRefPath;
+ normalizedRefPath = res.refPath;
+ justOne = res.justOne;
+ } catch (error) {
+ return error;
+ }
+
+ if (!modelNames) {
+ continue;
+ }
+ }
+
+ const _virtualRes = getVirtual(model.schema, options.path);
+ const virtual = _virtualRes == null ? null : _virtualRes.virtual;
+
+ let localField;
+ let count = false;
+ if (virtual && virtual.options) {
+ const virtualPrefix = _virtualRes.nestedSchemaPath ?
+ _virtualRes.nestedSchemaPath + '.' : '';
+ if (typeof virtual.options.localField === 'function') {
+ localField = virtualPrefix + virtual.options.localField.call(doc, doc);
+ } else {
+ localField = virtualPrefix + virtual.options.localField;
+ }
+ count = virtual.options.count;
+
+ if (virtual.options.skip != null && !options.hasOwnProperty('skip')) {
+ options.skip = virtual.options.skip;
+ }
+ if (virtual.options.limit != null && !options.hasOwnProperty('limit')) {
+ options.limit = virtual.options.limit;
+ }
+ if (virtual.options.perDocumentLimit != null && !options.hasOwnProperty('perDocumentLimit')) {
+ options.perDocumentLimit = virtual.options.perDocumentLimit;
+ }
+ } else {
+ localField = options.path;
+ }
+ let foreignField = virtual && virtual.options ?
+ virtual.options.foreignField :
+ '_id';
+
+ // `justOne = null` means we don't know from the schema whether the end
+ // result should be an array or a single doc. This can result from
+ // populating a POJO using `Model.populate()`
+ if ('justOne' in options && options.justOne !== void 0) {
+ justOne = options.justOne;
+ } else if (virtual && virtual.options && virtual.options.refPath) {
+ const normalizedRefPath =
+ normalizeRefPath(virtual.options.refPath, doc, options.path);
+ justOne = !!virtual.options.justOne;
+ isVirtual = true;
+ const refValue = utils.getValue(normalizedRefPath, doc);
+ modelNames = Array.isArray(refValue) ? refValue : [refValue];
+ } else if (virtual && virtual.options && virtual.options.ref) {
+ let normalizedRef;
+ if (typeof virtual.options.ref === 'function') {
+ normalizedRef = virtual.options.ref.call(doc, doc);
+ } else {
+ normalizedRef = virtual.options.ref;
+ }
+ justOne = !!virtual.options.justOne;
+ isVirtual = true;
+ if (!modelNames) {
+ modelNames = [].concat(normalizedRef);
+ }
+ } else if (schema && !schema[schemaMixedSymbol]) {
+ // Skip Mixed types because we explicitly don't do casting on those.
+ justOne = Array.isArray(schema) ?
+ schema.every(schema => !schema.$isMongooseArray) :
+ !schema.$isMongooseArray;
+ }
+
+ if (!modelNames) {
+ continue;
+ }
+
+ if (virtual && (!localField || !foreignField)) {
+ return new MongooseError('If you are populating a virtual, you must set the ' +
+ 'localField and foreignField options');
+ }
+
+ options.isVirtual = isVirtual;
+ options.virtual = virtual;
+ if (typeof localField === 'function') {
+ localField = localField.call(doc, doc);
+ }
+ if (typeof foreignField === 'function') {
+ foreignField = foreignField.call(doc);
+ }
+
+ const localFieldPathType = modelSchema._getPathType(localField);
+ const localFieldPath = localFieldPathType === 'real' ? modelSchema.path(localField) : localFieldPathType.schema;
+ const localFieldGetters = localFieldPath && localFieldPath.getters ? localFieldPath.getters : [];
+ let ret;
+
+ const _populateOptions = get(options, 'options', {});
+
+ const getters = 'getters' in _populateOptions ?
+ _populateOptions.getters :
+ options.isVirtual && get(virtual, 'options.getters', false);
+ if (localFieldGetters.length > 0 && getters) {
+ const hydratedDoc = (doc.$__ != null) ? doc : model.hydrate(doc);
+ const localFieldValue = mpath.get(localField, doc, lookupLocalFields);
+ if (Array.isArray(localFieldValue)) {
+ const localFieldHydratedValue = mpath.get(localField.split('.').slice(0, -1), hydratedDoc, lookupLocalFields);
+ ret = localFieldValue.map((localFieldArrVal, localFieldArrIndex) =>
+ localFieldPath.applyGetters(localFieldArrVal, localFieldHydratedValue[localFieldArrIndex]));
+ } else {
+ ret = localFieldPath.applyGetters(localFieldValue, hydratedDoc);
+ }
+ } else {
+ ret = convertTo_id(mpath.get(localField, doc, lookupLocalFields), schema);
+ }
+
+ const id = String(utils.getValue(foreignField, doc));
+ options._docs[id] = Array.isArray(ret) ? ret.slice() : ret;
+
+ let match = get(options, 'match', null) ||
+ get(currentOptions, 'match', null) ||
+ get(options, 'virtual.options.match', null) ||
+ get(options, 'virtual.options.options.match', null);
+
+ const hasMatchFunction = typeof match === 'function';
+ if (hasMatchFunction) {
+ match = match.call(doc, doc);
+ }
+
+ // Re: gh-8452. Embedded discriminators may not have `refPath`, so clear
+ // out embedded discriminator docs that don't have a `refPath` on the
+ // populated path.
+ if (isRefPath && normalizedRefPath != null) {
+ const pieces = normalizedRefPath.split('.');
+ let cur = '';
+ for (let j = 0; j < pieces.length; ++j) {
+ const piece = pieces[j];
+ cur = cur + (cur.length === 0 ? '' : '.') + piece;
+ const schematype = modelSchema.path(cur);
+ if (schematype != null &&
+ schematype.$isMongooseArray &&
+ schematype.caster.discriminators != null &&
+ Object.keys(schematype.caster.discriminators).length > 0) {
+ const subdocs = utils.getValue(cur, doc);
+ const remnant = options.path.substr(cur.length + 1);
+ const discriminatorKey = schematype.caster.schema.options.discriminatorKey;
+ modelNames = [];
+ for (const subdoc of subdocs) {
+ const discriminatorName = utils.getValue(discriminatorKey, subdoc);
+ const discriminator = schematype.caster.discriminators[discriminatorName];
+ const discriminatorSchema = discriminator && discriminator.schema;
+ if (discriminatorSchema == null) {
+ continue;
+ }
+ const _path = discriminatorSchema.path(remnant);
+ if (_path == null || _path.options.refPath == null) {
+ const docValue = utils.getValue(localField.substr(cur.length + 1), subdoc);
+ ret = ret.map(v => v === docValue ? SkipPopulateValue(v) : v);
+ continue;
+ }
+ const modelName = utils.getValue(pieces.slice(j + 1).join('.'), subdoc);
+ modelNames.push(modelName);
+ }
+ }
+ }
+ }
+
+ let k = modelNames.length;
+ while (k--) {
+ modelName = modelNames[k];
+ if (modelName == null) {
+ continue;
+ }
+
+ // `PopulateOptions#connection`: if the model is passed as a string, the
+ // connection matters because different connections have different models.
+ const connection = options.connection != null ? options.connection : model.db;
+
+ try {
+ Model = originalModel && originalModel[modelSymbol] ?
+ originalModel :
+ modelName[modelSymbol] ? modelName : connection.model(modelName);
+ } catch (error) {
+ // If `ret` is undefined, we'll add an empty entry to modelsMap. We shouldn't
+ // execute a query, but it is necessary to make sure `justOne` gets handled
+ // correctly for setting an empty array (see gh-8455)
+ if (ret !== undefined) {
+ return error;
+ }
+ }
+
+ let ids = ret;
+ const flat = Array.isArray(ret) ? utils.array.flatten(ret) : [];
+
+ if (isRefPath && Array.isArray(ret) && flat.length === modelNames.length) {
+ ids = flat.filter((val, i) => modelNames[i] === modelName);
+ }
+
+ if (!available[modelName] || currentOptions.perDocumentLimit != null || get(currentOptions, 'options.perDocumentLimit') != null) {
+ currentOptions = {
+ model: Model
+ };
+
+ if (isVirtual && get(virtual, 'options.options')) {
+ currentOptions.options = utils.clone(virtual.options.options);
+ }
+ utils.merge(currentOptions, options);
+
+ // Used internally for checking what model was used to populate this
+ // path.
+ options[populateModelSymbol] = Model;
+
+ available[modelName] = {
+ model: Model,
+ options: currentOptions,
+ match: hasMatchFunction ? [match] : match,
+ docs: [doc],
+ ids: [ids],
+ allIds: [ret],
+ localField: new Set([localField]),
+ foreignField: new Set([foreignField]),
+ justOne: justOne,
+ isVirtual: isVirtual,
+ virtual: virtual,
+ count: count,
+ [populateModelSymbol]: Model
+ };
+ map.push(available[modelName]);
+ } else {
+ available[modelName].localField.add(localField);
+ available[modelName].foreignField.add(foreignField);
+ available[modelName].docs.push(doc);
+ available[modelName].ids.push(ids);
+ available[modelName].allIds.push(ret);
+ if (hasMatchFunction) {
+ available[modelName].match.push(match);
+ }
+ }
+ }
+ }
+
+ return map;
+
+ function _getModelNames(doc, schema) {
+ let modelNames;
+ let discriminatorKey;
+ let isRefPath = false;
+ let justOne = null;
+
+ if (schema && schema.caster) {
+ schema = schema.caster;
+ }
+ if (schema && schema.$isSchemaMap) {
+ schema = schema.$__schemaType;
+ }
+
+ if (!schema && model.discriminators) {
+ discriminatorKey = model.schema.discriminatorMapping.key;
+ }
+
+ refPath = schema && schema.options && schema.options.refPath;
+
+ const normalizedRefPath = normalizeRefPath(refPath, doc, options.path);
+
+ if (modelNameFromQuery) {
+ modelNames = [modelNameFromQuery]; // query options
+ } else if (normalizedRefPath) {
+ if (options._queryProjection != null && isPathExcluded(options._queryProjection, normalizedRefPath)) {
+ throw new MongooseError('refPath `' + normalizedRefPath +
+ '` must not be excluded in projection, got ' +
+ util.inspect(options._queryProjection));
+ }
+
+ if (modelSchema.virtuals.hasOwnProperty(normalizedRefPath) && doc.$__ == null) {
+ modelNames = [modelSchema.virtuals[normalizedRefPath].applyGetters(void 0, doc)];
+ } else {
+ modelNames = utils.getValue(normalizedRefPath, doc);
+ }
+
+ if (Array.isArray(modelNames)) {
+ modelNames = utils.array.flatten(modelNames);
+ }
+
+ isRefPath = true;
+ } else {
+ let modelForCurrentDoc = model;
+ let schemaForCurrentDoc;
+
+ if (!schema && discriminatorKey) {
+ modelForFindSchema = utils.getValue(discriminatorKey, doc);
+ if (modelForFindSchema) {
+ // `modelForFindSchema` is the discriminator value, so we might need
+ // find the discriminated model name
+ const discriminatorModel = getDiscriminatorByValue(model, modelForFindSchema);
+ if (discriminatorModel != null) {
+ modelForCurrentDoc = discriminatorModel;
+ } else {
+ try {
+ modelForCurrentDoc = model.db.model(modelForFindSchema);
+ } catch (error) {
+ return error;
+ }
+ }
+
+ schemaForCurrentDoc = modelForCurrentDoc.schema._getSchema(options.path);
+
+ if (schemaForCurrentDoc && schemaForCurrentDoc.caster) {
+ schemaForCurrentDoc = schemaForCurrentDoc.caster;
+ }
+ }
+ } else {
+ schemaForCurrentDoc = schema;
+ }
+ const _virtualRes = getVirtual(modelForCurrentDoc.schema, options.path);
+ const virtual = _virtualRes == null ? null : _virtualRes.virtual;
+
+ if (schemaForCurrentDoc != null) {
+ justOne = !schemaForCurrentDoc.$isMongooseArray && !schemaForCurrentDoc._arrayPath;
+ }
+
+ let ref;
+ let refPath;
+
+ if ((ref = get(schemaForCurrentDoc, 'options.ref')) != null) {
+ ref = handleRefFunction(ref, doc);
+ modelNames = [ref];
+ } else if ((ref = get(virtual, 'options.ref')) != null) {
+ ref = handleRefFunction(ref, doc);
+
+ // When referencing nested arrays, the ref should be an Array
+ // of modelNames.
+ if (Array.isArray(ref)) {
+ modelNames = ref;
+ } else {
+ modelNames = [ref];
+ }
+
+ isVirtual = true;
+ } else if ((refPath = get(schemaForCurrentDoc, 'options.refPath')) != null) {
+ isRefPath = true;
+ refPath = normalizeRefPath(refPath, doc, options.path);
+ modelNames = utils.getValue(refPath, doc);
+ if (Array.isArray(modelNames)) {
+ modelNames = utils.array.flatten(modelNames);
+ }
+ } else {
+ // We may have a discriminator, in which case we don't want to
+ // populate using the base model by default
+ modelNames = discriminatorKey ? null : [model.modelName];
+ }
+ }
+
+ if (!modelNames) {
+ return { modelNames: modelNames, isRefPath: isRefPath, refPath: normalizedRefPath, justOne: justOne };
+ }
+
+ if (!Array.isArray(modelNames)) {
+ modelNames = [modelNames];
+ }
+
+ return { modelNames: modelNames, isRefPath: isRefPath, refPath: normalizedRefPath, justOne: justOne };
+ }
+};
+
+/*!
+ * ignore
+ */
+
+function handleRefFunction(ref, doc) {
+ if (typeof ref === 'function' && !ref[modelSymbol]) {
+ return ref.call(doc, doc);
+ }
+ return ref;
+}
+
+/*!
+ * Retrieve the _id of `val` if a Document or Array of Documents.
+ *
+ * @param {Array|Document|Any} val
+ * @return {Array|Document|Any}
+ */
+
+function convertTo_id(val, schema) {
+ if (val != null && val.$__ != null) return val._id;
+
+ if (Array.isArray(val)) {
+ for (let i = 0; i < val.length; ++i) {
+ if (val[i] != null && val[i].$__ != null) {
+ val[i] = val[i]._id;
+ }
+ }
+ if (val.isMongooseArray && val.$schema()) {
+ return val.$schema().cast(val, val.$parent());
+ }
+
+ return [].concat(val);
+ }
+
+ // `populate('map')` may be an object if populating on a doc that hasn't
+ // been hydrated yet
+ if (val != null &&
+ val.constructor.name === 'Object' &&
+ // The intent here is we should only flatten the object if we expect
+ // to get a Map in the end. Avoid doing this for mixed types.
+ (schema == null || schema[schemaMixedSymbol] == null)) {
+ const ret = [];
+ for (const key of Object.keys(val)) {
+ ret.push(val[key]);
+ }
+ return ret;
+ }
+ // If doc has already been hydrated, e.g. `doc.populate('map').execPopulate()`
+ // then `val` will already be a map
+ if (val instanceof Map) {
+ return Array.from(val.values());
+ }
+
+ return val;
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/getSchemaTypes.js b/node_modules/mongoose/lib/helpers/populate/getSchemaTypes.js
new file mode 100644
index 0000000..15660df
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/getSchemaTypes.js
@@ -0,0 +1,198 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+const Mixed = require('../../schema/mixed');
+const get = require('../get');
+const leanPopulateMap = require('./leanPopulateMap');
+const mpath = require('mpath');
+
+const populateModelSymbol = require('../symbols').populateModelSymbol;
+
+/*!
+ * @param {Schema} schema
+ * @param {Object} doc POJO
+ * @param {string} path
+ */
+
+module.exports = function getSchemaTypes(schema, doc, path) {
+ const pathschema = schema.path(path);
+ const topLevelDoc = doc;
+
+ if (pathschema) {
+ return pathschema;
+ }
+
+ function search(parts, schema, subdoc, nestedPath) {
+ let p = parts.length + 1;
+ let foundschema;
+ let trypath;
+
+ while (p--) {
+ trypath = parts.slice(0, p).join('.');
+ foundschema = schema.path(trypath);
+
+ if (foundschema == null) {
+ continue;
+ }
+
+ if (foundschema.caster) {
+ // array of Mixed?
+ if (foundschema.caster instanceof Mixed) {
+ return foundschema.caster;
+ }
+
+ let schemas = null;
+ if (foundschema.schema != null && foundschema.schema.discriminators != null) {
+ const discriminators = foundschema.schema.discriminators;
+ const discriminatorKeyPath = trypath + '.' +
+ foundschema.schema.options.discriminatorKey;
+ const keys = subdoc ? mpath.get(discriminatorKeyPath, subdoc) || [] : [];
+ schemas = Object.keys(discriminators).
+ reduce(function(cur, discriminator) {
+ if (doc == null || keys.indexOf(discriminator) !== -1) {
+ cur.push(discriminators[discriminator]);
+ }
+ return cur;
+ }, []);
+ }
+
+ // Now that we found the array, we need to check if there
+ // are remaining document paths to look up for casting.
+ // Also we need to handle array.$.path since schema.path
+ // doesn't work for that.
+ // If there is no foundschema.schema we are dealing with
+ // a path like array.$
+ if (p !== parts.length && foundschema.schema) {
+ let ret;
+ if (parts[p] === '$') {
+ if (p + 1 === parts.length) {
+ // comments.$
+ return foundschema;
+ }
+ // comments.$.comments.$.title
+ ret = search(
+ parts.slice(p + 1),
+ schema,
+ subdoc ? mpath.get(trypath, subdoc) : null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+ if (ret) {
+ ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
+ !foundschema.schema.$isSingleNested;
+ }
+ return ret;
+ }
+
+ if (schemas != null && schemas.length > 0) {
+ ret = [];
+ for (const schema of schemas) {
+ const _ret = search(
+ parts.slice(p),
+ schema,
+ subdoc ? mpath.get(trypath, subdoc) : null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+ if (_ret != null) {
+ _ret.$isUnderneathDocArray = _ret.$isUnderneathDocArray ||
+ !foundschema.schema.$isSingleNested;
+ if (_ret.$isUnderneathDocArray) {
+ ret.$isUnderneathDocArray = true;
+ }
+ ret.push(_ret);
+ }
+ }
+ return ret;
+ } else {
+ ret = search(
+ parts.slice(p),
+ foundschema.schema,
+ subdoc ? mpath.get(trypath, subdoc) : null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+
+ if (ret) {
+ ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
+ !foundschema.schema.$isSingleNested;
+ }
+
+ return ret;
+ }
+ } else if (p !== parts.length &&
+ foundschema.$isMongooseArray &&
+ foundschema.casterConstructor.$isMongooseArray) {
+ // Nested arrays. Drill down to the bottom of the nested array.
+ // Ignore discriminators.
+ let type = foundschema;
+ while (type.$isMongooseArray && !type.$isMongooseDocumentArray) {
+ type = type.casterConstructor;
+ }
+ return search(
+ parts.slice(p),
+ type.schema,
+ null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+ }
+ }
+
+ const fullPath = nestedPath.concat([trypath]).join('.');
+ if (topLevelDoc != null && topLevelDoc.$__ && topLevelDoc.populated(fullPath) && p < parts.length) {
+ const model = doc.$__.populated[fullPath].options[populateModelSymbol];
+ if (model != null) {
+ const ret = search(
+ parts.slice(p),
+ model.schema,
+ subdoc ? mpath.get(trypath, subdoc) : null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+
+ if (ret) {
+ ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
+ !model.schema.$isSingleNested;
+ }
+
+ return ret;
+ }
+ }
+
+ const _val = get(topLevelDoc, trypath);
+ if (_val != null) {
+ const model = Array.isArray(_val) && _val.length > 0 ?
+ leanPopulateMap.get(_val[0]) :
+ leanPopulateMap.get(_val);
+ // Populated using lean, `leanPopulateMap` value is the foreign model
+ const schema = model != null ? model.schema : null;
+ if (schema != null) {
+ const ret = search(
+ parts.slice(p),
+ schema,
+ subdoc ? mpath.get(trypath, subdoc) : null,
+ nestedPath.concat(parts.slice(0, p))
+ );
+
+ if (ret) {
+ ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
+ !schema.$isSingleNested;
+ }
+
+ return ret;
+ }
+ }
+
+ return foundschema;
+ }
+ }
+
+ // look for arrays
+ const parts = path.split('.');
+ for (let i = 0; i < parts.length; ++i) {
+ if (parts[i] === '$') {
+ // Re: gh-5628, because `schema.path()` doesn't take $ into account.
+ parts[i] = '0';
+ }
+ }
+ return search(parts, schema, doc, []);
+};
diff --git a/node_modules/mongoose/lib/helpers/populate/getVirtual.js b/node_modules/mongoose/lib/helpers/populate/getVirtual.js
new file mode 100644
index 0000000..fc1641d
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/getVirtual.js
@@ -0,0 +1,72 @@
+'use strict';
+
+module.exports = getVirtual;
+
+/*!
+ * ignore
+ */
+
+function getVirtual(schema, name) {
+ if (schema.virtuals[name]) {
+ return { virtual: schema.virtuals[name], path: void 0 };
+ }
+
+ const parts = name.split('.');
+ let cur = '';
+ let nestedSchemaPath = '';
+ for (let i = 0; i < parts.length; ++i) {
+ cur += (cur.length > 0 ? '.' : '') + parts[i];
+ if (schema.virtuals[cur]) {
+ if (i === parts.length - 1) {
+ return { virtual: schema.virtuals[cur], path: nestedSchemaPath };
+ }
+ continue;
+ }
+
+ if (schema.nested[cur]) {
+ continue;
+ }
+
+ if (schema.paths[cur] && schema.paths[cur].schema) {
+ schema = schema.paths[cur].schema;
+ const rest = parts.slice(i + 1).join('.');
+
+ if (schema.virtuals[rest]) {
+ if (i === parts.length - 2) {
+ return {
+ virtual: schema.virtuals[rest],
+ nestedSchemaPath: [nestedSchemaPath, cur].filter(v => !!v).join('.')
+ };
+ }
+ continue;
+ }
+
+ if (i + 1 < parts.length && schema.discriminators) {
+ for (const key of Object.keys(schema.discriminators)) {
+ const res = getVirtual(schema.discriminators[key], rest);
+ if (res != null) {
+ const _path = [nestedSchemaPath, cur, res.nestedSchemaPath].
+ filter(v => !!v).join('.');
+ return {
+ virtual: res.virtual,
+ nestedSchemaPath: _path
+ };
+ }
+ }
+ }
+
+ nestedSchemaPath += (nestedSchemaPath.length > 0 ? '.' : '') + cur;
+ cur = '';
+ continue;
+ }
+
+ if (schema.discriminators) {
+ for (const discriminatorKey of Object.keys(schema.discriminators)) {
+ const virtualFromDiscriminator = getVirtual(schema.discriminators[discriminatorKey], name);
+ if (virtualFromDiscriminator) return virtualFromDiscriminator;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/node_modules/mongoose/lib/helpers/populate/leanPopulateMap.js b/node_modules/mongoose/lib/helpers/populate/leanPopulateMap.js
new file mode 100644
index 0000000..a333124
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/leanPopulateMap.js
@@ -0,0 +1,7 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = new WeakMap(); \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/lookupLocalFields.js b/node_modules/mongoose/lib/helpers/populate/lookupLocalFields.js
new file mode 100644
index 0000000..08ed763
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/lookupLocalFields.js
@@ -0,0 +1,26 @@
+'use strict';
+
+module.exports = function lookupLocalFields(cur, path, val) {
+ if (cur == null) {
+ return cur;
+ }
+
+ if (cur._doc != null) {
+ cur = cur._doc;
+ }
+
+ if (arguments.length >= 3) {
+ cur[path] = val;
+ return val;
+ }
+
+
+ // Support populating paths under maps using `map.$*.subpath`
+ if (path === '$*') {
+ return cur instanceof Map ?
+ Array.from(cur.values()) :
+ Object.keys(cur).map(key => cur[key]);
+ }
+
+ return cur[path];
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/normalizeRefPath.js b/node_modules/mongoose/lib/helpers/populate/normalizeRefPath.js
new file mode 100644
index 0000000..233b741
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/normalizeRefPath.js
@@ -0,0 +1,45 @@
+'use strict';
+
+module.exports = function normalizeRefPath(refPath, doc, populatedPath) {
+ if (refPath == null) {
+ return refPath;
+ }
+
+ if (typeof refPath === 'function') {
+ refPath = refPath.call(doc, doc, populatedPath);
+ }
+
+ // If populated path has numerics, the end `refPath` should too. For example,
+ // if populating `a.0.b` instead of `a.b` and `b` has `refPath = a.c`, we
+ // should return `a.0.c` for the refPath.
+ const hasNumericProp = /(\.\d+$|\.\d+\.)/g;
+
+ if (hasNumericProp.test(populatedPath)) {
+ const chunks = populatedPath.split(hasNumericProp);
+
+ if (chunks[chunks.length - 1] === '') {
+ throw new Error('Can\'t populate individual element in an array');
+ }
+
+ let _refPath = '';
+ let _remaining = refPath;
+ // 2nd, 4th, etc. will be numeric props. For example: `[ 'a', '.0.', 'b' ]`
+ for (let i = 0; i < chunks.length; i += 2) {
+ const chunk = chunks[i];
+ if (_remaining.startsWith(chunk + '.')) {
+ _refPath += _remaining.substr(0, chunk.length) + chunks[i + 1];
+ _remaining = _remaining.substr(chunk.length + 1);
+ } else if (i === chunks.length - 1) {
+ _refPath += _remaining;
+ _remaining = '';
+ break;
+ } else {
+ throw new Error('Could not normalize ref path, chunk ' + chunk + ' not in populated path');
+ }
+ }
+
+ return _refPath;
+ }
+
+ return refPath;
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/removeDeselectedForeignField.js b/node_modules/mongoose/lib/helpers/populate/removeDeselectedForeignField.js
new file mode 100644
index 0000000..39b893a
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/removeDeselectedForeignField.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const get = require('../get');
+const mpath = require('mpath');
+const parseProjection = require('../projection/parseProjection');
+
+/*!
+ * ignore
+ */
+
+module.exports = function removeDeselectedForeignField(foreignFields, options, docs) {
+ const projection = parseProjection(get(options, 'select', null), true) ||
+ parseProjection(get(options, 'options.select', null), true);
+
+ if (projection == null) {
+ return;
+ }
+ for (const foreignField of foreignFields) {
+ if (!projection.hasOwnProperty('-' + foreignField)) {
+ continue;
+ }
+
+ for (const val of docs) {
+ if (val.$__ != null) {
+ mpath.unset(foreignField, val._doc);
+ } else {
+ mpath.unset(foreignField, val);
+ }
+ }
+ }
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/populate/validateRef.js b/node_modules/mongoose/lib/helpers/populate/validateRef.js
new file mode 100644
index 0000000..9dc2b6f
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/populate/validateRef.js
@@ -0,0 +1,19 @@
+'use strict';
+
+const MongooseError = require('../../error/mongooseError');
+const util = require('util');
+
+module.exports = validateRef;
+
+function validateRef(ref, path) {
+ if (typeof ref === 'string') {
+ return;
+ }
+
+ if (typeof ref === 'function') {
+ return;
+ }
+
+ throw new MongooseError('Invalid ref at path "' + path + '". Got ' +
+ util.inspect(ref, { depth: 0 }));
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/printJestWarning.js b/node_modules/mongoose/lib/helpers/printJestWarning.js
new file mode 100644
index 0000000..eb3a8eb
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/printJestWarning.js
@@ -0,0 +1,8 @@
+'use strict';
+
+if (typeof jest !== 'undefined' && typeof window !== 'undefined') {
+ console.warn('Mongoose: looks like you\'re trying to test a Mongoose app ' +
+ 'with Jest\'s default jsdom test environment. Please make sure you read ' +
+ 'Mongoose\'s docs on configuring Jest to test Node.js apps: ' +
+ 'http://mongoosejs.com/docs/jest.html');
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/projection/isDefiningProjection.js b/node_modules/mongoose/lib/helpers/projection/isDefiningProjection.js
new file mode 100644
index 0000000..67dfb39
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/isDefiningProjection.js
@@ -0,0 +1,18 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function isDefiningProjection(val) {
+ if (val == null) {
+ // `undefined` or `null` become exclusive projections
+ return true;
+ }
+ if (typeof val === 'object') {
+ // Only cases where a value does **not** define whether the whole projection
+ // is inclusive or exclusive are `$meta` and `$slice`.
+ return !('$meta' in val) && !('$slice' in val);
+ }
+ return true;
+};
diff --git a/node_modules/mongoose/lib/helpers/projection/isExclusive.js b/node_modules/mongoose/lib/helpers/projection/isExclusive.js
new file mode 100644
index 0000000..8c64bc5
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/isExclusive.js
@@ -0,0 +1,28 @@
+'use strict';
+
+const isDefiningProjection = require('./isDefiningProjection');
+
+/*!
+ * ignore
+ */
+
+module.exports = function isExclusive(projection) {
+ const keys = Object.keys(projection);
+ let ki = keys.length;
+ let exclude = null;
+
+ if (ki === 1 && keys[0] === '_id') {
+ exclude = !!projection[keys[ki]];
+ } else {
+ while (ki--) {
+ // Does this projection explicitly define inclusion/exclusion?
+ // Explicitly avoid `$meta` and `$slice`
+ if (keys[ki] !== '_id' && isDefiningProjection(projection[keys[ki]])) {
+ exclude = !projection[keys[ki]];
+ break;
+ }
+ }
+ }
+
+ return exclude;
+};
diff --git a/node_modules/mongoose/lib/helpers/projection/isInclusive.js b/node_modules/mongoose/lib/helpers/projection/isInclusive.js
new file mode 100644
index 0000000..098309f
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/isInclusive.js
@@ -0,0 +1,34 @@
+'use strict';
+
+const isDefiningProjection = require('./isDefiningProjection');
+
+/*!
+ * ignore
+ */
+
+module.exports = function isInclusive(projection) {
+ if (projection == null) {
+ return false;
+ }
+
+ const props = Object.keys(projection);
+ const numProps = props.length;
+ if (numProps === 0) {
+ return false;
+ }
+
+ for (let i = 0; i < numProps; ++i) {
+ const prop = props[i];
+ // Plus paths can't define the projection (see gh-7050)
+ if (prop.startsWith('+')) {
+ continue;
+ }
+ // If field is truthy (1, true, etc.) and not an object, then this
+ // projection must be inclusive. If object, assume its $meta, $slice, etc.
+ if (isDefiningProjection(projection[prop]) && !!projection[prop]) {
+ return true;
+ }
+ }
+
+ return false;
+};
diff --git a/node_modules/mongoose/lib/helpers/projection/isPathExcluded.js b/node_modules/mongoose/lib/helpers/projection/isPathExcluded.js
new file mode 100644
index 0000000..fc2592c
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/isPathExcluded.js
@@ -0,0 +1,35 @@
+'use strict';
+
+const isDefiningProjection = require('./isDefiningProjection');
+
+/*!
+ * Determines if `path` is excluded by `projection`
+ *
+ * @param {Object} projection
+ * @param {string} path
+ * @return {Boolean}
+ */
+
+module.exports = function isPathExcluded(projection, path) {
+ if (path === '_id') {
+ return projection._id === 0;
+ }
+
+ const paths = Object.keys(projection);
+ let type = null;
+
+ for (const _path of paths) {
+ if (isDefiningProjection(projection[_path])) {
+ type = projection[path] === 1 ? 'inclusive' : 'exclusive';
+ break;
+ }
+ }
+
+ if (type === 'inclusive') {
+ return projection[path] !== 1;
+ }
+ if (type === 'exclusive') {
+ return projection[path] === 0;
+ }
+ return false;
+};
diff --git a/node_modules/mongoose/lib/helpers/projection/isPathSelectedInclusive.js b/node_modules/mongoose/lib/helpers/projection/isPathSelectedInclusive.js
new file mode 100644
index 0000000..8a05fc9
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/isPathSelectedInclusive.js
@@ -0,0 +1,28 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function isPathSelectedInclusive(fields, path) {
+ const chunks = path.split('.');
+ let cur = '';
+ let j;
+ let keys;
+ let numKeys;
+ for (let i = 0; i < chunks.length; ++i) {
+ cur += cur.length ? '.' : '' + chunks[i];
+ if (fields[cur]) {
+ keys = Object.keys(fields);
+ numKeys = keys.length;
+ for (j = 0; j < numKeys; ++j) {
+ if (keys[i].indexOf(cur + '.') === 0 && keys[i].indexOf(path) !== 0) {
+ continue;
+ }
+ }
+ return true;
+ }
+ }
+
+ return false;
+};
diff --git a/node_modules/mongoose/lib/helpers/projection/parseProjection.js b/node_modules/mongoose/lib/helpers/projection/parseProjection.js
new file mode 100644
index 0000000..d2a44b1
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/projection/parseProjection.js
@@ -0,0 +1,33 @@
+'use strict';
+
+/**
+ * Convert a string or array into a projection object, retaining all
+ * `-` and `+` paths.
+ */
+
+module.exports = function parseProjection(v, retainMinusPaths) {
+ const type = typeof v;
+
+ if (type === 'string') {
+ v = v.split(/\s+/);
+ }
+ if (!Array.isArray(v) && Object.prototype.toString.call(v) !== '[object Arguments]') {
+ return v;
+ }
+
+ const len = v.length;
+ const ret = {};
+ for (let i = 0; i < len; ++i) {
+ let field = v[i];
+ if (!field) {
+ continue;
+ }
+ const include = '-' == field[0] ? 0 : 1;
+ if (!retainMinusPaths && include === 0) {
+ field = field.substring(1);
+ }
+ ret[field] = include;
+ }
+
+ return ret;
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/promiseOrCallback.js b/node_modules/mongoose/lib/helpers/promiseOrCallback.js
new file mode 100644
index 0000000..a1aff55
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/promiseOrCallback.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const PromiseProvider = require('../promise_provider');
+
+const emittedSymbol = Symbol.for('mongoose:emitted');
+
+module.exports = function promiseOrCallback(callback, fn, ee) {
+ if (typeof callback === 'function') {
+ return fn(function(error) {
+ if (error != null) {
+ if (ee != null && ee.listeners('error').length > 0 && !error[emittedSymbol]) {
+ error[emittedSymbol] = true;
+ ee.emit('error', error);
+ }
+ try {
+ callback(error);
+ } catch (error) {
+ return process.nextTick(() => {
+ throw error;
+ });
+ }
+ return;
+ }
+ callback.apply(this, arguments);
+ });
+ }
+
+ const Promise = PromiseProvider.get();
+
+ return new Promise((resolve, reject) => {
+ fn(function(error, res) {
+ if (error != null) {
+ if (ee != null && ee.listeners('error').length > 0 && !error[emittedSymbol]) {
+ error[emittedSymbol] = true;
+ ee.emit('error', error);
+ }
+ return reject(error);
+ }
+ if (arguments.length > 2) {
+ return resolve(Array.prototype.slice.call(arguments, 1));
+ }
+ resolve(res);
+ });
+ });
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/query/applyGlobalMaxTimeMS.js b/node_modules/mongoose/lib/helpers/query/applyGlobalMaxTimeMS.js
new file mode 100644
index 0000000..cb49260
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/applyGlobalMaxTimeMS.js
@@ -0,0 +1,15 @@
+'use strict';
+
+const utils = require('../../utils');
+
+module.exports = function applyGlobalMaxTimeMS(options, model) {
+ if (utils.hasUserDefinedProperty(options, 'maxTimeMS')) {
+ return;
+ }
+
+ if (utils.hasUserDefinedProperty(model.db.options, 'maxTimeMS')) {
+ options.maxTimeMS = model.db.options.maxTimeMS;
+ } else if (utils.hasUserDefinedProperty(model.base.options, 'maxTimeMS')) {
+ options.maxTimeMS = model.base.options.maxTimeMS;
+ }
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/query/applyQueryMiddleware.js b/node_modules/mongoose/lib/helpers/query/applyQueryMiddleware.js
new file mode 100644
index 0000000..a08baf8
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/applyQueryMiddleware.js
@@ -0,0 +1,90 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = applyQueryMiddleware;
+
+/*!
+ * ignore
+ */
+
+applyQueryMiddleware.middlewareFunctions = [
+ 'count',
+ 'countDocuments',
+ 'deleteMany',
+ 'deleteOne',
+ 'distinct',
+ 'estimatedDocumentCount',
+ 'find',
+ 'findOne',
+ 'findOneAndDelete',
+ 'findOneAndRemove',
+ 'findOneAndReplace',
+ 'findOneAndUpdate',
+ 'remove',
+ 'replaceOne',
+ 'update',
+ 'updateMany',
+ 'updateOne',
+ 'validate'
+];
+
+/*!
+ * Apply query middleware
+ *
+ * @param {Query} query constructor
+ * @param {Model} model
+ */
+
+function applyQueryMiddleware(Query, model) {
+ const kareemOptions = {
+ useErrorHandlers: true,
+ numCallbackParams: 1,
+ nullResultByDefault: true
+ };
+
+ const middleware = model.hooks.filter(hook => {
+ const contexts = _getContexts(hook);
+ if (hook.name === 'updateOne') {
+ return contexts.query == null || !!contexts.query;
+ }
+ if (hook.name === 'deleteOne') {
+ return !!contexts.query || Object.keys(contexts).length === 0;
+ }
+ if (hook.name === 'validate' || hook.name === 'remove') {
+ return !!contexts.query;
+ }
+ return true;
+ });
+
+ // `update()` thunk has a different name because `_update` was already taken
+ Query.prototype._execUpdate = middleware.createWrapper('update',
+ Query.prototype._execUpdate, null, kareemOptions);
+ // `distinct()` thunk has a different name because `_distinct` was already taken
+ Query.prototype.__distinct = middleware.createWrapper('distinct',
+ Query.prototype.__distinct, null, kareemOptions);
+
+ // `validate()` doesn't have a thunk because it doesn't execute a query.
+ Query.prototype.validate = middleware.createWrapper('validate',
+ Query.prototype.validate, null, kareemOptions);
+
+ applyQueryMiddleware.middlewareFunctions.
+ filter(v => v !== 'update' && v !== 'distinct' && v !== 'validate').
+ forEach(fn => {
+ Query.prototype[`_${fn}`] = middleware.createWrapper(fn,
+ Query.prototype[`_${fn}`], null, kareemOptions);
+ });
+}
+
+function _getContexts(hook) {
+ const ret = {};
+ if (hook.hasOwnProperty('query')) {
+ ret.query = hook.query;
+ }
+ if (hook.hasOwnProperty('document')) {
+ ret.document = hook.document;
+ }
+ return ret;
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/query/castFilterPath.js b/node_modules/mongoose/lib/helpers/query/castFilterPath.js
new file mode 100644
index 0000000..74ff1c2
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/castFilterPath.js
@@ -0,0 +1,55 @@
+'use strict';
+
+const isOperator = require('./isOperator');
+
+module.exports = function castFilterPath(query, schematype, val) {
+ const ctx = query;
+ const any$conditionals = Object.keys(val).some(isOperator);
+
+ if (!any$conditionals) {
+ return schematype.castForQueryWrapper({
+ val: val,
+ context: ctx
+ });
+ }
+
+ const ks = Object.keys(val);
+
+ let k = ks.length;
+
+ while (k--) {
+ const $cond = ks[k];
+ const nested = val[$cond];
+
+ if ($cond === '$not') {
+ if (nested && schematype && !schematype.caster) {
+ const _keys = Object.keys(nested);
+ if (_keys.length && isOperator(_keys[0])) {
+ for (const key in nested) {
+ nested[key] = schematype.castForQueryWrapper({
+ $conditional: key,
+ val: nested[key],
+ context: ctx
+ });
+ }
+ } else {
+ val[$cond] = schematype.castForQueryWrapper({
+ $conditional: $cond,
+ val: nested,
+ context: ctx
+ });
+ }
+ continue;
+ }
+ // cast(schematype.caster ? schematype.caster.schema : schema, nested, options, context);
+ } else {
+ val[$cond] = schematype.castForQueryWrapper({
+ $conditional: $cond,
+ val: nested,
+ context: ctx
+ });
+ }
+ }
+
+ return val;
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/query/castUpdate.js b/node_modules/mongoose/lib/helpers/query/castUpdate.js
new file mode 100644
index 0000000..bf60e5d
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/castUpdate.js
@@ -0,0 +1,538 @@
+'use strict';
+
+const CastError = require('../../error/cast');
+const MongooseError = require('../../error/mongooseError');
+const StrictModeError = require('../../error/strict');
+const ValidationError = require('../../error/validation');
+const castNumber = require('../../cast/number');
+const cast = require('../../cast');
+const getEmbeddedDiscriminatorPath = require('./getEmbeddedDiscriminatorPath');
+const handleImmutable = require('./handleImmutable');
+const moveImmutableProperties = require('../update/moveImmutableProperties');
+const schemaMixedSymbol = require('../../schema/symbols').schemaMixedSymbol;
+const utils = require('../../utils');
+
+/*!
+ * Casts an update op based on the given schema
+ *
+ * @param {Schema} schema
+ * @param {Object} obj
+ * @param {Object} options
+ * @param {Boolean} [options.overwrite] defaults to false
+ * @param {Boolean|String} [options.strict] defaults to true
+ * @param {Query} context passed to setters
+ * @return {Boolean} true iff the update is non-empty
+ */
+
+module.exports = function castUpdate(schema, obj, options, context, filter) {
+ if (obj == null) {
+ return undefined;
+ }
+ options = options || {};
+
+ // Update pipeline
+ if (Array.isArray(obj)) {
+ const len = obj.length;
+ for (let i = 0; i < len; ++i) {
+ const ops = Object.keys(obj[i]);
+ for (const op of ops) {
+ obj[i][op] = castPipelineOperator(op, obj[i][op]);
+ }
+ }
+ return obj;
+ }
+
+ if (options.upsert) {
+ moveImmutableProperties(schema, obj, context);
+ }
+
+ const ops = Object.keys(obj);
+ let i = ops.length;
+ const ret = {};
+ let val;
+ let hasDollarKey = false;
+ const overwrite = options.overwrite;
+
+ filter = filter || {};
+
+ while (i--) {
+ const op = ops[i];
+ // if overwrite is set, don't do any of the special $set stuff
+ if (op[0] !== '$' && !overwrite) {
+ // fix up $set sugar
+ if (!ret.$set) {
+ if (obj.$set) {
+ ret.$set = obj.$set;
+ } else {
+ ret.$set = {};
+ }
+ }
+ ret.$set[op] = obj[op];
+ ops.splice(i, 1);
+ if (!~ops.indexOf('$set')) ops.push('$set');
+ } else if (op === '$set') {
+ if (!ret.$set) {
+ ret[op] = obj[op];
+ }
+ } else {
+ ret[op] = obj[op];
+ }
+ }
+
+ // cast each value
+ i = ops.length;
+
+ while (i--) {
+ const op = ops[i];
+ val = ret[op];
+ hasDollarKey = hasDollarKey || op.startsWith('$');
+
+ if (val &&
+ typeof val === 'object' &&
+ !Buffer.isBuffer(val) &&
+ (!overwrite || hasDollarKey)) {
+ walkUpdatePath(schema, val, op, options, context, filter);
+ } else if (overwrite && ret && typeof ret === 'object') {
+ walkUpdatePath(schema, ret, '$set', options, context, filter);
+ } else {
+ const msg = 'Invalid atomic update value for ' + op + '. '
+ + 'Expected an object, received ' + typeof val;
+ throw new Error(msg);
+ }
+
+ if (op.startsWith('$') && utils.isEmptyObject(val)) {
+ delete ret[op];
+ }
+ }
+
+ if (Object.keys(ret).length === 0 &&
+ options.upsert &&
+ Object.keys(filter).length > 0) {
+ // Trick the driver into allowing empty upserts to work around
+ // https://github.com/mongodb/node-mongodb-native/pull/2490
+ return { $setOnInsert: filter };
+ }
+
+ return ret;
+};
+
+/*!
+ * ignore
+ */
+
+function castPipelineOperator(op, val) {
+ if (op === '$unset') {
+ if (!Array.isArray(val) || val.find(v => typeof v !== 'string')) {
+ throw new MongooseError('Invalid $unset in pipeline, must be ' +
+ 'an array of strings');
+ }
+ return val;
+ }
+ if (op === '$project') {
+ if (val == null || typeof val !== 'object') {
+ throw new MongooseError('Invalid $project in pipeline, must be an object');
+ }
+ return val;
+ }
+ if (op === '$addFields' || op === '$set') {
+ if (val == null || typeof val !== 'object') {
+ throw new MongooseError('Invalid ' + op + ' in pipeline, must be an object');
+ }
+ return val;
+ } else if (op === '$replaceRoot' || op === '$replaceWith') {
+ if (val == null || typeof val !== 'object') {
+ throw new MongooseError('Invalid ' + op + ' in pipeline, must be an object');
+ }
+ return val;
+ }
+
+ throw new MongooseError('Invalid update pipeline operator: "' + op + '"');
+}
+
+/*!
+ * Walk each path of obj and cast its values
+ * according to its schema.
+ *
+ * @param {Schema} schema
+ * @param {Object} obj - part of a query
+ * @param {String} op - the atomic operator ($pull, $set, etc)
+ * @param {Object} options
+ * @param {Boolean|String} [options.strict]
+ * @param {Boolean} [options.omitUndefined]
+ * @param {Query} context
+ * @param {String} pref - path prefix (internal only)
+ * @return {Bool} true if this path has keys to update
+ * @api private
+ */
+
+function walkUpdatePath(schema, obj, op, options, context, filter, pref) {
+ const strict = options.strict;
+ const prefix = pref ? pref + '.' : '';
+ const keys = Object.keys(obj);
+ let i = keys.length;
+ let hasKeys = false;
+ let schematype;
+ let key;
+ let val;
+
+ let aggregatedError = null;
+
+ let useNestedStrict;
+ if (options.useNestedStrict === undefined) {
+ useNestedStrict = schema.options.useNestedStrict;
+ } else {
+ useNestedStrict = options.useNestedStrict;
+ }
+
+ while (i--) {
+ key = keys[i];
+ val = obj[key];
+
+ // `$pull` is special because we need to cast the RHS as a query, not as
+ // an update.
+ if (op === '$pull') {
+ schematype = schema._getSchema(prefix + key);
+ if (schematype != null && schematype.schema != null) {
+ obj[key] = cast(schematype.schema, obj[key], options, context);
+ hasKeys = true;
+ continue;
+ }
+ }
+
+ if (val && val.constructor.name === 'Object') {
+ // watch for embedded doc schemas
+ schematype = schema._getSchema(prefix + key);
+
+ if (op !== '$setOnInsert' &&
+ handleImmutable(schematype, strict, obj, key, prefix + key, context)) {
+ continue;
+ }
+
+ if (schematype && schematype.caster && op in castOps) {
+ // embedded doc schema
+ if ('$each' in val) {
+ hasKeys = true;
+ try {
+ obj[key] = {
+ $each: castUpdateVal(schematype, val.$each, op, key, context, prefix + key)
+ };
+ } catch (error) {
+ aggregatedError = _handleCastError(error, context, key, aggregatedError);
+ }
+
+ if (val.$slice != null) {
+ obj[key].$slice = val.$slice | 0;
+ }
+
+ if (val.$sort) {
+ obj[key].$sort = val.$sort;
+ }
+
+ if (val.$position != null) {
+ obj[key].$position = castNumber(val.$position);
+ }
+ } else {
+ if (schematype != null && schematype.$isSingleNested) {
+ // Special case to make sure `strict` bubbles down correctly to
+ // single nested re: gh-8735
+ let _strict = strict;
+ if (useNestedStrict !== false && schematype.schema.options.hasOwnProperty('strict')) {
+ _strict = schematype.schema.options.strict;
+ } else if (useNestedStrict === false) {
+ _strict = schema.options.strict;
+ }
+ try {
+ obj[key] = schematype.castForQuery(val, context, { strict: _strict });
+ } catch (error) {
+ aggregatedError = _handleCastError(error, context, key, aggregatedError);
+ }
+ } else {
+ try {
+ obj[key] = castUpdateVal(schematype, val, op, key, context, prefix + key);
+ } catch (error) {
+ aggregatedError = _handleCastError(error, context, key, aggregatedError);
+ }
+ }
+
+ if (options.omitUndefined && obj[key] === void 0) {
+ delete obj[key];
+ continue;
+ }
+
+ hasKeys = true;
+ }
+ } else if ((op === '$currentDate') || (op in castOps && schematype)) {
+ // $currentDate can take an object
+ try {
+ obj[key] = castUpdateVal(schematype, val, op, key, context, prefix + key);
+ } catch (error) {
+ aggregatedError = _handleCastError(error, context, key, aggregatedError);
+ }
+
+ if (options.omitUndefined && obj[key] === void 0) {
+ delete obj[key];
+ continue;
+ }
+
+ hasKeys = true;
+ } else {
+ const pathToCheck = (prefix + key);
+ const v = schema._getPathType(pathToCheck);
+ let _strict = strict;
+ if (useNestedStrict &&
+ v &&
+ v.schema &&
+ 'strict' in v.schema.options) {
+ _strict = v.schema.options.strict;
+ }
+
+ if (v.pathType === 'undefined') {
+ if (_strict === 'throw') {
+ throw new StrictModeError(pathToCheck);
+ } else if (_strict) {
+ delete obj[key];
+ continue;
+ }
+ }
+
+ // gh-2314
+ // we should be able to set a schema-less field
+ // to an empty object literal
+ hasKeys |= walkUpdatePath(schema, val, op, options, context, filter, prefix + key) ||
+ (utils.isObject(val) && Object.keys(val).length === 0);
+ }
+ } else {
+ const checkPath = (key === '$each' || key === '$or' || key === '$and' || key === '$in') ?
+ pref : prefix + key;
+ schematype = schema._getSchema(checkPath);
+
+ // You can use `$setOnInsert` with immutable keys
+ if (op !== '$setOnInsert' &&
+ handleImmutable(schematype, strict, obj, key, prefix + key, context)) {
+ continue;
+ }
+
+ let pathDetails = schema._getPathType(checkPath);
+
+ // If no schema type, check for embedded discriminators because the
+ // filter or update may imply an embedded discriminator type. See #8378
+ if (schematype == null) {
+ const _res = getEmbeddedDiscriminatorPath(schema, obj, filter, checkPath);
+ if (_res.schematype != null) {
+ schematype = _res.schematype;
+ pathDetails = _res.type;
+ }
+ }
+
+ let isStrict = strict;
+ if (useNestedStrict &&
+ pathDetails &&
+ pathDetails.schema &&
+ 'strict' in pathDetails.schema.options) {
+ isStrict = pathDetails.schema.options.strict;
+ }
+
+ const skip = isStrict &&
+ !schematype &&
+ !/real|nested/.test(pathDetails.pathType);
+
+ if (skip) {
+ // Even if strict is `throw`, avoid throwing an error because of
+ // virtuals because of #6731
+ if (isStrict === 'throw' && schema.virtuals[checkPath] == null) {
+ throw new StrictModeError(prefix + key);
+ } else {
+ delete obj[key];
+ }
+ } else {
+ // gh-1845 temporary fix: ignore $rename. See gh-3027 for tracking
+ // improving this.
+ if (op === '$rename') {
+ hasKeys = true;
+ continue;
+ }
+
+ try {
+ obj[key] = castUpdateVal(schematype, val, op, key, context, prefix + key);
+ } catch (error) {
+ aggregatedError = _handleCastError(error, context, key, aggregatedError);
+ }
+
+ if (Array.isArray(obj[key]) && (op === '$addToSet' || op === '$push') && key !== '$each') {
+ if (schematype && schematype.caster && !schematype.caster.$isMongooseArray) {
+ obj[key] = { $each: obj[key] };
+ }
+ }
+
+ if (options.omitUndefined && obj[key] === void 0) {
+ delete obj[key];
+ continue;
+ }
+
+ hasKeys = true;
+ }
+ }
+ }
+
+ if (aggregatedError != null) {
+ throw aggregatedError;
+ }
+
+ return hasKeys;
+}
+
+/*!
+ * ignore
+ */
+
+function _handleCastError(error, query, key, aggregatedError) {
+ if (typeof query !== 'object' || !query.options.multipleCastError) {
+ throw error;
+ }
+ aggregatedError = aggregatedError || new ValidationError();
+ aggregatedError.addError(key, error);
+ return aggregatedError;
+}
+
+/*!
+ * These operators should be cast to numbers instead
+ * of their path schema type.
+ */
+
+const numberOps = {
+ $pop: 1,
+ $inc: 1
+};
+
+/*!
+ * These ops require no casting because the RHS doesn't do anything.
+ */
+
+const noCastOps = {
+ $unset: 1
+};
+
+/*!
+ * These operators require casting docs
+ * to real Documents for Update operations.
+ */
+
+const castOps = {
+ $push: 1,
+ $addToSet: 1,
+ $set: 1,
+ $setOnInsert: 1
+};
+
+/*!
+ * ignore
+ */
+
+const overwriteOps = {
+ $set: 1,
+ $setOnInsert: 1
+};
+
+/*!
+ * Casts `val` according to `schema` and atomic `op`.
+ *
+ * @param {SchemaType} schema
+ * @param {Object} val
+ * @param {String} op - the atomic operator ($pull, $set, etc)
+ * @param {String} $conditional
+ * @param {Query} context
+ * @api private
+ */
+
+function castUpdateVal(schema, val, op, $conditional, context, path) {
+ if (!schema) {
+ // non-existing schema path
+ if (op in numberOps) {
+ try {
+ return castNumber(val);
+ } catch (err) {
+ throw new CastError('number', val, path);
+ }
+ }
+ return val;
+ }
+
+ const cond = schema.caster && op in castOps &&
+ (utils.isObject(val) || Array.isArray(val));
+ if (cond && !overwriteOps[op]) {
+ // Cast values for ops that add data to MongoDB.
+ // Ensures embedded documents get ObjectIds etc.
+ let schemaArrayDepth = 0;
+ let cur = schema;
+ while (cur.$isMongooseArray) {
+ ++schemaArrayDepth;
+ cur = cur.caster;
+ }
+ let arrayDepth = 0;
+ let _val = val;
+ while (Array.isArray(_val)) {
+ ++arrayDepth;
+ _val = _val[0];
+ }
+
+ const additionalNesting = schemaArrayDepth - arrayDepth;
+ while (arrayDepth < schemaArrayDepth) {
+ val = [val];
+ ++arrayDepth;
+ }
+
+ let tmp = schema.applySetters(Array.isArray(val) ? val : [val], context);
+
+ for (let i = 0; i < additionalNesting; ++i) {
+ tmp = tmp[0];
+ }
+ return tmp;
+ }
+
+ if (op in noCastOps) {
+ return val;
+ }
+ if (op in numberOps) {
+ // Null and undefined not allowed for $pop, $inc
+ if (val == null) {
+ throw new CastError('number', val, schema.path);
+ }
+ if (op === '$inc') {
+ // Support `$inc` with long, int32, etc. (gh-4283)
+ return schema.castForQueryWrapper({
+ val: val,
+ context: context
+ });
+ }
+ try {
+ return castNumber(val);
+ } catch (error) {
+ throw new CastError('number', val, schema.path);
+ }
+ }
+ if (op === '$currentDate') {
+ if (typeof val === 'object') {
+ return { $type: val.$type };
+ }
+ return Boolean(val);
+ }
+
+ if (/^\$/.test($conditional)) {
+ return schema.castForQueryWrapper({
+ $conditional: $conditional,
+ val: val,
+ context: context
+ });
+ }
+
+ if (overwriteOps[op]) {
+ return schema.castForQueryWrapper({
+ val: val,
+ context: context,
+ $skipQueryCastForUpdate: val != null && schema.$isMongooseArray && schema.$fullPath != null && !schema.$fullPath.match(/\d+$/),
+ $applySetters: schema[schemaMixedSymbol] != null
+ });
+ }
+
+ return schema.castForQueryWrapper({ val: val, context: context });
+}
diff --git a/node_modules/mongoose/lib/helpers/query/completeMany.js b/node_modules/mongoose/lib/helpers/query/completeMany.js
new file mode 100644
index 0000000..aabe596
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/completeMany.js
@@ -0,0 +1,47 @@
+'use strict';
+
+const helpers = require('../../queryhelpers');
+
+module.exports = completeMany;
+
+/*!
+ * Given a model and an array of docs, hydrates all the docs to be instances
+ * of the model. Used to initialize docs returned from the db from `find()`
+ *
+ * @param {Model} model
+ * @param {Array} docs
+ * @param {Object} fields the projection used, including `select` from schemas
+ * @param {Object} userProvidedFields the user-specified projection
+ * @param {Object} opts
+ * @param {Array} [opts.populated]
+ * @param {ClientSession} [opts.session]
+ * @param {Function} callback
+ */
+
+function completeMany(model, docs, fields, userProvidedFields, opts, callback) {
+ const arr = [];
+ let count = docs.length;
+ const len = count;
+ let error = null;
+
+ function init(_error) {
+ if (_error != null) {
+ error = error || _error;
+ }
+ if (error != null) {
+ --count || process.nextTick(() => callback(error));
+ return;
+ }
+ --count || process.nextTick(() => callback(error, arr));
+ }
+
+ for (let i = 0; i < len; ++i) {
+ arr[i] = helpers.createModel(model, docs[i], fields, userProvidedFields);
+ try {
+ arr[i].init(docs[i], opts, init);
+ } catch (error) {
+ init(error);
+ }
+ arr[i].$session(opts.session);
+ }
+}
diff --git a/node_modules/mongoose/lib/helpers/query/getEmbeddedDiscriminatorPath.js b/node_modules/mongoose/lib/helpers/query/getEmbeddedDiscriminatorPath.js
new file mode 100644
index 0000000..395ea75
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/getEmbeddedDiscriminatorPath.js
@@ -0,0 +1,68 @@
+'use strict';
+
+const cleanPositionalOperators = require('../schema/cleanPositionalOperators');
+const get = require('../get');
+const getDiscriminatorByValue = require('../discriminator/getDiscriminatorByValue');
+
+/*!
+ * Like `schema.path()`, except with a document, because impossible to
+ * determine path type without knowing the embedded discriminator key.
+ */
+
+module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, path) {
+ const parts = path.split('.');
+ let schematype = null;
+ let type = 'adhocOrUndefined';
+
+ filter = filter || {};
+ update = update || {};
+
+ for (let i = 0; i < parts.length; ++i) {
+ const subpath = cleanPositionalOperators(parts.slice(0, i + 1).join('.'));
+ schematype = schema.path(subpath);
+ if (schematype == null) {
+ continue;
+ }
+
+ type = schema.pathType(subpath);
+ if ((schematype.$isSingleNested || schematype.$isMongooseDocumentArrayElement) &&
+ schematype.schema.discriminators != null) {
+ const key = get(schematype, 'schema.options.discriminatorKey');
+ const discriminatorValuePath = subpath + '.' + key;
+ const discriminatorFilterPath =
+ discriminatorValuePath.replace(/\.\d+\./, '.');
+ let discriminatorKey = null;
+
+ if (discriminatorValuePath in filter) {
+ discriminatorKey = filter[discriminatorValuePath];
+ }
+ if (discriminatorFilterPath in filter) {
+ discriminatorKey = filter[discriminatorFilterPath];
+ }
+ const wrapperPath = subpath.replace(/\.\d+$/, '');
+ if (schematype.$isMongooseDocumentArrayElement &&
+ get(filter[wrapperPath], '$elemMatch.' + key) != null) {
+ discriminatorKey = filter[wrapperPath].$elemMatch[key];
+ }
+
+ if (discriminatorValuePath in update) {
+ discriminatorKey = update[discriminatorValuePath];
+ }
+
+ if (discriminatorKey == null) {
+ continue;
+ }
+
+ const discriminatorSchema = getDiscriminatorByValue(schematype.caster, discriminatorKey).schema;
+
+ const rest = parts.slice(i + 1).join('.');
+ schematype = discriminatorSchema.path(rest);
+ if (schematype != null) {
+ type = discriminatorSchema._getPathType(rest);
+ break;
+ }
+ }
+ }
+
+ return { type: type, schematype: schematype };
+};
diff --git a/node_modules/mongoose/lib/helpers/query/handleImmutable.js b/node_modules/mongoose/lib/helpers/query/handleImmutable.js
new file mode 100644
index 0000000..22adb3c
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/handleImmutable.js
@@ -0,0 +1,28 @@
+'use strict';
+
+const StrictModeError = require('../../error/strict');
+
+module.exports = function handleImmutable(schematype, strict, obj, key, fullPath, ctx) {
+ if (schematype == null || !schematype.options || !schematype.options.immutable) {
+ return false;
+ }
+ let immutable = schematype.options.immutable;
+
+ if (typeof immutable === 'function') {
+ immutable = immutable.call(ctx, ctx);
+ }
+ if (!immutable) {
+ return false;
+ }
+
+ if (strict === false) {
+ return false;
+ }
+ if (strict === 'throw') {
+ throw new StrictModeError(null,
+ `Field ${fullPath} is immutable and strict = 'throw'`);
+ }
+
+ delete obj[key];
+ return true;
+};
diff --git a/node_modules/mongoose/lib/helpers/query/hasDollarKeys.js b/node_modules/mongoose/lib/helpers/query/hasDollarKeys.js
new file mode 100644
index 0000000..958e1c9
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/hasDollarKeys.js
@@ -0,0 +1,19 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function(obj) {
+ if (obj == null) {
+ return false;
+ }
+ const keys = Object.keys(obj);
+ const len = keys.length;
+ for (let i = 0; i < len; ++i) {
+ if (keys[i].startsWith('$')) {
+ return true;
+ }
+ }
+ return false;
+};
diff --git a/node_modules/mongoose/lib/helpers/query/isOperator.js b/node_modules/mongoose/lib/helpers/query/isOperator.js
new file mode 100644
index 0000000..3b98139
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/isOperator.js
@@ -0,0 +1,11 @@
+'use strict';
+
+const specialKeys = new Set([
+ '$ref',
+ '$id',
+ '$db'
+]);
+
+module.exports = function isOperator(path) {
+ return path.startsWith('$') && !specialKeys.has(path);
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/query/selectPopulatedFields.js b/node_modules/mongoose/lib/helpers/query/selectPopulatedFields.js
new file mode 100644
index 0000000..0653f18
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/selectPopulatedFields.js
@@ -0,0 +1,46 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+module.exports = function selectPopulatedFields(query) {
+ const opts = query._mongooseOptions;
+
+ if (opts.populate != null) {
+ const paths = Object.keys(opts.populate);
+ const userProvidedFields = query._userProvidedFields || {};
+ if (query.selectedInclusively()) {
+ for (const path of paths) {
+ if (!isPathInFields(userProvidedFields, path)) {
+ query.select(path);
+ } else if (userProvidedFields[path] === 0) {
+ delete query._fields[path];
+ }
+ }
+ } else if (query.selectedExclusively()) {
+ for (const path of paths) {
+ if (userProvidedFields[path] == null) {
+ delete query._fields[path];
+ }
+ }
+ }
+ }
+};
+
+/*!
+ * ignore
+ */
+
+function isPathInFields(userProvidedFields, path) {
+ const pieces = path.split('.');
+ const len = pieces.length;
+ let cur = pieces[0];
+ for (let i = 1; i < len; ++i) {
+ if (userProvidedFields[cur] != null) {
+ return true;
+ }
+ cur += '.' + pieces[i];
+ }
+ return userProvidedFields[cur] != null;
+}
diff --git a/node_modules/mongoose/lib/helpers/query/wrapThunk.js b/node_modules/mongoose/lib/helpers/query/wrapThunk.js
new file mode 100644
index 0000000..0005c33
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/query/wrapThunk.js
@@ -0,0 +1,18 @@
+'use strict';
+
+/*!
+ * A query thunk is the function responsible for sending the query to MongoDB,
+ * like `Query#_findOne()` or `Query#_execUpdate()`. The `Query#exec()` function
+ * calls a thunk. The term "thunk" here is the traditional Node.js definition:
+ * a function that takes exactly 1 parameter, a callback.
+ *
+ * This function defines common behavior for all query thunks.
+ */
+
+module.exports = function wrapThunk(fn) {
+ return function _wrappedThunk(cb) {
+ ++this._executionCount;
+
+ fn.call(this, cb);
+ };
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/addAutoId.js b/node_modules/mongoose/lib/helpers/schema/addAutoId.js
new file mode 100644
index 0000000..11a1f23
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/addAutoId.js
@@ -0,0 +1,7 @@
+'use strict';
+
+module.exports = function addAutoId(schema) {
+ const _obj = { _id: { auto: true } };
+ _obj._id[schema.options.typeKey] = 'ObjectId';
+ schema.add(_obj);
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/applyPlugins.js b/node_modules/mongoose/lib/helpers/schema/applyPlugins.js
new file mode 100644
index 0000000..f1daf40
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/applyPlugins.js
@@ -0,0 +1,44 @@
+'use strict';
+
+module.exports = function applyPlugins(schema, plugins, options, cacheKey) {
+ if (schema[cacheKey]) {
+ return;
+ }
+ schema[cacheKey] = true;
+
+ if (!options || !options.skipTopLevel) {
+ for (const plugin of plugins) {
+ schema.plugin(plugin[0], plugin[1]);
+ }
+ }
+
+ options = Object.assign({}, options);
+ delete options.skipTopLevel;
+
+ if (options.applyPluginsToChildSchemas !== false) {
+ for (const path of Object.keys(schema.paths)) {
+ const type = schema.paths[path];
+ if (type.schema != null) {
+ applyPlugins(type.schema, plugins, options, cacheKey);
+
+ // Recompile schema because plugins may have changed it, see gh-7572
+ type.caster.prototype.$__setSchema(type.schema);
+ }
+ }
+ }
+
+ const discriminators = schema.discriminators;
+ if (discriminators == null) {
+ return;
+ }
+
+ const applyPluginsToDiscriminators = options.applyPluginsToDiscriminators;
+
+ const keys = Object.keys(discriminators);
+ for (const discriminatorKey of keys) {
+ const discriminatorSchema = discriminators[discriminatorKey];
+
+ applyPlugins(discriminatorSchema, plugins,
+ { skipTopLevel: !applyPluginsToDiscriminators }, cacheKey);
+ }
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/applyWriteConcern.js b/node_modules/mongoose/lib/helpers/schema/applyWriteConcern.js
new file mode 100644
index 0000000..168156d
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/applyWriteConcern.js
@@ -0,0 +1,16 @@
+'use strict';
+
+const get = require('../get');
+
+module.exports = function applyWriteConcern(schema, options) {
+ const writeConcern = get(schema, 'options.writeConcern', {});
+ if (!('w' in options) && writeConcern.w != null) {
+ options.w = writeConcern.w;
+ }
+ if (!('j' in options) && writeConcern.j != null) {
+ options.j = writeConcern.j;
+ }
+ if (!('wtimeout' in options) && writeConcern.wtimeout != null) {
+ options.wtimeout = writeConcern.wtimeout;
+ }
+};
diff --git a/node_modules/mongoose/lib/helpers/schema/cleanPositionalOperators.js b/node_modules/mongoose/lib/helpers/schema/cleanPositionalOperators.js
new file mode 100644
index 0000000..b467be4
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/cleanPositionalOperators.js
@@ -0,0 +1,12 @@
+'use strict';
+
+/**
+ * For consistency's sake, we replace positional operator `$` and array filters
+ * `$[]` and `$[foo]` with `0` when looking up schema paths.
+ */
+
+module.exports = function cleanPositionalOperators(path) {
+ return path.
+ replace(/\.\$(\[[^\]]*\])?\./g, '.0.').
+ replace(/\.(\[[^\]]*\])?\$$/g, '.0');
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/getIndexes.js b/node_modules/mongoose/lib/helpers/schema/getIndexes.js
new file mode 100644
index 0000000..be907db
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/getIndexes.js
@@ -0,0 +1,155 @@
+'use strict';
+
+const get = require('../get');
+const helperIsObject = require('../isObject');
+
+/*!
+ * Gather all indexes defined in the schema, including single nested,
+ * document arrays, and embedded discriminators.
+ */
+
+module.exports = function getIndexes(schema) {
+ let indexes = [];
+ const schemaStack = new WeakMap();
+ const indexTypes = schema.constructor.indexTypes;
+ const indexByName = new Map();
+
+ collectIndexes(schema);
+ return indexes;
+
+ function collectIndexes(schema, prefix, baseSchema) {
+ // Ignore infinitely nested schemas, if we've already seen this schema
+ // along this path there must be a cycle
+ if (schemaStack.has(schema)) {
+ return;
+ }
+ schemaStack.set(schema, true);
+
+ prefix = prefix || '';
+ const keys = Object.keys(schema.paths);
+
+ for (const key of keys) {
+ const path = schema.paths[key];
+ if (baseSchema != null && baseSchema.paths[key]) {
+ // If looking at an embedded discriminator schema, don't look at paths
+ // that the
+ continue;
+ }
+
+ if (path.$isMongooseDocumentArray || path.$isSingleNested) {
+ if (get(path, 'options.excludeIndexes') !== true &&
+ get(path, 'schemaOptions.excludeIndexes') !== true &&
+ get(path, 'schema.options.excludeIndexes') !== true) {
+ collectIndexes(path.schema, prefix + key + '.');
+ }
+
+ if (path.schema.discriminators != null) {
+ const discriminators = path.schema.discriminators;
+ const discriminatorKeys = Object.keys(discriminators);
+ for (const discriminatorKey of discriminatorKeys) {
+ collectIndexes(discriminators[discriminatorKey],
+ prefix + key + '.', path.schema);
+ }
+ }
+
+ // Retained to minimize risk of backwards breaking changes due to
+ // gh-6113
+ if (path.$isMongooseDocumentArray) {
+ continue;
+ }
+ }
+
+ const index = path._index || (path.caster && path.caster._index);
+
+ if (index !== false && index !== null && index !== undefined) {
+ const field = {};
+ const isObject = helperIsObject(index);
+ const options = isObject ? index : {};
+ const type = typeof index === 'string' ? index :
+ isObject ? index.type :
+ false;
+
+ if (type && indexTypes.indexOf(type) !== -1) {
+ field[prefix + key] = type;
+ } else if (options.text) {
+ field[prefix + key] = 'text';
+ delete options.text;
+ } else {
+ const isDescendingIndex = Number(index) === -1;
+ field[prefix + key] = isDescendingIndex ? -1 : 1;
+ }
+
+ delete options.type;
+ if (!('background' in options)) {
+ options.background = true;
+ }
+ if (schema.options.autoIndex != null) {
+ options._autoIndex = schema.options.autoIndex;
+ }
+
+ const indexName = options && options.name;
+ if (typeof indexName === 'string') {
+ if (indexByName.has(indexName)) {
+ Object.assign(indexByName.get(indexName), field);
+ } else {
+ indexes.push([field, options]);
+ indexByName.set(indexName, field);
+ }
+ } else {
+ indexes.push([field, options]);
+ indexByName.set(indexName, field);
+ }
+ }
+ }
+
+ schemaStack.delete(schema);
+
+ if (prefix) {
+ fixSubIndexPaths(schema, prefix);
+ } else {
+ schema._indexes.forEach(function(index) {
+ if (!('background' in index[1])) {
+ index[1].background = true;
+ }
+ });
+ indexes = indexes.concat(schema._indexes);
+ }
+ }
+
+ /*!
+ * Checks for indexes added to subdocs using Schema.index().
+ * These indexes need their paths prefixed properly.
+ *
+ * schema._indexes = [ [indexObj, options], [indexObj, options] ..]
+ */
+
+ function fixSubIndexPaths(schema, prefix) {
+ const subindexes = schema._indexes;
+ const len = subindexes.length;
+ for (let i = 0; i < len; ++i) {
+ const indexObj = subindexes[i][0];
+ const indexOptions = subindexes[i][1];
+ const keys = Object.keys(indexObj);
+ const klen = keys.length;
+ const newindex = {};
+
+ // use forward iteration, order matters
+ for (let j = 0; j < klen; ++j) {
+ const key = keys[j];
+ newindex[prefix + key] = indexObj[key];
+ }
+
+ const newIndexOptions = Object.assign({}, indexOptions);
+ if (indexOptions != null && indexOptions.partialFilterExpression != null) {
+ newIndexOptions.partialFilterExpression = {};
+ const partialFilterExpression = indexOptions.partialFilterExpression;
+ for (const key of Object.keys(partialFilterExpression)) {
+ newIndexOptions.partialFilterExpression[prefix + key] =
+ partialFilterExpression[key];
+ }
+ }
+
+ indexes.push([newindex, newIndexOptions]);
+ }
+ }
+};
diff --git a/node_modules/mongoose/lib/helpers/schema/getPath.js b/node_modules/mongoose/lib/helpers/schema/getPath.js
new file mode 100644
index 0000000..ccbc67c
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/getPath.js
@@ -0,0 +1,35 @@
+'use strict';
+
+/*!
+ * Behaves like `Schema#path()`, except for it also digs into arrays without
+ * needing to put `.0.`, so `getPath(schema, 'docArr.elProp')` works.
+ */
+
+module.exports = function getPath(schema, path) {
+ let schematype = schema.path(path);
+ if (schematype != null) {
+ return schematype;
+ }
+
+ const pieces = path.split('.');
+ let cur = '';
+ let isArray = false;
+
+ for (const piece of pieces) {
+ if (/^\d+$/.test(piece) && isArray) {
+ continue;
+ }
+ cur = cur.length === 0 ? piece : cur + '.' + piece;
+
+ schematype = schema.path(cur);
+ if (schematype != null && schematype.schema) {
+ schema = schematype.schema;
+ cur = '';
+ if (schematype.$isMongooseDocumentArray) {
+ isArray = true;
+ }
+ }
+ }
+
+ return schematype;
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/handleIdOption.js b/node_modules/mongoose/lib/helpers/schema/handleIdOption.js
new file mode 100644
index 0000000..569bf9f
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/handleIdOption.js
@@ -0,0 +1,20 @@
+'use strict';
+
+const addAutoId = require('./addAutoId');
+
+module.exports = function handleIdOption(schema, options) {
+ if (options == null || options._id == null) {
+ return schema;
+ }
+
+ schema = schema.clone();
+ if (!options._id) {
+ schema.remove('_id');
+ schema.options._id = false;
+ } else if (!schema.paths['_id']) {
+ addAutoId(schema);
+ schema.options._id = true;
+ }
+
+ return schema;
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/handleTimestampOption.js b/node_modules/mongoose/lib/helpers/schema/handleTimestampOption.js
new file mode 100644
index 0000000..1551b7c
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/handleTimestampOption.js
@@ -0,0 +1,24 @@
+'use strict';
+
+module.exports = handleTimestampOption;
+
+/*!
+ * ignore
+ */
+
+function handleTimestampOption(arg, prop) {
+ if (arg == null) {
+ return null;
+ }
+
+ if (typeof arg === 'boolean') {
+ return prop;
+ }
+ if (typeof arg[prop] === 'boolean') {
+ return arg[prop] ? prop : null;
+ }
+ if (!(prop in arg)) {
+ return prop;
+ }
+ return arg[prop];
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/schema/merge.js b/node_modules/mongoose/lib/helpers/schema/merge.js
new file mode 100644
index 0000000..d206500
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schema/merge.js
@@ -0,0 +1,19 @@
+'use strict';
+
+module.exports = function merge(s1, s2) {
+ s1.add(s2.tree || {});
+
+ s1.callQueue = s1.callQueue.concat(s2.callQueue);
+ s1.method(s2.methods);
+ s1.static(s2.statics);
+
+ for (const query in s2.query) {
+ s1.query[query] = s2.query[query];
+ }
+
+ for (const virtual in s2.virtuals) {
+ s1.virtuals[virtual] = s2.virtuals[virtual].clone();
+ }
+
+ s1.s.hooks.merge(s2.s.hooks, false);
+};
diff --git a/node_modules/mongoose/lib/helpers/schematype/handleImmutable.js b/node_modules/mongoose/lib/helpers/schematype/handleImmutable.js
new file mode 100644
index 0000000..e31c4af
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/schematype/handleImmutable.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const StrictModeError = require('../../error/strict');
+
+/*!
+ * ignore
+ */
+
+module.exports = function(schematype) {
+ if (schematype.$immutable) {
+ schematype.$immutableSetter = createImmutableSetter(schematype.path,
+ schematype.options.immutable);
+ schematype.set(schematype.$immutableSetter);
+ } else if (schematype.$immutableSetter) {
+ schematype.setters = schematype.setters.
+ filter(fn => fn !== schematype.$immutableSetter);
+ delete schematype.$immutableSetter;
+ }
+};
+
+function createImmutableSetter(path, immutable) {
+ return function immutableSetter(v) {
+ if (this == null || this.$__ == null) {
+ return v;
+ }
+ if (this.isNew) {
+ return v;
+ }
+
+ const _immutable = typeof immutable === 'function' ?
+ immutable.call(this, this) :
+ immutable;
+ if (!_immutable) {
+ return v;
+ }
+
+ const _value = this.$__getValue(path);
+ if (this.$__.strictMode === 'throw' && v !== _value) {
+ throw new StrictModeError(path, 'Path `' + path + '` is immutable ' +
+ 'and strict mode is set to throw.', true);
+ }
+
+ return _value;
+ };
+}
diff --git a/node_modules/mongoose/lib/helpers/setDefaultsOnInsert.js b/node_modules/mongoose/lib/helpers/setDefaultsOnInsert.js
new file mode 100644
index 0000000..14e3f1b
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/setDefaultsOnInsert.js
@@ -0,0 +1,127 @@
+'use strict';
+const modifiedPaths = require('./common').modifiedPaths;
+const get = require('./get');
+
+/**
+ * Applies defaults to update and findOneAndUpdate operations.
+ *
+ * @param {Object} filter
+ * @param {Schema} schema
+ * @param {Object} castedDoc
+ * @param {Object} options
+ * @method setDefaultsOnInsert
+ * @api private
+ */
+
+module.exports = function(filter, schema, castedDoc, options) {
+ options = options || {};
+
+ const shouldSetDefaultsOnInsert =
+ options.setDefaultsOnInsert != null ?
+ options.setDefaultsOnInsert :
+ schema.base.options.setDefaultsOnInsert;
+
+ if (!options.upsert || !shouldSetDefaultsOnInsert) {
+ return castedDoc;
+ }
+
+ const keys = Object.keys(castedDoc || {});
+ const updatedKeys = {};
+ const updatedValues = {};
+ const numKeys = keys.length;
+ const modified = {};
+
+ let hasDollarUpdate = false;
+
+ for (let i = 0; i < numKeys; ++i) {
+ if (keys[i].startsWith('$')) {
+ modifiedPaths(castedDoc[keys[i]], '', modified);
+ hasDollarUpdate = true;
+ }
+ }
+
+ if (!hasDollarUpdate) {
+ modifiedPaths(castedDoc, '', modified);
+ }
+
+ const paths = Object.keys(filter);
+ const numPaths = paths.length;
+ for (let i = 0; i < numPaths; ++i) {
+ const path = paths[i];
+ const condition = filter[path];
+ if (condition && typeof condition === 'object') {
+ const conditionKeys = Object.keys(condition);
+ const numConditionKeys = conditionKeys.length;
+ let hasDollarKey = false;
+ for (let j = 0; j < numConditionKeys; ++j) {
+ if (conditionKeys[j].startsWith('$')) {
+ hasDollarKey = true;
+ break;
+ }
+ }
+ if (hasDollarKey) {
+ continue;
+ }
+ }
+ updatedKeys[path] = true;
+ modified[path] = true;
+ }
+
+ if (options && options.overwrite && !hasDollarUpdate) {
+ // Defaults will be set later, since we're overwriting we'll cast
+ // the whole update to a document
+ return castedDoc;
+ }
+
+ schema.eachPath(function(path, schemaType) {
+ // Skip single nested paths if underneath a map
+ const isUnderneathMap = schemaType.path.endsWith('.$*') ||
+ schemaType.path.indexOf('.$*.') !== -1;
+ if (schemaType.$isSingleNested && !isUnderneathMap) {
+ // Only handle nested schemas 1-level deep to avoid infinite
+ // recursion re: https://github.com/mongodb-js/mongoose-autopopulate/issues/11
+ schemaType.schema.eachPath(function(_path, _schemaType) {
+ if (_path === '_id' && _schemaType.auto) {
+ // Ignore _id if auto id so we don't create subdocs
+ return;
+ }
+
+ const def = _schemaType.getDefault(null, true);
+ if (!isModified(modified, path + '.' + _path) &&
+ typeof def !== 'undefined') {
+ castedDoc = castedDoc || {};
+ castedDoc.$setOnInsert = castedDoc.$setOnInsert || {};
+ castedDoc.$setOnInsert[path + '.' + _path] = def;
+ updatedValues[path + '.' + _path] = def;
+ }
+ });
+ } else {
+ const def = schemaType.getDefault(null, true);
+ if (!isModified(modified, path) && typeof def !== 'undefined') {
+ castedDoc = castedDoc || {};
+ castedDoc.$setOnInsert = castedDoc.$setOnInsert || {};
+ if (get(castedDoc, path) == null) {
+ castedDoc.$setOnInsert[path] = def;
+ }
+ updatedValues[path] = def;
+ }
+ }
+ });
+
+ return castedDoc;
+};
+
+function isModified(modified, path) {
+ if (modified[path]) {
+ return true;
+ }
+ const sp = path.split('.');
+ let cur = sp[0];
+ for (let i = 1; i < sp.length; ++i) {
+ if (modified[cur]) {
+ return true;
+ }
+ cur += '.' + sp[i];
+ }
+ return false;
+}
diff --git a/node_modules/mongoose/lib/helpers/specialProperties.js b/node_modules/mongoose/lib/helpers/specialProperties.js
new file mode 100644
index 0000000..1e1aca5
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/specialProperties.js
@@ -0,0 +1,3 @@
+'use strict';
+
+module.exports = new Set(['__proto__', 'constructor', 'prototype']); \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/symbols.js b/node_modules/mongoose/lib/helpers/symbols.js
new file mode 100644
index 0000000..9d619f7
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/symbols.js
@@ -0,0 +1,19 @@
+'use strict';
+
+exports.arrayAtomicsSymbol = Symbol('mongoose#Array#_atomics');
+exports.arrayParentSymbol = Symbol('mongoose#Array#_parent');
+exports.arrayPathSymbol = Symbol('mongoose#Array#_path');
+exports.arraySchemaSymbol = Symbol('mongoose#Array#_schema');
+exports.documentArrayParent = Symbol('mongoose:documentArrayParent');
+exports.documentIsSelected = Symbol('mongoose#Document#isSelected');
+exports.documentIsModified = Symbol('mongoose#Document#isModified');
+exports.documentModifiedPaths = Symbol('mongoose#Document#modifiedPaths');
+exports.documentSchemaSymbol = Symbol('mongoose#Document#schema');
+exports.getSymbol = Symbol('mongoose#Document#get');
+exports.modelSymbol = Symbol('mongoose#Model');
+exports.objectIdSymbol = Symbol('mongoose#ObjectId');
+exports.populateModelSymbol = Symbol('mongoose.PopulateOptions#Model');
+exports.schemaTypeSymbol = Symbol('mongoose#schemaType');
+exports.sessionNewDocuments = Symbol('mongoose:ClientSession#newDocuments');
+exports.scopeSymbol = Symbol('mongoose#Document#scope');
+exports.validatorErrorSymbol = Symbol('mongoose:validatorError'); \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/timestamps/setupTimestamps.js b/node_modules/mongoose/lib/helpers/timestamps/setupTimestamps.js
new file mode 100644
index 0000000..752a565
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/timestamps/setupTimestamps.js
@@ -0,0 +1,104 @@
+'use strict';
+
+const applyTimestampsToChildren = require('../update/applyTimestampsToChildren');
+const applyTimestampsToUpdate = require('../update/applyTimestampsToUpdate');
+const get = require('../get');
+const handleTimestampOption = require('../schema/handleTimestampOption');
+const symbols = require('../../schema/symbols');
+
+module.exports = function setupTimestamps(schema, timestamps) {
+ const childHasTimestamp = schema.childSchemas.find(withTimestamp);
+
+ function withTimestamp(s) {
+ const ts = s.schema.options.timestamps;
+ return !!ts;
+ }
+
+ if (!timestamps && !childHasTimestamp) {
+ return;
+ }
+
+ const createdAt = handleTimestampOption(timestamps, 'createdAt');
+ const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+ const currentTime = timestamps != null && timestamps.hasOwnProperty('currentTime') ?
+ timestamps.currentTime :
+ null;
+ const schemaAdditions = {};
+
+ schema.$timestamps = { createdAt: createdAt, updatedAt: updatedAt };
+
+ if (updatedAt && !schema.paths[updatedAt]) {
+ schemaAdditions[updatedAt] = Date;
+ }
+
+ if (createdAt && !schema.paths[createdAt]) {
+ schemaAdditions[createdAt] = Date;
+ }
+
+ schema.add(schemaAdditions);
+
+ schema.pre('save', function(next) {
+ const timestampOption = get(this, '$__.saveOptions.timestamps');
+ if (timestampOption === false) {
+ return next();
+ }
+
+ const skipUpdatedAt = timestampOption != null && timestampOption.updatedAt === false;
+ const skipCreatedAt = timestampOption != null && timestampOption.createdAt === false;
+
+ const defaultTimestamp = currentTime != null ?
+ currentTime() :
+ (this.ownerDocument ? this.ownerDocument() : this).constructor.base.now();
+ const auto_id = this._id && this._id.auto;
+
+ if (!skipCreatedAt && createdAt && !this.get(createdAt) && this.isSelected(createdAt)) {
+ this.$set(createdAt, auto_id ? this._id.getTimestamp() : defaultTimestamp);
+ }
+
+ if (!skipUpdatedAt && updatedAt && (this.isNew || this.isModified())) {
+ let ts = defaultTimestamp;
+ if (this.isNew) {
+ if (createdAt != null) {
+ ts = this.$__getValue(createdAt);
+ } else if (auto_id) {
+ ts = this._id.getTimestamp();
+ }
+ }
+ this.$set(updatedAt, ts);
+ }
+
+ next();
+ });
+
+ schema.methods.initializeTimestamps = function() {
+ const ts = currentTime != null ?
+ currentTime() :
+ this.constructor.base.now();
+ if (createdAt && !this.get(createdAt)) {
+ this.$set(createdAt, ts);
+ }
+ if (updatedAt && !this.get(updatedAt)) {
+ this.$set(updatedAt, ts);
+ }
+ return this;
+ };
+
+ _setTimestampsOnUpdate[symbols.builtInMiddleware] = true;
+
+ const opts = { query: true, model: false };
+ schema.pre('findOneAndUpdate', opts, _setTimestampsOnUpdate);
+ schema.pre('replaceOne', opts, _setTimestampsOnUpdate);
+ schema.pre('update', opts, _setTimestampsOnUpdate);
+ schema.pre('updateOne', opts, _setTimestampsOnUpdate);
+ schema.pre('updateMany', opts, _setTimestampsOnUpdate);
+
+ function _setTimestampsOnUpdate(next) {
+ const now = currentTime != null ?
+ currentTime() :
+ this.model.base.now();
+ applyTimestampsToUpdate(now, createdAt, updatedAt, this.getUpdate(),
+ this.options, this.schema);
+ applyTimestampsToChildren(now, this.getUpdate(), this.model.schema);
+ next();
+ }
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/topology/allServersUnknown.js b/node_modules/mongoose/lib/helpers/topology/allServersUnknown.js
new file mode 100644
index 0000000..d3c7b4b
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/topology/allServersUnknown.js
@@ -0,0 +1,11 @@
+'use strict';
+
+module.exports = function allServersUnknown(topologyDescription) {
+ if (topologyDescription == null ||
+ topologyDescription.constructor.name !== 'TopologyDescription') {
+ return false;
+ }
+
+ const servers = Array.from(topologyDescription.servers.values());
+ return servers.length > 0 && servers.every(server => server.type === 'Unknown');
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/topology/isAtlas.js b/node_modules/mongoose/lib/helpers/topology/isAtlas.js
new file mode 100644
index 0000000..3bb8129
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/topology/isAtlas.js
@@ -0,0 +1,12 @@
+'use strict';
+
+module.exports = function isAtlas(topologyDescription) {
+ if (topologyDescription == null ||
+ topologyDescription.constructor.name !== 'TopologyDescription') {
+ return false;
+ }
+
+ const hostnames = Array.from(topologyDescription.servers.keys());
+ return hostnames.length > 0 &&
+ hostnames.every(host => host.endsWith('.mongodb.net:27017'));
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/topology/isSSLError.js b/node_modules/mongoose/lib/helpers/topology/isSSLError.js
new file mode 100644
index 0000000..61e57d1
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/topology/isSSLError.js
@@ -0,0 +1,15 @@
+'use strict';
+
+const nonSSLMessage = 'Client network socket disconnected before secure TLS ' +
+ 'connection was established';
+
+module.exports = function isSSLError(topologyDescription) {
+ if (topologyDescription == null ||
+ topologyDescription.constructor.name !== 'TopologyDescription') {
+ return false;
+ }
+
+ const descriptions = Array.from(topologyDescription.servers.values());
+ return descriptions.length > 0 &&
+ descriptions.every(descr => descr.error && descr.error.message.indexOf(nonSSLMessage) !== -1);
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/update/applyTimestampsToChildren.js b/node_modules/mongoose/lib/helpers/update/applyTimestampsToChildren.js
new file mode 100644
index 0000000..680d692
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/update/applyTimestampsToChildren.js
@@ -0,0 +1,172 @@
+'use strict';
+
+const cleanPositionalOperators = require('../schema/cleanPositionalOperators');
+const handleTimestampOption = require('../schema/handleTimestampOption');
+
+module.exports = applyTimestampsToChildren;
+
+/*!
+ * ignore
+ */
+
+function applyTimestampsToChildren(now, update, schema) {
+ if (update == null) {
+ return;
+ }
+
+ const keys = Object.keys(update);
+ const hasDollarKey = keys.some(key => key.startsWith('$'));
+
+ if (hasDollarKey) {
+ if (update.$push) {
+ for (const key of Object.keys(update.$push)) {
+ const $path = schema.path(key);
+ if (update.$push[key] &&
+ $path &&
+ $path.$isMongooseDocumentArray &&
+ $path.schema.options.timestamps) {
+ const timestamps = $path.schema.options.timestamps;
+ const createdAt = handleTimestampOption(timestamps, 'createdAt');
+ const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+ if (update.$push[key].$each) {
+ update.$push[key].$each.forEach(function(subdoc) {
+ if (updatedAt != null) {
+ subdoc[updatedAt] = now;
+ }
+ if (createdAt != null) {
+ subdoc[createdAt] = now;
+ }
+ });
+ } else {
+ if (updatedAt != null) {
+ update.$push[key][updatedAt] = now;
+ }
+ if (createdAt != null) {
+ update.$push[key][createdAt] = now;
+ }
+ }
+ }
+ }
+ }
+ if (update.$set != null) {
+ const keys = Object.keys(update.$set);
+ for (const key of keys) {
+ applyTimestampsToUpdateKey(schema, key, update.$set, now);
+ }
+ }
+ }
+
+ const updateKeys = Object.keys(update).filter(key => !key.startsWith('$'));
+ for (const key of updateKeys) {
+ applyTimestampsToUpdateKey(schema, key, update, now);
+ }
+}
+
+function applyTimestampsToDocumentArray(arr, schematype, now) {
+ const timestamps = schematype.schema.options.timestamps;
+
+ if (!timestamps) {
+ return;
+ }
+
+ const len = arr.length;
+
+ const createdAt = handleTimestampOption(timestamps, 'createdAt');
+ const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+ for (let i = 0; i < len; ++i) {
+ if (updatedAt != null) {
+ arr[i][updatedAt] = now;
+ }
+ if (createdAt != null) {
+ arr[i][createdAt] = now;
+ }
+
+ applyTimestampsToChildren(now, arr[i], schematype.schema);
+ }
+}
+
+function applyTimestampsToSingleNested(subdoc, schematype, now) {
+ const timestamps = schematype.schema.options.timestamps;
+ if (!timestamps) {
+ return;
+ }
+
+ const createdAt = handleTimestampOption(timestamps, 'createdAt');
+ const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+ if (updatedAt != null) {
+ subdoc[updatedAt] = now;
+ }
+ if (createdAt != null) {
+ subdoc[createdAt] = now;
+ }
+
+ applyTimestampsToChildren(now, subdoc, schematype.schema);
+}
+
+function applyTimestampsToUpdateKey(schema, key, update, now) {
+ // Replace positional operator `$` and array filters `$[]` and `$[.*]`
+ const keyToSearch = cleanPositionalOperators(key);
+ const path = schema.path(keyToSearch);
+ if (!path) {
+ return;
+ }
+
+ const parentSchemaTypes = [];
+ const pieces = keyToSearch.split('.');
+ for (let i = pieces.length - 1; i > 0; --i) {
+ const s = schema.path(pieces.slice(0, i).join('.'));
+ if (s != null &&
+ (s.$isMongooseDocumentArray || s.$isSingleNested)) {
+ parentSchemaTypes.push({ parentPath: key.split('.').slice(0, i).join('.'), parentSchemaType: s });
+ }
+ }
+
+ if (Array.isArray(update[key]) && path.$isMongooseDocumentArray) {
+ applyTimestampsToDocumentArray(update[key], path, now);
+ } else if (update[key] && path.$isSingleNested) {
+ applyTimestampsToSingleNested(update[key], path, now);
+ } else if (parentSchemaTypes.length > 0) {
+ for (const item of parentSchemaTypes) {
+ const parentPath = item.parentPath;
+ const parentSchemaType = item.parentSchemaType;
+ const timestamps = parentSchemaType.schema.options.timestamps;
+ const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+
+ if (!timestamps || updatedAt == null) {
+ continue;
+ }
+
+ if (parentSchemaType.$isSingleNested) {
+ // Single nested is easy
+ update[parentPath + '.' + updatedAt] = now;
+ } else if (parentSchemaType.$isMongooseDocumentArray) {
+ let childPath = key.substr(parentPath.length + 1);
+
+ if (/^\d+$/.test(childPath)) {
+ update[parentPath + '.' + childPath][updatedAt] = now;
+ continue;
+ }
+
+ const firstDot = childPath.indexOf('.');
+ childPath = firstDot !== -1 ? childPath.substr(0, firstDot) : childPath;
+
+ update[parentPath + '.' + childPath + '.' + updatedAt] = now;
+ }
+ }
+ } else if (path.schema != null && path.schema != schema && update[key]) {
+ const timestamps = path.schema.options.timestamps;
+ const createdAt = handleTimestampOption(timestamps, 'createdAt');
+ const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
+
+ if (!timestamps) {
+ return;
+ }
+
+ if (updatedAt != null) {
+ update[key][updatedAt] = now;
+ }
+ if (createdAt != null) {
+ update[key][createdAt] = now;
+ }
+ }
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/update/applyTimestampsToUpdate.js b/node_modules/mongoose/lib/helpers/update/applyTimestampsToUpdate.js
new file mode 100644
index 0000000..27d6e32
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/update/applyTimestampsToUpdate.js
@@ -0,0 +1,119 @@
+'use strict';
+
+/*!
+ * ignore
+ */
+
+const get = require('../get');
+
+module.exports = applyTimestampsToUpdate;
+
+/*!
+ * ignore
+ */
+
+function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, options) {
+ const updates = currentUpdate;
+ let _updates = updates;
+ const overwrite = get(options, 'overwrite', false);
+ const timestamps = get(options, 'timestamps', true);
+
+ // Support skipping timestamps at the query level, see gh-6980
+ if (!timestamps || updates == null) {
+ return currentUpdate;
+ }
+
+ const skipCreatedAt = timestamps != null && timestamps.createdAt === false;
+ const skipUpdatedAt = timestamps != null && timestamps.updatedAt === false;
+
+ if (overwrite) {
+ if (currentUpdate && currentUpdate.$set) {
+ currentUpdate = currentUpdate.$set;
+ updates.$set = {};
+ _updates = updates.$set;
+ }
+ if (!skipUpdatedAt && updatedAt && !currentUpdate[updatedAt]) {
+ _updates[updatedAt] = now;
+ }
+ if (!skipCreatedAt && createdAt && !currentUpdate[createdAt]) {
+ _updates[createdAt] = now;
+ }
+ return updates;
+ }
+ currentUpdate = currentUpdate || {};
+
+ if (Array.isArray(updates)) {
+ // Update with aggregation pipeline
+ updates.push({ $set: { updatedAt: now } });
+
+ return updates;
+ }
+
+ updates.$set = updates.$set || {};
+ if (!skipUpdatedAt && updatedAt &&
+ (!currentUpdate.$currentDate || !currentUpdate.$currentDate[updatedAt])) {
+ let timestampSet = false;
+ if (updatedAt.indexOf('.') !== -1) {
+ const pieces = updatedAt.split('.');
+ for (let i = 1; i < pieces.length; ++i) {
+ const remnant = pieces.slice(-i).join('.');
+ const start = pieces.slice(0, -i).join('.');
+ if (currentUpdate[start] != null) {
+ currentUpdate[start][remnant] = now;
+ timestampSet = true;
+ break;
+ } else if (currentUpdate.$set && currentUpdate.$set[start]) {
+ currentUpdate.$set[start][remnant] = now;
+ timestampSet = true;
+ break;
+ }
+ }
+ }
+
+ if (!timestampSet) {
+ updates.$set[updatedAt] = now;
+ }
+
+ if (updates.hasOwnProperty(updatedAt)) {
+ delete updates[updatedAt];
+ }
+ }
+
+ if (!skipCreatedAt && createdAt) {
+ if (currentUpdate[createdAt]) {
+ delete currentUpdate[createdAt];
+ }
+ if (currentUpdate.$set && currentUpdate.$set[createdAt]) {
+ delete currentUpdate.$set[createdAt];
+ }
+
+ let timestampSet = false;
+ if (createdAt.indexOf('.') !== -1) {
+ const pieces = createdAt.split('.');
+ for (let i = 1; i < pieces.length; ++i) {
+ const remnant = pieces.slice(-i).join('.');
+ const start = pieces.slice(0, -i).join('.');
+ if (currentUpdate[start] != null) {
+ currentUpdate[start][remnant] = now;
+ timestampSet = true;
+ break;
+ } else if (currentUpdate.$set && currentUpdate.$set[start]) {
+ currentUpdate.$set[start][remnant] = now;
+ timestampSet = true;
+ break;
+ }
+ }
+ }
+
+ if (!timestampSet) {
+ updates.$setOnInsert = updates.$setOnInsert || {};
+ updates.$setOnInsert[createdAt] = now;
+ }
+ }
+
+ if (Object.keys(updates.$set).length === 0) {
+ delete updates.$set;
+ }
+
+ return updates;
+}
diff --git a/node_modules/mongoose/lib/helpers/update/castArrayFilters.js b/node_modules/mongoose/lib/helpers/update/castArrayFilters.js
new file mode 100644
index 0000000..57018d9
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/update/castArrayFilters.js
@@ -0,0 +1,78 @@
+'use strict';
+
+const castFilterPath = require('../query/castFilterPath');
+const cleanPositionalOperators = require('../schema/cleanPositionalOperators');
+const getPath = require('../schema/getPath');
+const modifiedPaths = require('./modifiedPaths');
+
+module.exports = function castArrayFilters(query) {
+ const arrayFilters = query.options.arrayFilters;
+ if (!Array.isArray(arrayFilters)) {
+ return;
+ }
+
+ const update = query.getUpdate();
+ const schema = query.schema;
+ const strictQuery = schema.options.strictQuery;
+
+ const updatedPaths = modifiedPaths(update);
+
+ const updatedPathsByFilter = Object.keys(updatedPaths).reduce((cur, path) => {
+ const matches = path.match(/\$\[[^\]]+\]/g);
+ if (matches == null) {
+ return cur;
+ }
+ for (const match of matches) {
+ const firstMatch = path.indexOf(match);
+ if (firstMatch !== path.lastIndexOf(match)) {
+ throw new Error(`Path '${path}' contains the same array filter multiple times`);
+ }
+ cur[match.substring(2, match.length - 1)] = path.
+ substr(0, firstMatch - 1).
+ replace(/\$\[[^\]]+\]/g, '0');
+ }
+ return cur;
+ }, {});
+
+ for (const filter of arrayFilters) {
+ if (filter == null) {
+ throw new Error(`Got null array filter in ${arrayFilters}`);
+ }
+ for (const key in filter) {
+
+ if (filter[key] == null) {
+ continue;
+ }
+
+ const dot = key.indexOf('.');
+ let filterPath = dot === -1 ?
+ updatedPathsByFilter[key] + '.0' :
+ updatedPathsByFilter[key.substr(0, dot)] + '.0' + key.substr(dot);
+
+ if (filterPath == null) {
+ throw new Error(`Filter path not found for ${key}`);
+ }
+
+ // If there are multiple array filters in the path being updated, make sure
+ // to replace them so we can get the schema path.
+ filterPath = cleanPositionalOperators(filterPath);
+
+ const schematype = getPath(schema, filterPath);
+ if (schematype == null) {
+ if (!strictQuery) {
+ return;
+ }
+ // For now, treat `strictQuery = true` and `strictQuery = 'throw'` as
+ // equivalent for casting array filters. `strictQuery = true` doesn't
+ // quite work in this context because we never want to silently strip out
+ // array filters, even if the path isn't in the schema.
+ throw new Error(`Could not find path "${filterPath}" in schema`);
+ }
+ if (typeof filter[key] === 'object') {
+ filter[key] = castFilterPath(query, schematype, filter[key]);
+ } else {
+ filter[key] = schematype.castForQuery(filter[key]);
+ }
+ }
+ }
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/update/modifiedPaths.js b/node_modules/mongoose/lib/helpers/update/modifiedPaths.js
new file mode 100644
index 0000000..9cb567d
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/update/modifiedPaths.js
@@ -0,0 +1,33 @@
+'use strict';
+
+const _modifiedPaths = require('../common').modifiedPaths;
+
+/**
+ * Given an update document with potential update operators (`$set`, etc.)
+ * returns an object whose keys are the directly modified paths.
+ *
+ * If there are any top-level keys that don't start with `$`, we assume those
+ * will get wrapped in a `$set`. The Mongoose Query is responsible for wrapping
+ * top-level keys in `$set`.
+ *
+ * @param {Object} update
+ * @return {Object} modified
+ */
+
+module.exports = function modifiedPaths(update) {
+ const keys = Object.keys(update);
+ const res = {};
+
+ const withoutDollarKeys = {};
+ for (const key of keys) {
+ if (key.startsWith('$')) {
+ _modifiedPaths(update[key], '', res);
+ continue;
+ }
+ withoutDollarKeys[key] = update[key];
+ }
+
+ _modifiedPaths(withoutDollarKeys, '', res);
+
+ return res;
+};
diff --git a/node_modules/mongoose/lib/helpers/update/moveImmutableProperties.js b/node_modules/mongoose/lib/helpers/update/moveImmutableProperties.js
new file mode 100644
index 0000000..8541c5b
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/update/moveImmutableProperties.js
@@ -0,0 +1,53 @@
+'use strict';
+
+const get = require('../get');
+
+/**
+ * Given an update, move all $set on immutable properties to $setOnInsert.
+ * This should only be called for upserts, because $setOnInsert bypasses the
+ * strictness check for immutable properties.
+ */
+
+module.exports = function moveImmutableProperties(schema, update, ctx) {
+ if (update == null) {
+ return;
+ }
+
+ const keys = Object.keys(update);
+ for (const key of keys) {
+ const isDollarKey = key.startsWith('$');
+
+ if (key === '$set') {
+ const updatedPaths = Object.keys(update[key]);
+ for (const path of updatedPaths) {
+ _walkUpdatePath(schema, update[key], path, update, ctx);
+ }
+ } else if (!isDollarKey) {
+ _walkUpdatePath(schema, update, key, update, ctx);
+ }
+
+ }
+};
+
+function _walkUpdatePath(schema, op, path, update, ctx) {
+ const schematype = schema.path(path);
+ if (schematype == null) {
+ return;
+ }
+
+ let immutable = get(schematype, 'options.immutable', null);
+ if (immutable == null) {
+ return;
+ }
+ if (typeof immutable === 'function') {
+ immutable = immutable.call(ctx, ctx);
+ }
+
+ if (!immutable) {
+ return;
+ }
+
+ update.$setOnInsert = update.$setOnInsert || {};
+ update.$setOnInsert[path] = op[path];
+ delete op[path];
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/update/removeUnusedArrayFilters.js b/node_modules/mongoose/lib/helpers/update/removeUnusedArrayFilters.js
new file mode 100644
index 0000000..d460628
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/update/removeUnusedArrayFilters.js
@@ -0,0 +1,18 @@
+'use strict';
+
+/**
+ * MongoDB throws an error if there's unused array filters. That is, if `options.arrayFilters` defines
+ * a filter, but none of the `update` keys use it. This should be enough to filter out all unused array
+ * filters.
+ */
+
+module.exports = function removeUnusedArrayFilters(update, arrayFilters) {
+ const updateKeys = Object.keys(update).map(key => Object.keys(update[key])).reduce((cur, arr) => cur.concat(arr), []);
+ return arrayFilters.filter(obj => {
+ const firstKey = Object.keys(obj)[0];
+ const firstDot = firstKey.indexOf('.');
+ const arrayFilterKey = firstDot === -1 ? firstKey : firstKey.slice(0, firstDot);
+
+ return updateKeys.find(key => key.includes('$[' + arrayFilterKey + ']')) != null;
+ });
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/updateValidators.js b/node_modules/mongoose/lib/helpers/updateValidators.js
new file mode 100644
index 0000000..aeea634
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/updateValidators.js
@@ -0,0 +1,257 @@
+'use strict';
+
+/*!
+ * Module dependencies.
+ */
+
+const ValidationError = require('../error/validation');
+const cleanPositionalOperators = require('./schema/cleanPositionalOperators');
+const flatten = require('./common').flatten;
+const modifiedPaths = require('./common').modifiedPaths;
+
+/**
+ * Applies validators and defaults to update and findOneAndUpdate operations,
+ * specifically passing a null doc as `this` to validators and defaults
+ *
+ * @param {Query} query
+ * @param {Schema} schema
+ * @param {Object} castedDoc
+ * @param {Object} options
+ * @method runValidatorsOnUpdate
+ * @api private
+ */
+
+module.exports = function(query, schema, castedDoc, options, callback) {
+ let _keys;
+ const keys = Object.keys(castedDoc || {});
+ let updatedKeys = {};
+ let updatedValues = {};
+ const isPull = {};
+ const arrayAtomicUpdates = {};
+ const numKeys = keys.length;
+ let hasDollarUpdate = false;
+ const modified = {};
+ let currentUpdate;
+ let key;
+ let i;
+
+ for (i = 0; i < numKeys; ++i) {
+ if (keys[i].startsWith('$')) {
+ hasDollarUpdate = true;
+ if (keys[i] === '$push' || keys[i] === '$addToSet') {
+ _keys = Object.keys(castedDoc[keys[i]]);
+ for (let ii = 0; ii < _keys.length; ++ii) {
+ currentUpdate = castedDoc[keys[i]][_keys[ii]];
+ if (currentUpdate && currentUpdate.$each) {
+ arrayAtomicUpdates[_keys[ii]] = (arrayAtomicUpdates[_keys[ii]] || []).
+ concat(currentUpdate.$each);
+ } else {
+ arrayAtomicUpdates[_keys[ii]] = (arrayAtomicUpdates[_keys[ii]] || []).
+ concat([currentUpdate]);
+ }
+ }
+ continue;
+ }
+ modifiedPaths(castedDoc[keys[i]], '', modified);
+ const flat = flatten(castedDoc[keys[i]], null, null, schema);
+ const paths = Object.keys(flat);
+ const numPaths = paths.length;
+ for (let j = 0; j < numPaths; ++j) {
+ const updatedPath = cleanPositionalOperators(paths[j]);
+ key = keys[i];
+ // With `$pull` we might flatten `$in`. Skip stuff nested under `$in`
+ // for the rest of the logic, it will get handled later.
+ if (updatedPath.includes('$')) {
+ continue;
+ }
+ if (key === '$set' || key === '$setOnInsert' ||
+ key === '$pull' || key === '$pullAll') {
+ updatedValues[updatedPath] = flat[paths[j]];
+ isPull[updatedPath] = key === '$pull' || key === '$pullAll';
+ } else if (key === '$unset') {
+ updatedValues[updatedPath] = undefined;
+ }
+ updatedKeys[updatedPath] = true;
+ }
+ }
+ }
+
+ if (!hasDollarUpdate) {
+ modifiedPaths(castedDoc, '', modified);
+ updatedValues = flatten(castedDoc, null, null, schema);
+ updatedKeys = Object.keys(updatedValues);
+ }
+
+ const updates = Object.keys(updatedValues);
+ const numUpdates = updates.length;
+ const validatorsToExecute = [];
+ const validationErrors = [];
+
+ const alreadyValidated = [];
+
+ const context = options && options.context === 'query' ? query : null;
+ function iter(i, v) {
+ const schemaPath = schema._getSchema(updates[i]);
+ if (schemaPath == null) {
+ return;
+ }
+ if (schemaPath.instance === 'Mixed' && schemaPath.path !== updates[i]) {
+ return;
+ }
+
+ if (v && Array.isArray(v.$in)) {
+ v.$in.forEach((v, i) => {
+ validatorsToExecute.push(function(callback) {
+ schemaPath.doValidate(
+ v,
+ function(err) {
+ if (err) {
+ err.path = updates[i] + '.$in.' + i;
+ validationErrors.push(err);
+ }
+ callback(null);
+ },
+ context,
+ { updateValidator: true });
+ });
+ });
+ } else {
+ if (isPull[updates[i]] &&
+ schemaPath.$isMongooseArray) {
+ return;
+ }
+
+ if (schemaPath.$isMongooseDocumentArrayElement && v != null && v.$__ != null) {
+ alreadyValidated.push(updates[i]);
+ validatorsToExecute.push(function(callback) {
+ schemaPath.doValidate(v, function(err) {
+ if (err) {
+ err.path = updates[i];
+ validationErrors.push(err);
+ return callback(null);
+ }
+
+ v.validate(function(err) {
+ if (err) {
+ if (err.errors) {
+ for (const key of Object.keys(err.errors)) {
+ const _err = err.errors[key];
+ _err.path = updates[i] + '.' + key;
+ validationErrors.push(_err);
+ }
+ } else {
+ err.path = updates[i];
+ validationErrors.push(err);
+ }
+ }
+ callback(null);
+ });
+ }, context, { updateValidator: true });
+ });
+ } else {
+ validatorsToExecute.push(function(callback) {
+ for (const path of alreadyValidated) {
+ if (updates[i].startsWith(path + '.')) {
+ return callback(null);
+ }
+ }
+
+ schemaPath.doValidate(v, function(err) {
+ if (schemaPath.schema != null &&
+ schemaPath.schema.options.storeSubdocValidationError === false &&
+ err instanceof ValidationError) {
+ return callback(null);
+ }
+
+ if (err) {
+ err.path = updates[i];
+ validationErrors.push(err);
+ }
+ callback(null);
+ }, context, { updateValidator: true });
+ });
+ }
+ }
+ }
+ for (i = 0; i < numUpdates; ++i) {
+ iter(i, updatedValues[updates[i]]);
+ }
+
+ const arrayUpdates = Object.keys(arrayAtomicUpdates);
+ for (const arrayUpdate of arrayUpdates) {
+ let schemaPath = schema._getSchema(arrayUpdate);
+ if (schemaPath && schemaPath.$isMongooseDocumentArray) {
+ validatorsToExecute.push(function(callback) {
+ schemaPath.doValidate(
+ arrayAtomicUpdates[arrayUpdate],
+ getValidationCallback(arrayUpdate, validationErrors, callback),
+ options && options.context === 'query' ? query : null);
+ });
+ } else {
+ schemaPath = schema._getSchema(arrayUpdate + '.0');
+ for (const atomicUpdate of arrayAtomicUpdates[arrayUpdate]) {
+ validatorsToExecute.push(function(callback) {
+ schemaPath.doValidate(
+ atomicUpdate,
+ getValidationCallback(arrayUpdate, validationErrors, callback),
+ options && options.context === 'query' ? query : null,
+ { updateValidator: true });
+ });
+ }
+ }
+ }
+
+ if (callback != null) {
+ let numValidators = validatorsToExecute.length;
+ if (numValidators === 0) {
+ return _done(callback);
+ }
+ for (const validator of validatorsToExecute) {
+ validator(function() {
+ if (--numValidators <= 0) {
+ _done(callback);
+ }
+ });
+ }
+
+ return;
+ }
+
+ return function(callback) {
+ let numValidators = validatorsToExecute.length;
+ if (numValidators === 0) {
+ return _done(callback);
+ }
+ for (const validator of validatorsToExecute) {
+ validator(function() {
+ if (--numValidators <= 0) {
+ _done(callback);
+ }
+ });
+ }
+ };
+
+ function _done(callback) {
+ if (validationErrors.length) {
+ const err = new ValidationError(null);
+
+ for (const validationError of validationErrors) {
+ err.addError(validationError.path, validationError);
+ }
+
+ return callback(err);
+ }
+ callback(null);
+ }
+
+ function getValidationCallback(arrayUpdate, validationErrors, callback) {
+ return function(err) {
+ if (err) {
+ err.path = arrayUpdate;
+ validationErrors.push(err);
+ }
+ callback(null);
+ };
+ }
+};
+