Refactoring day1

This commit is contained in:
2020-08-20 20:27:14 +02:00
parent 6aceefeb2f
commit b907489a75
481 changed files with 5321 additions and 5616 deletions

View File

@@ -909,32 +909,6 @@ Aggregate.prototype.facet = function(options) {
return this.append({ $facet: options });
};
/**
* Helper for [Atlas Text Search](https://docs.atlas.mongodb.com/reference/atlas-search/tutorial/)'s
* `$search` stage.
*
* ####Example:
*
* Model.aggregate().
* search({
* text: {
* query: 'baseball',
* path: 'plot'
* }
* });
*
* // Output: [{ plot: '...', title: '...' }]
*
* @param {Object} $search options
* @return {Aggregate} this
* @see $search https://docs.atlas.mongodb.com/reference/atlas-search/tutorial/
* @api public
*/
Aggregate.prototype.search = function(options) {
return this.append({ $search: options });
};
/**
* Returns the current pipeline
*

5
node_modules/mongoose/lib/cast.js generated vendored
View File

@@ -9,7 +9,6 @@ const StrictModeError = require('./error/strict');
const Types = require('./schema/index');
const castTextSearch = require('./schema/operators/text');
const get = require('./helpers/get');
const getSchemaDiscriminatorByValue = require('./helpers/discriminator/getSchemaDiscriminatorByValue');
const isOperator = require('./helpers/query/isOperator');
const util = require('util');
const isObject = require('./helpers/isObject');
@@ -43,10 +42,6 @@ module.exports = function cast(schema, obj, options, context) {
delete obj._bsontype;
}
if (schema != null && schema.discriminators != null && obj[schema.options.discriminatorKey] != null) {
schema = getSchemaDiscriminatorByValue(schema, obj[schema.options.discriminatorKey]) || schema;
}
const paths = Object.keys(obj);
let i = paths.length;
let _keys;

View File

@@ -14,17 +14,16 @@ const CastError = require('../error/cast');
*/
module.exports = function castBoolean(value, path) {
if (value == null) {
return value;
}
if (module.exports.convertToTrue.has(value)) {
return true;
}
if (module.exports.convertToFalse.has(value)) {
return false;
}
if (value == null) {
return value;
}
throw new CastError('boolean', value, path);
};

View File

@@ -27,6 +27,10 @@ function Collection(name, conn, opts) {
opts.capped = {};
}
opts.bufferCommands = undefined === opts.bufferCommands
? true
: opts.bufferCommands;
if (typeof opts.capped === 'number') {
opts.capped = { size: opts.capped };
}
@@ -36,7 +40,7 @@ function Collection(name, conn, opts) {
this.collectionName = name;
this.conn = conn;
this.queue = [];
this.buffer = true;
this.buffer = this.opts.bufferCommands;
this.emitter = new EventEmitter();
if (STATES.connected === this.conn.readyState) {
@@ -89,7 +93,7 @@ Collection.prototype.onOpen = function() {
*/
Collection.prototype.onClose = function(force) {
if (this._shouldBufferCommands() && !force) {
if (this.opts.bufferCommands && !force) {
this.buffer = true;
}
};
@@ -258,29 +262,6 @@ Collection.prototype.watch = function() {
throw new Error('Collection#watch unimplemented by driver');
};
/*!
* ignore
*/
Collection.prototype._shouldBufferCommands = function _shouldBufferCommands() {
const conn = this.conn;
const opts = this.opts;
if (opts.bufferCommands != null) {
return opts.bufferCommands;
}
if (opts && opts.schemaUserProvidedOptions != null && opts.schemaUserProvidedOptions.bufferCommands != null) {
return opts.schemaUserProvidedOptions.bufferCommands;
}
if (conn.config.bufferCommands != null) {
return conn.config.bufferCommands;
}
if (conn.base != null && conn.base.get('bufferCommands') != null) {
return conn.base.get('bufferCommands');
}
return true;
};
/*!
* Module exports.
*/

View File

@@ -22,9 +22,6 @@ const utils = require('./utils');
const parseConnectionString = require('mongodb/lib/core').parseConnectionString;
const arrayAtomicsSymbol = require('./helpers/symbols').arrayAtomicsSymbol;
const sessionNewDocuments = require('./helpers/symbols').sessionNewDocuments;
let id = 0;
/*!
@@ -420,76 +417,6 @@ Connection.prototype.startSession = _wrapConnHelper(function startSession(option
cb(null, session);
});
/**
* _Requires MongoDB >= 3.6.0._ Executes the wrapped async function
* in a transaction. Mongoose will commit the transaction if the
* async function executes successfully and attempt to retry if
* there was a retriable error.
*
* Calls the MongoDB driver's [`session.withTransaction()`](http://mongodb.github.io/node-mongodb-native/3.5/api/ClientSession.html#withTransaction),
* but also handles resetting Mongoose document state as shown below.
*
* ####Example:
*
* const doc = new Person({ name: 'Will Riker' });
* await db.transaction(async function setRank(session) {
* doc.rank = 'Captain';
* await doc.save({ session });
* doc.isNew; // false
*
* // Throw an error to abort the transaction
* throw new Error('Oops!');
* }).catch(() => {});
*
* // true, `transaction()` reset the document's state because the
* // transaction was aborted.
* doc.isNew;
*
* @method transaction
* @param {Function} fn Function to execute in a transaction
* @return {Promise<Any>} promise that resolves to the returned value of `fn`
* @api public
*/
Connection.prototype.transaction = function transaction(fn) {
return this.startSession().then(session => {
session[sessionNewDocuments] = new Map();
return session.withTransaction(() => fn(session)).
then(res => {
delete session[sessionNewDocuments];
return res;
}).
catch(err => {
// If transaction was aborted, we need to reset newly
// inserted documents' `isNew`.
for (const doc of session[sessionNewDocuments].keys()) {
const state = session[sessionNewDocuments].get(doc);
if (state.hasOwnProperty('isNew')) {
doc.isNew = state.isNew;
}
if (state.hasOwnProperty('versionKey')) {
doc.set(doc.schema.options.versionKey, state.versionKey);
}
for (const path of state.modifiedPaths) {
doc.$__.activePaths.paths[path] = 'modify';
doc.$__.activePaths.states.modify[path] = true;
}
for (const path of state.atomics.keys()) {
const val = doc.$__getValue(path);
if (val == null) {
continue;
}
val[arrayAtomicsSymbol] = state.atomics.get(path);
}
}
delete session[sessionNewDocuments];
throw err;
});
});
};
/**
* Helper for `dropCollection()`. Will delete the given collection, including
* all documents and indexes.
@@ -625,6 +552,7 @@ Connection.prototype.onOpen = function() {
* @param {Number} [options.reconnectTries=30] If you're connected to a single server or mongos proxy (as opposed to a replica set), the MongoDB driver will try to reconnect every `reconnectInterval` milliseconds for `reconnectTries` times, and give up afterward. When the driver gives up, the mongoose connection emits a `reconnectFailed` event. This option does nothing for replica set connections.
* @param {Number} [options.reconnectInterval=1000] See `reconnectTries` option above.
* @param {Class} [options.promiseLibrary] Sets the [underlying driver's promise library](http://mongodb.github.io/node-mongodb-native/3.1/api/MongoClient.html).
* @param {Number} [options.poolSize=5] The maximum number of sockets the MongoDB driver will keep open for this connection. By default, `poolSize` is 5. Keep in mind that, as of MongoDB 3.4, MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](http://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
* @param {Number} [options.bufferMaxEntries] This option does nothing if `useUnifiedTopology` is set. The MongoDB driver also has its own buffering mechanism that kicks in when the driver is disconnected. Set this option to 0 and set `bufferCommands` to `false` on your schemas if you want your database operations to fail immediately when the driver is not connected, as opposed to waiting for reconnection.
* @param {Number} [options.connectTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _during initial connection_. Defaults to 30000. This option is passed transparently to [Node.js' `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback).
* @param {Number} [options.socketTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. This is set to `30000` by default, you should set this to 2-3x your longest running operation if you expect some of your database operations to run longer than 20 seconds. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
@@ -635,6 +563,9 @@ Connection.prototype.onOpen = function() {
*/
Connection.prototype.openUri = function(uri, options, callback) {
this.readyState = STATES.connecting;
this._closeCalled = false;
if (typeof options === 'function') {
callback = options;
options = null;
@@ -659,23 +590,6 @@ Connection.prototype.openUri = function(uri, options, callback) {
typeof callback + '"');
}
if (this.readyState === STATES.connecting || this.readyState === STATES.connected) {
if (this._connectionString !== uri) {
throw new MongooseError('Can\'t call `openUri()` on an active connection with ' +
'different connection strings. Make sure you aren\'t calling `mongoose.connect()` ' +
'multiple times. See: https://mongoosejs.com/docs/connections.html#multiple_connections');
}
if (typeof callback === 'function') {
callback(null, this);
}
return this;
}
this._connectionString = uri;
this.readyState = STATES.connecting;
this._closeCalled = false;
const Promise = PromiseProvider.get();
const _this = this;
@@ -717,9 +631,7 @@ Connection.prototype.openUri = function(uri, options, callback) {
delete options.pass;
if (options.bufferCommands != null) {
if (options.bufferMaxEntries == null) {
options.bufferMaxEntries = 0;
}
options.bufferMaxEntries = 0;
this.config.bufferCommands = options.bufferCommands;
delete options.bufferCommands;
}
@@ -782,6 +694,18 @@ Connection.prototype.openUri = function(uri, options, callback) {
});
});
const _handleReconnect = () => {
// If we aren't disconnected, we assume this reconnect is due to a
// socket timeout. If there's no activity on a socket for
// `socketTimeoutMS`, the driver will attempt to reconnect and emit
// this event.
if (_this.readyState !== STATES.connected) {
_this.readyState = STATES.connected;
_this.emit('reconnect');
_this.emit('reconnected');
}
};
const promise = new Promise((resolve, reject) => {
const client = new mongodb.MongoClient(uri, options);
_this.client = client;
@@ -791,9 +715,111 @@ Connection.prototype.openUri = function(uri, options, callback) {
return reject(error);
}
_setClient(_this, client, options, dbName);
const db = dbName != null ? client.db(dbName) : client.db();
_this.db = db;
// `useUnifiedTopology` events
const type = get(db, 's.topology.s.description.type', '');
if (options.useUnifiedTopology) {
if (type === 'Single') {
const server = Array.from(db.s.topology.s.servers.values())[0];
server.s.topology.on('serverHeartbeatSucceeded', () => {
_handleReconnect();
});
server.s.pool.on('reconnect', () => {
_handleReconnect();
});
client.on('serverDescriptionChanged', ev => {
const newDescription = ev.newDescription;
if (newDescription.type === 'Standalone') {
_handleReconnect();
} else {
_this.readyState = STATES.disconnected;
}
});
} else if (type.startsWith('ReplicaSet')) {
client.on('topologyDescriptionChanged', ev => {
// Emit disconnected if we've lost connectivity to _all_ servers
// in the replica set.
const description = ev.newDescription;
const servers = Array.from(ev.newDescription.servers.values());
const allServersDisconnected = description.type === 'ReplicaSetNoPrimary' &&
servers.reduce((cur, d) => cur || d.type === 'Unknown', false);
if (_this.readyState === STATES.connected && allServersDisconnected) {
// Implicitly emits 'disconnected'
_this.readyState = STATES.disconnected;
} else if (_this.readyState === STATES.disconnected && !allServersDisconnected) {
_handleReconnect();
}
});
db.on('close', function() {
const type = get(db, 's.topology.s.description.type', '');
if (type !== 'ReplicaSetWithPrimary') {
// Implicitly emits 'disconnected'
_this.readyState = STATES.disconnected;
}
});
}
}
// Backwards compat for mongoose 4.x
db.on('reconnect', function() {
_handleReconnect();
});
db.s.topology.on('reconnectFailed', function() {
_this.emit('reconnectFailed');
});
if (!options.useUnifiedTopology) {
db.s.topology.on('left', function(data) {
_this.emit('left', data);
});
}
db.s.topology.on('joined', function(data) {
_this.emit('joined', data);
});
db.s.topology.on('fullsetup', function(data) {
_this.emit('fullsetup', data);
});
if (get(db, 's.topology.s.coreTopology.s.pool') != null) {
db.s.topology.s.coreTopology.s.pool.on('attemptReconnect', function() {
_this.emit('attemptReconnect');
});
}
if (!options.useUnifiedTopology || !type.startsWith('ReplicaSet')) {
db.on('close', function() {
// Implicitly emits 'disconnected'
_this.readyState = STATES.disconnected;
});
}
if (!options.useUnifiedTopology) {
client.on('left', function() {
if (_this.readyState === STATES.connected &&
get(db, 's.topology.s.coreTopology.s.replicaSetState.topologyType') === 'ReplicaSetNoPrimary') {
_this.readyState = STATES.disconnected;
}
});
}
db.on('timeout', function() {
_this.emit('timeout');
});
delete _this.then;
delete _this.catch;
_this.readyState = STATES.connected;
for (const i in _this.collections) {
if (utils.object.hasOwnProperty(_this.collections, i)) {
_this.collections[i].onOpen();
}
}
resolve(_this);
_this.emit('open');
});
});
@@ -827,126 +853,6 @@ Connection.prototype.openUri = function(uri, options, callback) {
return this;
};
function _setClient(conn, client, options, dbName) {
const db = dbName != null ? client.db(dbName) : client.db();
conn.db = db;
conn.client = client;
const _handleReconnect = () => {
// If we aren't disconnected, we assume this reconnect is due to a
// socket timeout. If there's no activity on a socket for
// `socketTimeoutMS`, the driver will attempt to reconnect and emit
// this event.
if (conn.readyState !== STATES.connected) {
conn.readyState = STATES.connected;
conn.emit('reconnect');
conn.emit('reconnected');
conn.onOpen();
}
};
// `useUnifiedTopology` events
const type = get(db, 's.topology.s.description.type', '');
if (options.useUnifiedTopology) {
if (type === 'Single') {
const server = Array.from(db.s.topology.s.servers.values())[0];
server.s.topology.on('serverHeartbeatSucceeded', () => {
_handleReconnect();
});
server.s.pool.on('reconnect', () => {
_handleReconnect();
});
client.on('serverDescriptionChanged', ev => {
const newDescription = ev.newDescription;
if (newDescription.type === 'Standalone') {
_handleReconnect();
} else {
conn.readyState = STATES.disconnected;
}
});
} else if (type.startsWith('ReplicaSet')) {
client.on('topologyDescriptionChanged', ev => {
// Emit disconnected if we've lost connectivity to _all_ servers
// in the replica set.
const description = ev.newDescription;
const servers = Array.from(ev.newDescription.servers.values());
const allServersDisconnected = description.type === 'ReplicaSetNoPrimary' &&
servers.reduce((cur, d) => cur || d.type === 'Unknown', false);
if (conn.readyState === STATES.connected && allServersDisconnected) {
// Implicitly emits 'disconnected'
conn.readyState = STATES.disconnected;
} else if (conn.readyState === STATES.disconnected && !allServersDisconnected) {
_handleReconnect();
}
});
db.on('close', function() {
const type = get(db, 's.topology.s.description.type', '');
if (type !== 'ReplicaSetWithPrimary') {
// Implicitly emits 'disconnected'
conn.readyState = STATES.disconnected;
}
});
}
}
// Backwards compat for mongoose 4.x
db.on('reconnect', function() {
_handleReconnect();
});
db.s.topology.on('reconnectFailed', function() {
conn.emit('reconnectFailed');
});
if (!options.useUnifiedTopology) {
db.s.topology.on('left', function(data) {
conn.emit('left', data);
});
}
db.s.topology.on('joined', function(data) {
conn.emit('joined', data);
});
db.s.topology.on('fullsetup', function(data) {
conn.emit('fullsetup', data);
});
if (get(db, 's.topology.s.coreTopology.s.pool') != null) {
db.s.topology.s.coreTopology.s.pool.on('attemptReconnect', function() {
conn.emit('attemptReconnect');
});
}
if (!options.useUnifiedTopology || !type.startsWith('ReplicaSet')) {
db.on('close', function() {
// Implicitly emits 'disconnected'
conn.readyState = STATES.disconnected;
});
}
if (!options.useUnifiedTopology) {
client.on('left', function() {
if (conn.readyState === STATES.connected &&
get(db, 's.topology.s.coreTopology.s.replicaSetState.topologyType') === 'ReplicaSetNoPrimary') {
conn.readyState = STATES.disconnected;
}
});
}
db.on('timeout', function() {
conn.emit('timeout');
});
delete conn.then;
delete conn.catch;
conn.readyState = STATES.connected;
for (const i in conn.collections) {
if (utils.object.hasOwnProperty(conn.collections, i)) {
conn.collections[i].onOpen();
}
}
conn.emit('open');
}
/*!
* ignore
*/
@@ -1361,57 +1267,6 @@ Connection.prototype.optionsProvideAuthenticationData = function(options) {
((options.pass) || this.authMechanismDoesNotRequirePassword());
};
/**
* Returns the [MongoDB driver `MongoClient`](http://mongodb.github.io/node-mongodb-native/3.5/api/MongoClient.html) instance
* that this connection uses to talk to MongoDB.
*
* ####Example:
* const conn = await mongoose.createConnection('mongodb://localhost:27017/test');
*
* conn.getClient(); // MongoClient { ... }
*
* @api public
* @return {MongoClient}
*/
Connection.prototype.getClient = function getClient() {
return this.client;
};
/**
* Set the [MongoDB driver `MongoClient`](http://mongodb.github.io/node-mongodb-native/3.5/api/MongoClient.html) instance
* that this connection uses to talk to MongoDB. This is useful if you already have a MongoClient instance, and want to
* reuse it.
*
* ####Example:
* const client = await mongodb.MongoClient.connect('mongodb://localhost:27017/test');
*
* const conn = mongoose.createConnection().setClient(client);
*
* conn.getClient(); // MongoClient { ... }
* conn.readyState; // 1, means 'CONNECTED'
*
* @api public
* @return {Connection} this
*/
Connection.prototype.setClient = function setClient(client) {
if (!(client instanceof mongodb.MongoClient)) {
throw new MongooseError('Must call `setClient()` with an instance of MongoClient');
}
if (this.client != null || this.readyState !== STATES.disconnected) {
throw new MongooseError('Cannot call `setClient()` on a connection that is already connected.');
}
if (!client.isConnected()) {
throw new MongooseError('Cannot call `setClient()` with a MongoClient that is not connected.');
}
this._connectionString = client.s.url;
_setClient(this, client, { useUnifiedTopology: client.s.options.useUnifiedTopology }, client.s.options.dbName);
return this;
};
/**
* Switches to a different database using the same connection pool.
*

153
node_modules/mongoose/lib/document.js generated vendored
View File

@@ -30,7 +30,6 @@ const isExclusive = require('./helpers/projection/isExclusive');
const inspect = require('util').inspect;
const internalToObjectOptions = require('./options').internalToObjectOptions;
const mpath = require('mpath');
const queryhelpers = require('./queryhelpers');
const utils = require('./utils');
const isPromise = require('./helpers/isPromise');
@@ -57,8 +56,7 @@ const specialProperties = utils.specialProperties;
*
* @param {Object} obj the values to set
* @param {Object} [fields] optional object containing the fields which were selected in the query returning this document and any populated paths data
* @param {Object} [options] various configuration options for the document
* @param {Boolean} [options.defaults=true] if `false`, skip applying default values to this document.
* @param {Boolean} [skipId] bool, should we auto create an ObjectId _id
* @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
* @event `init`: Emitted on a document after it has been retrieved from the db and fully hydrated by Mongoose.
* @event `save`: Emitted when the document is successfully saved
@@ -70,9 +68,7 @@ function Document(obj, fields, skipId, options) {
options = skipId;
skipId = options.skipId;
}
options = Object.assign({}, options);
const defaults = get(options, 'defaults', true);
options.defaults = defaults;
options = options || {};
// Support `browserDocument.js` syntax
if (this.schema == null) {
@@ -131,11 +127,9 @@ function Document(obj, fields, skipId, options) {
// By default, defaults get applied **before** setting initial values
// Re: gh-6155
if (defaults) {
$__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, true, {
isNew: this.isNew
});
}
$__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, true, {
isNew: this.isNew
});
}
if (obj) {
@@ -154,13 +148,13 @@ function Document(obj, fields, skipId, options) {
// Function defaults get applied **after** setting initial values so they
// see the full doc rather than an empty one, unless they opt out.
// Re: gh-3781, gh-6155
if (options.willInit && defaults) {
if (options.willInit) {
EventEmitter.prototype.once.call(this, 'init', () => {
$__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, false, options.skipDefaults, {
isNew: this.isNew
});
});
} else if (defaults) {
} else {
$__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, false, options.skipDefaults, {
isNew: this.isNew
});
@@ -548,16 +542,6 @@ Document.prototype.$__init = function(doc, opts) {
} else {
this.populated(item.path, item._docs[id], item);
}
if (item._childDocs == null) {
continue;
}
for (const child of item._childDocs) {
if (child == null || child.$__ == null) {
continue;
}
child.$__.parent = this;
}
}
}
@@ -657,7 +641,7 @@ function init(self, obj, doc, opts, prefix) {
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = schema._castNullish(null);
doc[i] = null;
} else if (obj[i] !== undefined) {
const intCache = obj[i].$__ || {};
const wasPopulated = intCache.wasPopulated || null;
@@ -1255,10 +1239,6 @@ Document.prototype.$set = function $set(path, val, type, options) {
delete this.$__.populated[path];
}
if (schema.$isSingleNested && val != null) {
_checkImmutableSubpaths(val, schema, priorVal);
}
this.$markValid(path);
} catch (e) {
if (e instanceof MongooseError.StrictModeError && e.isImmutableError) {
@@ -2476,7 +2456,7 @@ function _handlePathsToValidate(paths, pathsToValidate) {
*
* @param {Array|string} pathsToValidate only validate the given paths
* @param {Object} [options] options for validation
* @param {Boolean} [options.validateModifiedOnly=false] If `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
* @param {Boolean} [options.validateModifiedOnly=false] if `true` mongoose validates only modified paths.
* @return {ValidationError|undefined} ValidationError if there are errors during validation, or undefined if there is no error.
* @api public
*/
@@ -2657,29 +2637,6 @@ function _markValidSubpaths(doc, path) {
}
}
/*!
* ignore
*/
function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
const schema = schematype.schema;
if (schema == null) {
return;
}
for (const key of Object.keys(schema.paths)) {
const path = schema.paths[key];
if (path.$immutableSetter == null) {
continue;
}
const oldVal = priorVal == null ? void 0 : priorVal.$__getValue(key);
// Calling immutableSetter with `oldVal` even though it expects `newVal`
// is intentional. That's because `$immutableSetter` compares its param
// to the current value.
path.$immutableSetter.call(subdoc, oldVal);
}
}
/**
* Saves this document by inserting a new document into the database if [document.isNew](/docs/api.html#document_Document-isNew) is `true`,
* or sends an [updateOne](/docs/api.html#document_Document-updateOne) operation **only** with the modifications to the database, it does not replace the whole document in the latter case.
@@ -2701,7 +2658,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
* @param {Session} [options.session=null] the [session](https://docs.mongodb.com/manual/reference/server-sessions/) associated with this save operation. If not specified, defaults to the [document's associated session](api.html#document_Document-$session).
* @param {Object} [options.safe] (DEPRECATED) overrides [schema's safe option](http://mongoosejs.com//docs/guide.html#safe). Use the `w` option instead.
* @param {Boolean} [options.validateBeforeSave] set to false to save without validating.
* @param {Boolean} [options.validateModifiedOnly=false] If `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
* @param {Boolean} [options.validateModifiedOnly=false] if `true` mongoose validates only modified paths.
* @param {Number|String} [options.w] set the [write concern](https://docs.mongodb.com/manual/reference/write-concern/#w-option). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern)
* @param {Boolean} [options.j] set to true for MongoDB to wait until this `save()` has been [journaled before resolving the returned promise](https://docs.mongodb.com/manual/reference/write-concern/#j-option). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern)
* @param {Number} [options.wtimeout] sets a [timeout for the write concern](https://docs.mongodb.com/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern).
@@ -3122,10 +3079,6 @@ Document.prototype.$toObject = function(options, json) {
applySchemaTypeTransforms(this, ret);
}
if (options.useProjection) {
omitDeselectedFields(this, ret);
}
if (transform === true || (schemaOptions.toObject && transform)) {
const opts = options.json ? schemaOptions.toJSON : schemaOptions.toObject;
@@ -3161,7 +3114,6 @@ Document.prototype.$toObject = function(options, json) {
* - `depopulate` depopulate any populated paths, replacing them with their original refs, defaults to false
* - `versionKey` whether to include the version key, defaults to true
* - `flattenMaps` convert Maps to POJOs. Useful if you want to JSON.stringify() the result of toObject(), defaults to false
* - `useProjection` set to `true` to omit fields that are excluded in this document's projection. Unless you specified a projection, this will omit any field that has `select: false` in the schema.
*
* ####Getters/Virtuals
*
@@ -3286,7 +3238,6 @@ Document.prototype.$toObject = function(options, json) {
* @param {Boolean} [options.depopulate=false] if true, replace any conventionally populated paths with the original id in the output. Has no affect on virtual populated paths.
* @param {Boolean} [options.versionKey=true] if false, exclude the version key (`__v` by default) from the output
* @param {Boolean} [options.flattenMaps=false] if true, convert Maps to POJOs. Useful if you want to `JSON.stringify()` the result of `toObject()`.
* @param {Boolean} [options.useProjection=false] - If true, omits fields that are excluded in this document's projection. Unless you specified a projection, this will omit any field that has `select: false` in the schema.
* @return {Object} js object
* @see mongodb.Binary http://mongodb.github.com/node-mongodb-native/api-bson-generated/binary.html
* @api public
@@ -3490,37 +3441,6 @@ function throwErrorIfPromise(path, transformedValue) {
}
}
/*!
* ignore
*/
function omitDeselectedFields(self, json) {
const schema = self.schema;
const paths = Object.keys(schema.paths || {});
const cur = self._doc;
if (!cur) {
return json;
}
let selected = self.$__.selected;
if (selected === void 0) {
selected = {};
queryhelpers.applyPaths(selected, schema);
}
if (selected == null || Object.keys(selected).length === 0) {
return json;
}
for (const path of paths) {
if (selected[path] != null && !selected[path]) {
delete json[path];
}
}
return json;
}
/**
* The return value of this method is used in calls to JSON.stringify(doc).
*
@@ -3543,20 +3463,6 @@ Document.prototype.toJSON = function(options) {
return this.$toObject(options, true);
};
/**
* If this document is a subdocument or populated document, returns the document's
* parent. Returns `undefined` otherwise.
*
* @api public
* @method parent
* @memberOf Document
* @instance
*/
Document.prototype.parent = function() {
return this.$__.parent;
};
/**
* Helper for console.log
*
@@ -3930,45 +3836,6 @@ Document.prototype.$__fullPath = function(path) {
return path || '';
};
/**
* Returns the changes that happened to the document
* in the format that will be sent to MongoDB.
*
* ###Example:
* const userSchema = new Schema({
* name: String,
* age: Number,
* country: String
* });
* const User = mongoose.model('User', userSchema);
* const user = await User.create({
* name: 'Hafez',
* age: 25,
* country: 'Egypt'
* });
*
* // returns an empty object, no changes happened yet
* user.getChanges(); // { }
*
* user.country = undefined;
* user.age = 26;
*
* user.getChanges(); // { $set: { age: 26 }, { $unset: { country: 1 } } }
*
* await user.save();
*
* user.getChanges(); // { }
*
* @return {Object} changes
*/
Document.prototype.getChanges = function() {
const delta = this.$__delta();
const changes = delta ? delta[1] : {};
return changes;
};
/*!
* Module exports.
*/

View File

@@ -140,7 +140,7 @@ function iter(i) {
}
}
if (this._shouldBufferCommands() && this.buffer) {
if (this.buffer) {
if (syncCollectionMethods[i]) {
throw new Error('Collection method ' + i + ' is synchronous');
}
@@ -148,9 +148,6 @@ function iter(i) {
this.addQueue(i, args);
return;
}
this.conn.emit('buffer', { method: i, args: args });
return new this.Promise((resolve, reject) => {
this.addQueue(i, [].concat(args).concat([(err, res) => {
if (err != null) {
@@ -173,10 +170,6 @@ function iter(i) {
}
try {
if (collection == null) {
throw new MongooseError('Cannot call `' + this.name + '.' + i + '()` before initial connection is complete if `bufferCommands = false`. Make sure you `await mongoose.connect()` if you have `bufferCommands = false`.');
}
return collection[i].apply(collection, args);
} catch (error) {
// Collection operation may throw because of max bson size, catch it here

View File

@@ -28,8 +28,7 @@ class MongooseServerSelectionError extends MongooseError {
// Special message for a case that is likely due to IP whitelisting issues.
const isAtlasWhitelistError = isAtlas(reason) &&
allServersUnknown(reason) &&
err.message.indexOf('bad auth') === -1 &&
err.message.indexOf('Authentication failed') === -1;
err.message.indexOf('bad auth') === -1;
this.message = isAtlasWhitelistError ?
atlasMessage :
err.message;

View File

@@ -4,9 +4,10 @@
'use strict';
const MongooseError = require('./mongooseError');
const MongooseError = require('./');
const util = require('util');
class ValidationError extends MongooseError {
/**
* Document Validation Error
@@ -107,4 +108,4 @@ function _generateMessage(err) {
* Module exports
*/
module.exports = ValidationError;
module.exports = exports = ValidationError;

View File

@@ -38,14 +38,6 @@ class ValidatorError extends MongooseError {
toString() {
return this.message;
}
/*!
* Ensure `name` and `message` show up in toJSON output re: gh-9296
*/
toJSON() {
return Object.assign({ name: this.name, message: this.message }, this);
}
}

View File

@@ -4,14 +4,13 @@ module.exports = arrayDepth;
function arrayDepth(arr) {
if (!Array.isArray(arr)) {
return { min: 0, max: 0, containsNonArrayItem: true };
return { min: 0, max: 0 };
}
if (arr.length === 0) {
return { min: 1, max: 1, containsNonArrayItem: false };
return { min: 1, max: 1 };
}
const res = arrayDepth(arr[0]);
for (let i = 1; i < arr.length; ++i) {
const _res = arrayDepth(arr[i]);
if (_res.min < res.min) {
@@ -20,7 +19,6 @@ function arrayDepth(arr) {
if (_res.max > res.max) {
res.max = _res.max;
}
res.containsNonArrayItem = res.containsNonArrayItem || _res.containsNonArrayItem;
}
res.min = res.min + 1;

View File

@@ -124,13 +124,6 @@ function defineKey(prop, subprops, prototype, prefix, keys, options) {
}
});
Object.defineProperty(nested, '$__parent', {
enumerable: false,
configurable: true,
writable: false,
value: this
});
compile(subprops, nested, path, options);
this.$__.getters[path] = nested;
}
@@ -138,10 +131,8 @@ function defineKey(prop, subprops, prototype, prefix, keys, options) {
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.$__parent.get(path);
if (v instanceof Document) {
v = v.toObject({ transform: false });
}
const doc = this.$__[scopeSymbol] || this;
doc.$set(path, v);

View File

@@ -3,52 +3,8 @@
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;
}
// If these options are different, need to rebuild the index
const optionKeys = [
'unique',
'partialFilterExpression',
@@ -61,9 +17,6 @@ module.exports = function isIndexEqual(key, options, 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;
@@ -92,4 +45,4 @@ module.exports = function isIndexEqual(key, options, dbIndex) {
}
return true;
};
};

View File

@@ -37,12 +37,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
} 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.');
}
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;
@@ -58,6 +54,7 @@ module.exports = function castBulkWrite(originalModel, op, options) {
applyTimestampsToChildren(now, op['updateOne']['update'], model.schema);
if (op['updateOne'].setDefaultsOnInsert) {
setDefaultsOnInsert(op['updateOne']['filter'], model.schema, op['updateOne']['update'], {
setDefaultsOnInsert: true,
@@ -74,7 +71,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
strict: strict,
overwrite: false,
upsert: op['updateOne'].upsert
}, model, op['updateOne']['filter']);
});
} catch (error) {
return callback(error, null);
}
@@ -84,12 +82,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
} 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.');
}
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;
@@ -121,7 +115,7 @@ module.exports = function castBulkWrite(originalModel, op, options) {
strict: strict,
overwrite: false,
upsert: op['updateMany'].upsert
}, model, op['updateMany']['filter']);
});
} catch (error) {
return callback(error, null);
@@ -159,7 +153,6 @@ module.exports = function castBulkWrite(originalModel, op, options) {
if (error) {
return callback(error, null);
}
op['replaceOne']['replacement'] = op['replaceOne']['replacement'].toBSON();
callback(null);
});
};

View File

@@ -149,17 +149,11 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
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(', ') +
')');
' (can only modify ' +
Object.keys(CUSTOMIZABLE_DISCRIMINATOR_OPTIONS).join(', ') +
')');
}
}
}

View File

@@ -18,7 +18,6 @@ module.exports = function assignVals(o) {
justOne: o.justOne
});
populateOptions.$nullIfNotFound = o.isVirtual;
const populatedModel = o.populatedModel;
const originalIds = [].concat(o.rawIds);
@@ -40,31 +39,12 @@ module.exports = function assignVals(o) {
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);
return valueFilter(val[0], options, populateOptions);
} else if (o.justOne === false && !Array.isArray(val)) {
return valueFilter([val], options, populateOptions, populatedModel);
return valueFilter([val], options, populateOptions);
}
return valueFilter(val, options, populateOptions, populatedModel);
return valueFilter(val, options, populateOptions);
}
for (let i = 0; i < docs.length; ++i) {
@@ -104,16 +84,6 @@ module.exports = function assignVals(o) {
}, 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

View File

@@ -40,7 +40,6 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
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
@@ -77,7 +76,6 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
isRefPath = isRefPath || res.isRefPath;
normalizedRefPath = normalizeRefPath(normalizedRefPath, doc, options.path) ||
res.refPath;
justOne = res.justOne;
} catch (error) {
return error;
}
@@ -101,7 +99,6 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
modelNames = res.modelNames;
isRefPath = res.isRefPath;
normalizedRefPath = res.refPath;
justOne = res.justOne;
} catch (error) {
return error;
}
@@ -145,6 +142,7 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
// `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()`
let justOne = null;
if ('justOne' in options && options.justOne !== void 0) {
justOne = options.justOne;
} else if (virtual && virtual.options && virtual.options.refPath) {
@@ -341,7 +339,6 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
let modelNames;
let discriminatorKey;
let isRefPath = false;
let justOne = null;
if (schema && schema.caster) {
schema = schema.caster;
@@ -410,10 +407,6 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
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;
@@ -447,14 +440,14 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
}
if (!modelNames) {
return { modelNames: modelNames, isRefPath: isRefPath, refPath: normalizedRefPath, justOne: justOne };
return { modelNames: modelNames, isRefPath: isRefPath, refPath: normalizedRefPath };
}
if (!Array.isArray(modelNames)) {
modelNames = [modelNames];
}
return { modelNames: modelNames, isRefPath: isRefPath, refPath: normalizedRefPath, justOne: justOne };
return { modelNames: modelNames, isRefPath: isRefPath, refPath: normalizedRefPath };
}
};

View File

@@ -105,14 +105,6 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
}
}
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;
};

View File

@@ -33,13 +33,11 @@ function createImmutableSetter(path, immutable) {
if (!_immutable) {
return v;
}
const _value = this.$__getValue(path);
if (this.$__.strictMode === 'throw' && v !== _value) {
if (this.$__.strictMode === 'throw' && v !== this[path]) {
throw new StrictModeError(path, 'Path `' + path + '` is immutable ' +
'and strict mode is set to throw.', true);
}
return _value;
return this[path];
};
}

View File

@@ -14,17 +14,6 @@ const get = require('./get');
*/
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 = {};
@@ -33,6 +22,12 @@ module.exports = function(filter, schema, castedDoc, options) {
let hasDollarUpdate = false;
options = options || {};
if (!options.upsert || !options.setDefaultsOnInsert) {
return castedDoc;
}
for (let i = 0; i < numKeys; ++i) {
if (keys[i].startsWith('$')) {
modifiedPaths(castedDoc[keys[i]], '', modified);

View File

@@ -11,6 +11,5 @@ 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');

View File

@@ -15,19 +15,25 @@ function applyTimestampsToChildren(now, update, schema) {
}
const keys = Object.keys(update);
let key;
let createdAt;
let updatedAt;
let timestamps;
let path;
const hasDollarKey = keys.length && keys[0].startsWith('$');
if (hasDollarKey) {
if (update.$push) {
for (const key of Object.keys(update.$push)) {
for (key in 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');
timestamps = $path.schema.options.timestamps;
createdAt = handleTimestampOption(timestamps, 'createdAt');
updatedAt = handleTimestampOption(timestamps, 'updatedAt');
if (update.$push[key].$each) {
update.$push[key].$each.forEach(function(subdoc) {
if (updatedAt != null) {
@@ -50,14 +56,93 @@ function applyTimestampsToChildren(now, update, schema) {
}
if (update.$set != null) {
const keys = Object.keys(update.$set);
for (const key of keys) {
applyTimestampsToUpdateKey(schema, key, update.$set, now);
for (key of keys) {
// Replace positional operator `$` and array filters `$[]` and `$[.*]`
const keyToSearch = cleanPositionalOperators(key);
path = schema.path(keyToSearch);
if (!path) {
continue;
}
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.$set[key]) && path.$isMongooseDocumentArray) {
applyTimestampsToDocumentArray(update.$set[key], path, now);
} else if (update.$set[key] && path.$isSingleNested) {
applyTimestampsToSingleNested(update.$set[key], path, now);
} else if (parentSchemaTypes.length > 0) {
for (const item of parentSchemaTypes) {
const parentPath = item.parentPath;
const parentSchemaType = item.parentSchemaType;
timestamps = parentSchemaType.schema.options.timestamps;
createdAt = handleTimestampOption(timestamps, 'createdAt');
updatedAt = handleTimestampOption(timestamps, 'updatedAt');
if (!timestamps || updatedAt == null) {
continue;
}
if (parentSchemaType.$isSingleNested) {
// Single nested is easy
update.$set[parentPath + '.' + updatedAt] = now;
continue;
}
if (parentSchemaType.$isMongooseDocumentArray) {
let childPath = key.substr(parentPath.length + 1);
if (/^\d+$/.test(childPath)) {
update.$set[parentPath + '.' + childPath][updatedAt] = now;
continue;
}
const firstDot = childPath.indexOf('.');
childPath = firstDot !== -1 ? childPath.substr(0, firstDot) : childPath;
update.$set[parentPath + '.' + childPath + '.' + updatedAt] = now;
}
}
} else if (path.schema != null && path.schema != schema && update.$set[key]) {
timestamps = path.schema.options.timestamps;
createdAt = handleTimestampOption(timestamps, 'createdAt');
updatedAt = handleTimestampOption(timestamps, 'updatedAt');
if (!timestamps) {
continue;
}
if (updatedAt != null) {
update.$set[key][updatedAt] = now;
}
if (createdAt != null) {
update.$set[key][createdAt] = now;
}
}
}
}
} else {
const keys = Object.keys(update).filter(key => !key.startsWith('$'));
for (const key of keys) {
applyTimestampsToUpdateKey(schema, key, update, now);
for (key of keys) {
// Replace positional operator `$` and array filters `$[]` and `$[.*]`
const keyToSearch = cleanPositionalOperators(key);
path = schema.path(keyToSearch);
if (!path) {
continue;
}
if (Array.isArray(update[key]) && path.$isMongooseDocumentArray) {
applyTimestampsToDocumentArray(update[key], path, now);
} else if (update[key] != null && path.$isSingleNested) {
applyTimestampsToSingleNested(update[key], path, now);
}
}
}
}
@@ -102,71 +187,3 @@ function applyTimestampsToSingleNested(subdoc, schematype, 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;
}
}
}

12
node_modules/mongoose/lib/index.js generated vendored
View File

@@ -34,7 +34,6 @@ const pkg = require('../package.json');
const cast = require('./cast');
const removeSubdocs = require('./plugins/removeSubdocs');
const saveSubdocs = require('./plugins/saveSubdocs');
const trackTransaction = require('./plugins/trackTransaction');
const validateBeforeSave = require('./plugins/validateBeforeSave');
const Aggregate = require('./aggregate');
@@ -107,8 +106,7 @@ function Mongoose(options) {
[saveSubdocs, { deduplicate: true }],
[validateBeforeSave, { deduplicate: true }],
[shardingPlugin, { deduplicate: true }],
[removeSubdocs, { deduplicate: true }],
[trackTransaction, { deduplicate: true }]
[removeSubdocs, { deduplicate: true }]
]
});
}
@@ -147,7 +145,6 @@ Mongoose.prototype.driver = require('./driver');
*
* Currently supported options are:
* - 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arugments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
* - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information.
* - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
* - 'useCreateIndex': false by default. Set to `true` to make Mongoose's default index build use `createIndex()` instead of `ensureIndex()` to avoid deprecation warnings from the MongoDB driver.
* - 'useFindAndModify': true by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
@@ -161,7 +158,6 @@ Mongoose.prototype.driver = require('./driver');
* - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject)
* - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
* - 'strict': true by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
* - 'strictQuery': false by default, may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas.
* - 'selectPopulatedPaths': true by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
* - 'typePojoToMixed': true by default, may be `false` or `true`. Sets the default typePojoToMixed for schemas.
* - 'maxTimeMS': If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query
@@ -217,7 +213,7 @@ Mongoose.prototype.get = Mongoose.prototype.set;
/**
* Creates a Connection instance.
*
* Each `connection` instance maps to a single database. This method is helpful when managing multiple db connections.
* Each `connection` instance maps to a single database. This method is helpful when mangaging multiple db connections.
*
*
* _Options passed take precedence over options included in connection strings._
@@ -264,7 +260,7 @@ Mongoose.prototype.get = Mongoose.prototype.set;
* @param {Number} [options.bufferMaxEntries] This option does nothing if `useUnifiedTopology` is set. The MongoDB driver also has its own buffering mechanism that kicks in when the driver is disconnected. Set this option to 0 and set `bufferCommands` to `false` on your schemas if you want your database operations to fail immediately when the driver is not connected, as opposed to waiting for reconnection.
* @param {Number} [options.connectTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _during initial connection_. Defaults to 30000. This option is passed transparently to [Node.js' `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback).
* @param {Number} [options.socketTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. This is set to `30000` by default, you should set this to 2-3x your longest running operation if you expect some of your database operations to run longer than 20 seconds. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
* @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0`, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
* @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
* @return {Connection} the created Connection object. Connections are thenable, so you can do `await mongoose.createConnection()`
* @api public
*/
@@ -326,7 +322,7 @@ Mongoose.prototype.createConnection = function(uri, options, callback) {
* @param {Number} [options.bufferMaxEntries] This option does nothing if `useUnifiedTopology` is set. The MongoDB driver also has its own buffering mechanism that kicks in when the driver is disconnected. Set this option to 0 and set `bufferCommands` to `false` on your schemas if you want your database operations to fail immediately when the driver is not connected, as opposed to waiting for reconnection.
* @param {Number} [options.connectTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _during initial connection_. Defaults to 30000. This option is passed transparently to [Node.js' `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback).
* @param {Number} [options.socketTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. This is set to `30000` by default, you should set this to 2-3x your longest running operation if you expect some of your database operations to run longer than 20 seconds. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
* @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0`, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
* @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
* @param {Function} [callback]
* @see Mongoose#createConnection #index_Mongoose-createConnection
* @api public

168
node_modules/mongoose/lib/model.js generated vendored
View File

@@ -436,7 +436,7 @@ function generateVersionError(doc, modifiedPaths) {
* @param {Session} [options.session=null] the [session](https://docs.mongodb.com/manual/reference/server-sessions/) associated with this save operation. If not specified, defaults to the [document's associated session](api.html#document_Document-$session).
* @param {Object} [options.safe] (DEPRECATED) overrides [schema's safe option](http://mongoosejs.com//docs/guide.html#safe). Use the `w` option instead.
* @param {Boolean} [options.validateBeforeSave] set to false to save without validating.
* @param {Boolean} [options.validateModifiedOnly=false] if `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
* @param {Boolean} [options.validateModifiedOnly=false] if `true` mongoose validates only modified paths.
* @param {Number|String} [options.w] set the [write concern](https://docs.mongodb.com/manual/reference/write-concern/#w-option). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern)
* @param {Boolean} [options.j] set to true for MongoDB to wait until this `save()` has been [journaled before resolving the returned promise](https://docs.mongodb.com/manual/reference/write-concern/#j-option). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern)
* @param {Number} [options.wtimeout] sets a [timeout for the write concern](https://docs.mongodb.com/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern).
@@ -542,11 +542,6 @@ function operand(self, where, delta, data, val, op) {
// already marked for versioning?
if (VERSION_ALL === (VERSION_ALL & self.$__.version)) return;
if (self.schema.options.optimisticConcurrency) {
self.$__.version = VERSION_ALL;
return;
}
switch (op) {
case '$set':
case '$unset':
@@ -1362,7 +1357,7 @@ Model.syncIndexes = function syncIndexes(options, callback) {
cb = this.$wrapCallback(cb);
this.createCollection(err => {
if (err != null && err.codeName !== 'NamespaceExists') {
if (err) {
return cb(err);
}
this.cleanIndexes((err, dropped) => {
@@ -1573,7 +1568,7 @@ function _ensureIndexes(model, options, callback) {
model.emit('error', err);
}
model.emit('index', err || indexError);
callback && callback(err || indexError);
callback && callback(err);
};
for (const index of indexes) {
@@ -1981,26 +1976,35 @@ Model.deleteMany = function deleteMany(conditions, options, callback) {
/**
* Finds documents.
*
* Mongoose casts the `filter` to match the model's schema before the command is sent.
* The `filter` are cast to their respective SchemaTypes before the command is sent.
* See our [query casting tutorial](/docs/tutorials/query_casting.html) for
* more information on how Mongoose casts `filter`.
*
* ####Examples:
*
* // find all documents
* await MyModel.find({});
*
* // find all documents named john and at least 18
* await MyModel.find({ name: 'john', age: { $gte: 18 } }).exec();
* // named john and at least 18
* MyModel.find({ name: 'john', age: { $gte: 18 }});
*
* // executes, passing results to callback
* MyModel.find({ name: 'john', age: { $gte: 18 }}, function (err, docs) {});
*
* // executes, name LIKE john and only selecting the "name" and "friends" fields
* await MyModel.find({ name: /john/i }, 'name friends').exec();
* MyModel.find({ name: /john/i }, 'name friends', function (err, docs) { })
*
* // passing options
* await MyModel.find({ name: /john/i }, null, { skip: 10 }).exec();
* MyModel.find({ name: /john/i }, null, { skip: 10 })
*
* // passing options and executes
* MyModel.find({ name: /john/i }, null, { skip: 10 }, function (err, docs) {});
*
* // executing a query explicitly
* var query = MyModel.find({ name: /john/i }, null, { skip: 10 })
* query.exec(function (err, docs) {});
*
* // using the promise returned from executing a query
* var query = MyModel.find({ name: /john/i }, null, { skip: 10 });
* var promise = query.exec();
* promise.addBack(function (err, docs) {});
*
* @param {Object|ObjectId} filter
* @param {Object|String} [projection] optional fields to return, see [`Query.prototype.select()`](http://mongoosejs.com/docs/api.html#query_Query-select)
@@ -2063,14 +2067,26 @@ Model.find = function find(conditions, projection, options, callback) {
*
* ####Example:
*
* // Find the adventure with the given `id`, or `null` if not found
* await Adventure.findById(id).exec();
*
* // using callback
* // find adventure by id and execute
* Adventure.findById(id, function (err, adventure) {});
*
* // same as above
* Adventure.findById(id).exec(callback);
*
* // select only the adventures name and length
* await Adventure.findById(id, 'name length').exec();
* Adventure.findById(id, 'name length', function (err, adventure) {});
*
* // same as above
* Adventure.findById(id, 'name length').exec(callback);
*
* // include all properties except for `length`
* Adventure.findById(id, '-length').exec(function (err, adventure) {});
*
* // passing options (in this case return the raw js objects, not mongoose documents by passing `lean`
* Adventure.findById(id, 'name', { lean: true }, function (err, doc) {});
*
* // same as above
* Adventure.findById(id, 'name').lean().exec(function (err, doc) {});
*
* @param {Any} id value of `_id` to query by
* @param {Object|String} [projection] optional fields to return, see [`Query.prototype.select()`](#query_Query-select)
@@ -2106,14 +2122,26 @@ Model.findById = function findById(id, projection, options, callback) {
*
* ####Example:
*
* // Find one adventure whose `country` is 'Croatia', otherwise `null`
* await Adventure.findOne({ country: 'Croatia' }).exec();
* // find one iphone adventures - iphone adventures??
* Adventure.findOne({ type: 'iphone' }, function (err, adventure) {});
*
* // using callback
* Adventure.findOne({ country: 'Croatia' }, function (err, adventure) {});
* // same as above
* Adventure.findOne({ type: 'iphone' }).exec(function (err, adventure) {});
*
* // select only the adventures name and length
* await Adventure.findOne({ country: 'Croatia' }, 'name length').exec();
* // select only the adventures name
* Adventure.findOne({ type: 'iphone' }, 'name', function (err, adventure) {});
*
* // same as above
* Adventure.findOne({ type: 'iphone' }, 'name').exec(function (err, adventure) {});
*
* // specify options, in this case lean
* Adventure.findOne({ type: 'iphone' }, 'name', { lean: true }, callback);
*
* // same as above
* Adventure.findOne({ type: 'iphone' }, 'name', { lean: true }).exec(callback);
*
* // chaining findOne queries (same as above)
* Adventure.findOne({ type: 'iphone' }).select('name').lean().exec(callback);
*
* @param {Object} [conditions]
* @param {Object|String} [projection] optional fields to return, see [`Query.prototype.select()`](#query_Query-select)
@@ -2417,7 +2445,7 @@ Model.$where = function $where() {
* @param {Object} [conditions]
* @param {Object} [update]
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
* @param {Boolean} [options.new=false] By default, `findOneAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied. To change the default to `true`, use `mongoose.set('returnOriginal', false);`.
* @param {Boolean} [options.new=false] By default, `findOneAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied.
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](/docs/api.html#query_Query-lean) and [the Mongoose lean tutorial](/docs/tutorials/lean.html).
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
@@ -2560,7 +2588,7 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) {
* @param {Object|Number|String} id value of `_id` to query by
* @param {Object} [update]
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
* @param {Boolean} [options.new=false] By default, `findByIdAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied. To change the default to `true`, use `mongoose.set('returnOriginal', false);`.
* @param {Boolean} [options.new=false] By default, `findByIdAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied.
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](/docs/api.html#query_Query-lean) and [the Mongoose lean tutorial](/docs/tutorials/lean.html).
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
@@ -2759,7 +2787,7 @@ Model.findByIdAndDelete = function(id, options, callback) {
* @param {Object} filter Replace the first document that matches this filter
* @param {Object} [replacement] Replace with this document
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
* @param {Boolean} [options.new=false] By default, `findOneAndReplace()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndReplace()` will instead give you the object after `update` was applied. To change the default to `true`, use `mongoose.set('returnOriginal', false);`.
* @param {Boolean} [options.new=false] By default, `findOneAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied.
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](/docs/api.html#query_Query-lean) and [the Mongoose lean tutorial](/docs/tutorials/lean.html).
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
@@ -2953,16 +2981,26 @@ Model.findByIdAndRemove = function(id, options, callback) {
*
* ####Example:
*
* // Insert one new `Character` document
* await Character.create({ name: 'Jean-Luc Picard' });
* // pass a spread of docs and a callback
* Candy.create({ type: 'jelly bean' }, { type: 'snickers' }, function (err, jellybean, snickers) {
* if (err) // ...
* });
*
* // Insert multiple new `Character` documents
* await Character.create([{ name: 'Will Riker' }, { name: 'Geordi LaForge' }]);
* // pass an array of docs
* var array = [{ type: 'jelly bean' }, { type: 'snickers' }];
* Candy.create(array, function (err, candies) {
* if (err) // ...
*
* // Create a new character within a transaction. Note that you **must**
* // pass an array as the first parameter to `create()` if you want to
* // specify options.
* await Character.create([{ name: 'Jean-Luc Picard' }], { session });
* var jellybean = candies[0];
* var snickers = candies[1];
* // ...
* });
*
* // callback is optional; use the returned promise if you like:
* var promise = Candy.create({ type: 'jawbreaker' });
* promise.then(function (jawbreaker) {
* // ...
* })
*
* @param {Array|Object} docs Documents to insert, as a spread or array
* @param {Object} [options] Options passed down to `save()`. To specify `options`, `docs` **must** be an array, not a spread.
@@ -3491,15 +3529,14 @@ Model.bulkWrite = function(ops, options, callback) {
* var mongooseCandy = Candy.hydrate({ _id: '54108337212ffb6d459f854c', type: 'jelly bean' });
*
* @param {Object} obj
* @param {Object|String} [projection] optional projection containing which fields should be selected for this document
* @return {Document} document instance
* @api public
*/
Model.hydrate = function(obj, projection) {
Model.hydrate = function(obj) {
_checkContext(this, 'hydrate');
const model = require('./queryhelpers').createModel(this, obj, projection);
const model = require('./queryhelpers').createModel(this, obj);
model.init(obj);
return model;
};
@@ -4425,9 +4462,6 @@ function populate(model, docs, options, callback) {
for (const arr of params) {
const mod = arr[0];
const assignmentOpts = arr[3];
for (const val of vals) {
mod.options._childDocs.push(val);
}
_assign(model, vals, mod, assignmentOpts);
}
@@ -4487,16 +4521,7 @@ function _execPopulateQuery(mod, match, select, assignmentOpts, callback) {
query.populate(subPopulate);
}
query.exec((err, docs) => {
if (err != null) {
return callback(err);
}
for (const val of docs) {
leanPopulateMap.set(val, mod.model);
}
callback(null, docs);
});
query.exec(callback);
}
/*!
@@ -4573,7 +4598,9 @@ function _assign(model, vals, mod, assignmentOpts) {
}
}
// flag each as result of population
if (!lean) {
if (lean) {
leanPopulateMap.set(val, mod.model);
} else {
val.$__.wasPopulated = true;
}
}
@@ -4593,7 +4620,6 @@ function _assign(model, vals, mod, assignmentOpts) {
justOne: mod.justOne,
isVirtual: mod.isVirtual,
allOptions: mod,
populatedModel: mod.model,
lean: lean,
virtual: mod.virtual,
count: mod.count,
@@ -4710,8 +4736,23 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
const _userProvidedOptions = schema._userProvidedOptions || {};
// `bufferCommands` is true by default...
let bufferCommands = true;
// First, take the global option
if (connection.base.get('bufferCommands') != null) {
bufferCommands = connection.base.get('bufferCommands');
}
// Connection-specific overrides the global option
if (connection.config.bufferCommands != null) {
bufferCommands = connection.config.bufferCommands;
}
// And schema options override global and connection
if (_userProvidedOptions.bufferCommands != null) {
bufferCommands = _userProvidedOptions.bufferCommands;
}
const collectionOptions = {
schemaUserProvidedOptions: _userProvidedOptions,
bufferCommands: bufferCommands,
capped: schema.options.capped,
autoCreate: schema.options.autoCreate,
Promise: model.base.Promise
@@ -4805,8 +4846,17 @@ Model.__subclass = function subclass(conn, schema, collection) {
utils.toCollectionName(_this.modelName, this.base.pluralize());
}
let bufferCommands = true;
if (s) {
if (conn.config.bufferCommands != null) {
bufferCommands = conn.config.bufferCommands;
}
if (_userProvidedOptions.bufferCommands != null) {
bufferCommands = _userProvidedOptions.bufferCommands;
}
}
const collectionOptions = {
schemaUserProvidedOptions: _userProvidedOptions,
bufferCommands: bufferCommands,
capped: s && options.capped
};
@@ -4848,7 +4898,7 @@ Model.$wrapCallback = function(callback) {
if (err != null && err.name === 'MongoServerSelectionError') {
arguments[0] = serverSelectionError.assimilateError(err);
}
if (err != null && err.name === 'MongoNetworkTimeoutError' && err.message.endsWith('timed out')) {
if (err != null && err.name === 'MongoNetworkError' && err.message.endsWith('timed out')) {
_this.db.emit('timeout');
}

View File

@@ -5,7 +5,6 @@ const clone = require('../helpers/clone');
class PopulateOptions {
constructor(obj) {
this._docs = {};
this._childDocs = [];
if (obj == null) {
return;

55
node_modules/mongoose/lib/query.js generated vendored
View File

@@ -1293,7 +1293,6 @@ Query.prototype.getOptions = function() {
* - [writeConcern](https://docs.mongodb.com/manual/reference/method/db.collection.update/)
* - [timestamps](https://mongoosejs.com/docs/guide.html#timestamps): If `timestamps` is set in the schema, set this option to `false` to skip timestamps for that particular update. Has no effect if `timestamps` is not enabled in the schema options.
* - omitUndefined: delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
* - overwriteDiscriminatorKey: allow setting the discriminator key in the update. Will use the correct discriminator schema if the update changes the discriminator key.
*
* The following options are only for `find()`, `findOne()`, `findById()`, `findOneAndUpdate()`, and `findByIdAndUpdate()`:
*
@@ -1362,10 +1361,6 @@ Query.prototype.setOptions = function(options, overwrite) {
this._mongooseOptions.setDefaultsOnInsert = options.setDefaultsOnInsert;
delete options.setDefaultsOnInsert;
}
if ('overwriteDiscriminatorKey' in options) {
this._mongooseOptions.overwriteDiscriminatorKey = options.overwriteDiscriminatorKey;
delete options.overwriteDiscriminatorKey;
}
return Query.base.setOptions.call(this, options);
};
@@ -3004,24 +2999,19 @@ Query.prototype.findOneAndUpdate = function(criteria, doc, options, callback) {
this._mergeUpdate(doc);
}
options = options ? utils.clone(options) : {};
if (options) {
options = utils.clone(options);
if (options.projection) {
this.select(options.projection);
delete options.projection;
}
if (options.fields) {
this.select(options.fields);
delete options.fields;
}
if (options.projection) {
this.select(options.projection);
delete options.projection;
this.setOptions(options);
}
if (options.fields) {
this.select(options.fields);
delete options.fields;
}
const returnOriginal = get(this, 'model.base.options.returnOriginal');
if (options.returnOriginal == null && returnOriginal != null) {
options.returnOriginal = returnOriginal;
}
this.setOptions(options);
if (!callback) {
return this;
@@ -3340,14 +3330,7 @@ Query.prototype.findOneAndReplace = function(filter, replacement, options, callb
this._mergeUpdate(replacement);
}
options = options || {};
const returnOriginal = get(this, 'model.base.options.returnOriginal');
if (options.returnOriginal == null && returnOriginal != null) {
options.returnOriginal = returnOriginal;
}
this.setOptions(options);
options && this.setOptions(options);
if (!callback) {
return this;
@@ -4502,19 +4485,6 @@ Query.prototype._post = function(fn) {
Query.prototype._castUpdate = function _castUpdate(obj, overwrite) {
let strict;
let schema = this.schema;
const discriminatorKey = schema.options.discriminatorKey;
const baseSchema = schema._baseSchema ? schema._baseSchema : schema;
if (this._mongooseOptions.overwriteDiscriminatorKey &&
obj[discriminatorKey] != null &&
baseSchema.discriminators) {
const _schema = baseSchema.discriminators[obj[discriminatorKey]];
if (_schema != null) {
schema = _schema;
}
}
if ('strict' in this._mongooseOptions) {
strict = this._mongooseOptions.strict;
} else if (this.schema && this.schema.options) {
@@ -4538,6 +4508,7 @@ Query.prototype._castUpdate = function _castUpdate(obj, overwrite) {
upsert = this.options.upsert;
}
let schema = this.schema;
const filter = this._conditions;
if (schema != null &&
utils.hasUserDefinedProperty(filter, schema.options.discriminatorKey) &&

16
node_modules/mongoose/lib/schema.js generated vendored
View File

@@ -69,7 +69,7 @@ let id = 0;
* - [typePojoToMixed](/docs/guide.html#typePojoToMixed) - boolean - defaults to true. Determines whether a type set to a POJO becomes a Mixed path or a Subdocument
* - [useNestedStrict](/docs/guide.html#useNestedStrict) - boolean - defaults to false
* - [validateBeforeSave](/docs/guide.html#validateBeforeSave) - bool - defaults to `true`
* - [versionKey](/docs/guide.html#versionKey): string or object - defaults to "__v"
* - [versionKey](/docs/guide.html#versionKey): string - defaults to "__v"
* - [collation](/docs/guide.html#collation): object - defaults to null (which means use no collation)
* - [selectPopulatedPaths](/docs/guide.html#selectPopulatedPaths): boolean - defaults to `true`
* - [skipVersioning](/docs/guide.html#skipVersioning): object - paths to exclude from versioning
@@ -400,11 +400,9 @@ Schema.prototype.defaultOptions = function(options) {
const baseOptions = get(this, 'base.options', {});
options = utils.options({
strict: 'strict' in baseOptions ? baseOptions.strict : true,
strictQuery: 'strictQuery' in baseOptions ? baseOptions.strictQuery : false,
bufferCommands: true,
capped: false, // { size, max, autoIndexId }
versionKey: '__v',
optimisticConcurrency: false,
discriminatorKey: '__t',
minimize: true,
autoIndex: null,
@@ -424,10 +422,6 @@ Schema.prototype.defaultOptions = function(options) {
options.read = readPref(options.read);
}
if (options.optimisticConcurrency && !options.versionKey) {
throw new MongooseError('Must set `versionKey` if using `optimisticConcurrency`');
}
return options;
};
@@ -941,14 +935,6 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
if (options.hasOwnProperty('typePojoToMixed')) {
childSchemaOptions.typePojoToMixed = options.typePojoToMixed;
}
if (this._userProvidedOptions.hasOwnProperty('_id')) {
childSchemaOptions._id = this._userProvidedOptions._id;
} else if (Schema.Types.DocumentArray.defaultOptions &&
Schema.Types.DocumentArray.defaultOptions._id != null) {
childSchemaOptions._id = Schema.Types.DocumentArray.defaultOptions._id;
}
const childSchema = new Schema(cast, childSchemaOptions);
childSchema.$implicitlyCreated = true;
return new MongooseTypes.DocumentArray(path, childSchema, obj);

View File

@@ -175,7 +175,7 @@ SingleNestedPath.prototype.cast = function(val, doc, init, priorVal) {
subdoc.init(val);
} else {
if (Object.keys(val).length === 0) {
return new Constructor({}, selected, doc, undefined, { priorDoc: priorVal });
return new Constructor({}, selected, doc);
}
return new Constructor(val, selected, doc, undefined, { priorDoc: priorVal });
@@ -300,26 +300,6 @@ SingleNestedPath.prototype.discriminator = function(name, schema, value) {
return this.caster.discriminators[name];
};
/**
* Sets a default option for all SingleNestedPath instances.
*
* ####Example:
*
* // Make all numbers have option `min` equal to 0.
* mongoose.Schema.Embedded.set('required', true);
*
* @param {String} option - The option you'd like to set the value for
* @param {*} value - value for option
* @return {undefined}
* @function set
* @static
* @api public
*/
SingleNestedPath.defaultOptions = {};
SingleNestedPath.set = SchemaType.set;
/*!
* ignore
*/

View File

@@ -280,7 +280,7 @@ SchemaArray.prototype._applySetters = function(value, scope, init, priorVal) {
// No need to wrap empty arrays
if (value != null && value.length > 0) {
const valueDepth = arrayDepth(value);
if (valueDepth.min === valueDepth.max && valueDepth.max < depth && valueDepth.containsNonArrayItem) {
if (valueDepth.min === valueDepth.max && valueDepth.max < depth) {
for (let i = valueDepth.max; i < depth; ++i) {
value = [value];
}

View File

@@ -224,30 +224,6 @@ SchemaBoolean.prototype.castForQuery = function($conditional, val) {
return this._castForQuery($conditional);
};
/**
*
* @api private
*/
SchemaBoolean.prototype._castNullish = function _castNullish(v) {
if (typeof v === 'undefined' && this.$$context != null && this.$$context._mongooseOptions.omitUndefined) {
return v;
}
const castBoolean = typeof this.constructor.cast === 'function' ?
this.constructor.cast() :
SchemaBoolean.cast();
if (castBoolean == null) {
return v;
}
if (castBoolean.convertToFalse instanceof Set && castBoolean.convertToFalse.has(v)) {
return false;
}
if (castBoolean.convertToTrue instanceof Set && castBoolean.convertToTrue.has(v)) {
return true;
}
return v;
};
/*!
* Module exports.
*/

View File

@@ -361,11 +361,6 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
// lazy load
MongooseDocumentArray || (MongooseDocumentArray = require('../types/documentarray'));
// Skip casting if `value` is the same as the previous value, no need to cast. See gh-9266
if (value != null && value[arrayPathSymbol] != null && value === prev) {
return value;
}
let selected;
let subdoc;
const _opts = { transform: false, virtuals: false };
@@ -518,26 +513,6 @@ function scopePaths(array, fields, init) {
return hasKeys && selected || undefined;
}
/**
* Sets a default option for all DocumentArray instances.
*
* ####Example:
*
* // Make all numbers have option `min` equal to 0.
* mongoose.Schema.DocumentArray.set('_id', false);
*
* @param {String} option - The option you'd like to set the value for
* @param {*} value - value for option
* @return {undefined}
* @function set
* @static
* @api public
*/
DocumentArrayPath.defaultOptions = {};
DocumentArrayPath.set = SchemaType.set;
/*!
* Module exports.
*/

View File

@@ -516,10 +516,6 @@ SchemaString.prototype.match = function match(regExp, message) {
return false;
}
// In case RegExp happens to have `/g` flag set, we need to reset the
// `lastIndex`, otherwise `match` will intermittently fail.
regExp.lastIndex = 0;
const ret = ((v != null && v !== '')
? regExp.test(v)
: true);

View File

@@ -54,6 +54,7 @@ function SchemaType(path, options, instance) {
}
}
if (options.select == null) {
delete options.select;
}
@@ -441,38 +442,6 @@ SchemaType.prototype.immutable = function(bool) {
return this;
};
/**
* Defines a custom function for transforming this path when converting a document to JSON.
*
* Mongoose calls this function with one parameter: the current `value` of the path. Mongoose
* then uses the return value in the JSON output.
*
* ####Example:
*
* const schema = new Schema({
* date: { type: Date, transform: v => v.getFullYear() }
* });
* const Model = mongoose.model('Test', schema);
*
* await Model.create({ date: new Date('2016-06-01') });
* const doc = await Model.findOne();
*
* doc.date instanceof Date; // true
*
* doc.toJSON().date; // 2016 as a number
* JSON.stringify(doc); // '{"_id":...,"date":2016}'
*
* @param {Function} fn
* @return {SchemaType} this
* @api public
*/
SchemaType.prototype.transform = function(fn) {
this.options.transform = fn;
return this;
};
/**
* Adds a setter to this schematype.
*
@@ -1042,14 +1011,6 @@ SchemaType.prototype._applySetters = function(value, scope, init, priorVal) {
return v;
};
/*!
* ignore
*/
SchemaType.prototype._castNullish = function _castNullish(v) {
return v;
};
/**
* Applies setters
*
@@ -1063,7 +1024,7 @@ SchemaType.prototype.applySetters = function(value, scope, init, priorVal, optio
let v = this._applySetters(value, scope, init, priorVal, options);
if (v == null) {
return this._castNullish(v);
return v;
}
// do not cast until all setters are applied #665

View File

@@ -703,7 +703,7 @@ class CoreMongooseArray extends Array {
}
/**
* Alias of [pull](#mongoosearray_MongooseArray-pull)
* Alias of [pull](#types_array_MongooseArray-pull)
*
* @see MongooseArray#pull #types_array_MongooseArray-pull
* @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pull
@@ -955,4 +955,4 @@ function _checkManualPopulation(arr, docs) {
}
}
module.exports = CoreMongooseArray;
module.exports = CoreMongooseArray;

View File

@@ -280,7 +280,7 @@ EmbeddedDocument.prototype.invalidate = function(path, err, val) {
if (!this[documentArrayParent] || this.__index == null) {
if (err[validatorErrorSymbol] || err instanceof ValidationError) {
return this.ownerDocument().$__.validationError;
return true;
}
throw err;
}
@@ -290,7 +290,7 @@ EmbeddedDocument.prototype.invalidate = function(path, err, val) {
const fullPath = [parentPath, index, path].join('.');
this[documentArrayParent].invalidate(fullPath, err, val);
return this.ownerDocument().$__.validationError;
return true;
};
/**

View File

@@ -29,10 +29,7 @@ function Subdocument(value, fields, parent, skipId, options) {
}
if (parent != null) {
// If setting a nested path, should copy isNew from parent re: gh-7048
options = Object.assign({}, options, {
isNew: parent.isNew,
defaults: parent.$__.$options.defaults
});
options = Object.assign({}, options, { isNew: parent.isNew });
}
Document.call(this, value, fields, skipId, options);
@@ -51,9 +48,6 @@ function Subdocument(value, fields, parent, skipId, options) {
}
}
}
delete options.priorDoc;
delete this.$__.$options.priorDoc;
}
}
@@ -174,8 +168,6 @@ Subdocument.prototype.invalidate = function(path, err, val) {
} else if (err.kind === 'cast' || err.name === 'CastError') {
throw err;
}
return this.ownerDocument().$__.validationError;
};
/*!

View File

@@ -14,20 +14,17 @@ const VALID_OPTIONS = Object.freeze([
'debug',
'maxTimeMS',
'objectIdGetter',
'returnOriginal',
'runValidators',
'selectPopulatedPaths',
'setDefaultsOnInsert',
'strict',
'strictQuery',
'toJSON',
'toObject',
'typePojoToMixed',
'useCreateIndex',
'useFindAndModify',
'useNewUrlParser',
'usePushEach',
'useUnifiedTopology'
'useUnifiedTopology',
'typePojoToMixed'
]);
module.exports = VALID_OPTIONS;