vuetify eingebunden + erster Versuch Combobox
This commit is contained in:
+40
-22
@@ -570,7 +570,15 @@ function init(self, obj, doc, prefix) {
|
||||
Document.prototype.update = function update() {
|
||||
const args = utils.args(arguments);
|
||||
args.unshift({_id: this._id});
|
||||
return this.constructor.update.apply(this.constructor, args);
|
||||
const query = this.constructor.update.apply(this.constructor, args);
|
||||
|
||||
if (this.$session() != null) {
|
||||
if (!('session' in query.options)) {
|
||||
query.options.session = this.$session();
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -603,6 +611,12 @@ Document.prototype.updateOne = function updateOne(doc, options, callback) {
|
||||
this.constructor._middleware.execPost('updateOne', this, [], {}, cb);
|
||||
});
|
||||
|
||||
if (this.$session() != null) {
|
||||
if (!('session' in query.options)) {
|
||||
query.options.session = this.$session();
|
||||
}
|
||||
}
|
||||
|
||||
if (callback != null) {
|
||||
return query.exec(callback);
|
||||
}
|
||||
@@ -1502,11 +1516,11 @@ Document.prototype.$isDefault = function(path) {
|
||||
*
|
||||
* ####Example:
|
||||
* product.remove(function (err, product) {
|
||||
* product.isDeleted(); // true
|
||||
* product.$isDeleted(); // true
|
||||
* product.remove(); // no-op, doesn't send anything to the db
|
||||
*
|
||||
* product.isDeleted(false);
|
||||
* product.isDeleted(); // false
|
||||
* product.$isDeleted(false);
|
||||
* product.$isDeleted(); // false
|
||||
* product.remove(); // will execute a remove against the db
|
||||
* })
|
||||
*
|
||||
@@ -2791,7 +2805,13 @@ function applyGetters(self, json, type, options) {
|
||||
part = parts[ii];
|
||||
v = cur[part];
|
||||
if (ii === last) {
|
||||
branch[part] = clone(self.get(path), options);
|
||||
const val = self.get(path);
|
||||
// Ignore single nested docs: getters will run because of `clone()`
|
||||
// before `applyGetters()` in `$toObject()`. Quirk because single
|
||||
// nested subdocs are hydrated docs in `_doc` as opposed to POJOs.
|
||||
if (val != null && val.$__ == null) {
|
||||
branch[part] = clone(val, options);
|
||||
}
|
||||
} else if (v == null) {
|
||||
if (part in cur) {
|
||||
branch[part] = v;
|
||||
@@ -3104,43 +3124,41 @@ Document.prototype.depopulate = function(path) {
|
||||
if (typeof path === 'string') {
|
||||
path = path.split(' ');
|
||||
}
|
||||
let i;
|
||||
let populatedIds;
|
||||
const virtualKeys = this.$$populatedVirtuals ? Object.keys(this.$$populatedVirtuals) : [];
|
||||
const populated = get(this, '$__.populated', {});
|
||||
|
||||
if (arguments.length === 0) {
|
||||
// Depopulate all
|
||||
const keys = this.$__.populated ? Object.keys(this.$__.populated) : [];
|
||||
|
||||
for (i = 0; i < virtualKeys.length; i++) {
|
||||
for (let i = 0; i < virtualKeys.length; i++) {
|
||||
delete this.$$populatedVirtuals[virtualKeys[i]];
|
||||
delete this._doc[virtualKeys[i]];
|
||||
delete populated[virtualKeys[i]];
|
||||
}
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
const keys = Object.keys(populated);
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
populatedIds = this.populated(keys[i]);
|
||||
if (!populatedIds) {
|
||||
continue;
|
||||
}
|
||||
delete this.$__.populated[keys[i]];
|
||||
delete populated[keys[i]];
|
||||
this.$set(keys[i], populatedIds);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
for (i = 0; i < path.length; i++) {
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
populatedIds = this.populated(path[i]);
|
||||
if (!populatedIds) {
|
||||
if (virtualKeys.indexOf(path[i]) === -1) {
|
||||
continue;
|
||||
} else {
|
||||
delete this.$$populatedVirtuals[path[i]];
|
||||
delete this._doc[path[i]];
|
||||
continue;
|
||||
}
|
||||
delete populated[path[i]];
|
||||
|
||||
if (virtualKeys.indexOf(path[i]) !== -1) {
|
||||
delete this.$$populatedVirtuals[path[i]];
|
||||
delete this._doc[path[i]];
|
||||
} else {
|
||||
this.$set(path[i], populatedIds);
|
||||
}
|
||||
delete this.$__.populated[path[i]];
|
||||
this.$set(path[i], populatedIds);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
+1
-1
@@ -117,7 +117,7 @@ function iter(i) {
|
||||
const collection = this.collection;
|
||||
const args = arguments;
|
||||
const _this = this;
|
||||
const debug = _this.conn.base.options.debug;
|
||||
const debug = get(_this, 'conn.base.options.debug');
|
||||
|
||||
// If user force closed, queueing will hang forever. See #5664
|
||||
if (this.opts.$wasForceClosed) {
|
||||
|
||||
+6
-4
@@ -13,15 +13,15 @@ const util = require('util');
|
||||
* @inherits MongooseError
|
||||
*/
|
||||
|
||||
function DocumentNotFoundError(query) {
|
||||
function DocumentNotFoundError(filter) {
|
||||
let msg;
|
||||
const messages = MongooseError.messages;
|
||||
if (messages.DocumentNotFoundError != null) {
|
||||
msg = typeof messages.DocumentNotFoundError === 'function' ?
|
||||
messages.DocumentNotFoundError(query) :
|
||||
messages.DocumentNotFoundError(filter) :
|
||||
messages.DocumentNotFoundError;
|
||||
} else {
|
||||
msg = 'No document found for query "' + util.inspect(query) + '"';
|
||||
msg = 'No document found for query "' + util.inspect(filter) + '"';
|
||||
}
|
||||
|
||||
MongooseError.call(this, msg);
|
||||
@@ -33,7 +33,9 @@ function DocumentNotFoundError(query) {
|
||||
this.stack = new Error().stack;
|
||||
}
|
||||
|
||||
this.query = query;
|
||||
this.filter = filter;
|
||||
// Backwards compat
|
||||
this.query = filter;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
+3
-3
@@ -109,10 +109,10 @@ function applyHooks(model, schema, options) {
|
||||
objToDecorate[method] = function() {
|
||||
const args = Array.prototype.slice.call(arguments);
|
||||
const cb = utils.last(args);
|
||||
const argsWithoutCallback = cb == null ? args :
|
||||
args.slice(0, args.length - 1);
|
||||
const argsWithoutCallback = typeof cb === 'function' ?
|
||||
args.slice(0, args.length - 1) : args;
|
||||
return utils.promiseOrCallback(cb, callback => {
|
||||
this[`$__${method}`].apply(this,
|
||||
return this[`$__${method}`].apply(this,
|
||||
argsWithoutCallback.concat([callback]));
|
||||
}, model.events);
|
||||
};
|
||||
|
||||
+12
-8
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const defineKey = require('../document/compile').defineKey;
|
||||
const get = require('../../helpers/get');
|
||||
const get = require('../get');
|
||||
const utils = require('../../utils');
|
||||
|
||||
const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
|
||||
@@ -15,23 +15,27 @@ const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
|
||||
* ignore
|
||||
*/
|
||||
|
||||
module.exports = function discriminator(model, name, schema, tiedValue) {
|
||||
module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins) {
|
||||
if (!(schema && schema.instanceOfSchema)) {
|
||||
throw new Error('You must pass a valid discriminator Schema');
|
||||
}
|
||||
|
||||
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 });
|
||||
|
||||
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 baseSchemaAddition = {};
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function castFilterPath(query, schematype, val) {
|
||||
const ctx = query;
|
||||
const any$conditionals = Object.keys(val).some(function(k) {
|
||||
return k.charAt(0) === '$' && k !== '$id' && k !== '$ref';
|
||||
});
|
||||
|
||||
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 && _keys[0].charAt(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;
|
||||
};
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
'use strict';
|
||||
|
||||
const castFilterPath = require('../query/castFilterPath');
|
||||
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 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);
|
||||
}
|
||||
return cur;
|
||||
}, {});
|
||||
|
||||
for (const filter of arrayFilters) {
|
||||
if (filter == null) {
|
||||
throw new Error(`Got null array filter in ${arrayFilters}`);
|
||||
}
|
||||
const firstKey = Object.keys(filter)[0];
|
||||
|
||||
if (filter[firstKey] == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const dot = firstKey.indexOf('.');
|
||||
let filterPath = dot === -1 ?
|
||||
updatedPathsByFilter[firstKey] + '.0' :
|
||||
updatedPathsByFilter[firstKey.substr(0, dot)] + '.0' + firstKey.substr(dot);
|
||||
|
||||
if (filterPath == null) {
|
||||
throw new Error(`Filter path not found for ${firstKey}`);
|
||||
}
|
||||
|
||||
// If there are multiple array filters in the path being updated, make sure
|
||||
// to replace them so we can get the schema path.
|
||||
filterPath = filterPath.replace(/\$\[[^\]]+\]/g, '0');
|
||||
|
||||
const schematype = schema.path(filterPath);
|
||||
if (typeof filter[firstKey] === 'object') {
|
||||
filter[firstKey] = castFilterPath(query, schematype, filter[firstKey]);
|
||||
} else {
|
||||
filter[firstKey] = schematype.castForQuery(filter[firstKey]);
|
||||
}
|
||||
}
|
||||
};
|
||||
+49
-8
@@ -19,6 +19,7 @@ const Types = require('./types');
|
||||
const Query = require('./query');
|
||||
const Model = require('./model');
|
||||
const Document = require('./document');
|
||||
const get = require('./helpers/get');
|
||||
const legacyPluralize = require('mongoose-legacy-pluralize');
|
||||
const utils = require('./utils');
|
||||
const pkg = require('../package.json');
|
||||
@@ -555,17 +556,33 @@ Mongoose.prototype._applyPlugins = function(schema, options) {
|
||||
if (schema.$globalPluginsApplied) {
|
||||
return;
|
||||
}
|
||||
let i;
|
||||
let len;
|
||||
schema.$globalPluginsApplied = true;
|
||||
|
||||
if (!options || !options.skipTopLevel) {
|
||||
for (i = 0, len = this.plugins.length; i < len; ++i) {
|
||||
for (let i = 0; i < this.plugins.length; ++i) {
|
||||
schema.plugin(this.plugins[i][0], this.plugins[i][1]);
|
||||
}
|
||||
schema.$globalPluginsApplied = true;
|
||||
}
|
||||
for (i = 0, len = schema.childSchemas.length; i < len; ++i) {
|
||||
|
||||
for (let i = 0; i < schema.childSchemas.length; ++i) {
|
||||
this._applyPlugins(schema.childSchemas[i].schema);
|
||||
}
|
||||
|
||||
const discriminators = schema.discriminators;
|
||||
if (discriminators == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const applyPluginsToDiscriminators = get(this,
|
||||
'options.applyPluginsToDiscriminators', false);
|
||||
|
||||
const keys = Object.keys(discriminators);
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
const discriminatorKey = keys[i];
|
||||
const discriminatorSchema = discriminators[discriminatorKey];
|
||||
|
||||
this._applyPlugins(discriminatorSchema, { skipTopLevel: !applyPluginsToDiscriminators });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -586,7 +603,7 @@ Mongoose.prototype.plugin = function(fn, opts) {
|
||||
};
|
||||
|
||||
/**
|
||||
* The default connection of the mongoose module.
|
||||
* The Mongoose module's default connection. Equivalent to `mongoose.connections][0]`, see [`connections`](#mongoose_Mongoose-connections).
|
||||
*
|
||||
* ####Example:
|
||||
*
|
||||
@@ -596,10 +613,11 @@ Mongoose.prototype.plugin = function(fn, opts) {
|
||||
*
|
||||
* This is the connection used by default for every model created using [mongoose.model](#index_Mongoose-model).
|
||||
*
|
||||
* To create a new connection, use [`createConnection()`](#mongoose_Mongoose-createConnection).
|
||||
*
|
||||
* @memberOf Mongoose
|
||||
* @instance
|
||||
* @property connection
|
||||
* @return {Connection}
|
||||
* @property {Connection} connection
|
||||
* @api public
|
||||
*/
|
||||
|
||||
@@ -614,6 +632,29 @@ Mongoose.prototype.__defineSetter__('connection', function(v) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* An array containing all [connections](connections.html) associated with this
|
||||
* Mongoose instance. By default, there is 1 connection. Calling
|
||||
* [`createConnection()`](#mongoose_Mongoose-createConnection) adds a connection
|
||||
* to this array.
|
||||
*
|
||||
* ####Example:
|
||||
*
|
||||
* const mongoose = require('mongoose');
|
||||
* mongoose.connections.length; // 1, just the default connection
|
||||
* mongoose.connections[0] === mongoose.connection; // true
|
||||
*
|
||||
* mongoose.createConnection('mongodb://localhost:27017/test');
|
||||
* mongoose.connections.length; // 2
|
||||
*
|
||||
* @memberOf Mongoose
|
||||
* @instance
|
||||
* @property {Array} connections
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Mongoose.prototype.connections;
|
||||
|
||||
/*!
|
||||
* Driver dependent APIs
|
||||
*/
|
||||
|
||||
+71
-31
@@ -171,13 +171,12 @@ Model.prototype.baseModelName;
|
||||
* MyModel.events.on('error', err => console.log(err.message));
|
||||
*
|
||||
* // Prints a 'CastError' because of the above handler
|
||||
* await MyModel.findOne({ _id: 'notanid' }).catch({} => {});
|
||||
* await MyModel.findOne({ _id: 'notanid' }).catch(noop);
|
||||
*
|
||||
* @api public
|
||||
* @fires error whenever any query or model function errors
|
||||
* @property events
|
||||
* @memberOf Model
|
||||
* @static
|
||||
* @static events
|
||||
*/
|
||||
|
||||
Model.events;
|
||||
@@ -193,15 +192,28 @@ Model.events;
|
||||
|
||||
Model._middleware;
|
||||
|
||||
/*!
|
||||
* ignore
|
||||
*/
|
||||
|
||||
function _applyCustomWhere(doc, where) {
|
||||
if (doc.$where == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const keys = Object.keys(doc.$where);
|
||||
const len = keys.length;
|
||||
for (let i = 0; i < len; ++i) {
|
||||
where[keys[i]] = doc.$where[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* ignore
|
||||
*/
|
||||
|
||||
Model.prototype.$__handleSave = function(options, callback) {
|
||||
const _this = this;
|
||||
let i;
|
||||
let keys;
|
||||
let len;
|
||||
let saveOptions = {};
|
||||
|
||||
if ('safe' in options) {
|
||||
@@ -285,13 +297,7 @@ Model.prototype.$__handleSave = function(options, callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.$where) {
|
||||
keys = Object.keys(this.$where);
|
||||
len = keys.length;
|
||||
for (i = 0; i < len; ++i) {
|
||||
where[keys[i]] = this.$where[keys[i]];
|
||||
}
|
||||
}
|
||||
_applyCustomWhere(this, where);
|
||||
|
||||
this[modelCollectionSymbol].updateOne(where, delta[1], saveOptions, function(err, ret) {
|
||||
if (err) {
|
||||
@@ -420,6 +426,7 @@ function generateVersionError(doc, modifiedPaths) {
|
||||
* @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).
|
||||
* @param {Boolean} [options.checkKeys=true] the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names)
|
||||
* @param {Boolean} [options.timestamps=true] if `false` and [timestamps](./guide.html#timestamps) are enabled, skip timestamps for this `save()`.
|
||||
* @param {Function} [fn] optional callback
|
||||
* @return {Promise|undefined} Returns undefined if used with callback or a Promise otherwise.
|
||||
* @api public
|
||||
@@ -458,8 +465,11 @@ Model.prototype.save = function(options, fn) {
|
||||
return cb(parallelSave);
|
||||
}
|
||||
|
||||
this.$__.saveOptions = options;
|
||||
|
||||
this.$__save(options, error => {
|
||||
this.$__.saving = undefined;
|
||||
delete this.$__.saveOptions;
|
||||
|
||||
if (error) {
|
||||
this.$__handleReject(error);
|
||||
@@ -915,6 +925,15 @@ Model.prototype.$__remove = function $__remove(options, cb) {
|
||||
return cb(where);
|
||||
}
|
||||
|
||||
_applyCustomWhere(this, where);
|
||||
|
||||
if (this.$session() != null) {
|
||||
options = options || {};
|
||||
if (!('session' in options)) {
|
||||
options.session = this.$session();
|
||||
}
|
||||
}
|
||||
|
||||
this[modelCollectionSymbol].deleteOne(where, options, err => {
|
||||
if (!err) {
|
||||
this.$__.isDeleted = true;
|
||||
@@ -985,12 +1004,13 @@ Model.discriminator = function(name, schema, value) {
|
||||
}
|
||||
}
|
||||
|
||||
schema = discriminator(this, name, schema, value);
|
||||
schema = discriminator(this, name, schema, value, true);
|
||||
if (this.db.models[name]) {
|
||||
throw new OverwriteModelError(name);
|
||||
}
|
||||
|
||||
schema.$isRootDiscriminator = true;
|
||||
schema.$globalPluginsApplied = true;
|
||||
|
||||
model = this.db.model(model || name, schema, this.collection.name);
|
||||
this.discriminators[name] = model;
|
||||
@@ -1567,15 +1587,32 @@ Model.discriminators;
|
||||
* @return {Object} the translated 'pure' fields/conditions
|
||||
*/
|
||||
Model.translateAliases = function translateAliases(fields) {
|
||||
const aliases = this.schema.aliases;
|
||||
|
||||
if (typeof fields === 'object') {
|
||||
// Fields is an object (query conditions or document fields)
|
||||
for (const key in fields) {
|
||||
if (aliases[key]) {
|
||||
fields[aliases[key]] = fields[key];
|
||||
delete fields[key];
|
||||
let alias;
|
||||
const translated = [];
|
||||
const fieldKeys = key.split('.');
|
||||
let currentSchema = this.schema;
|
||||
for (const field in fieldKeys) {
|
||||
const name = fieldKeys[field];
|
||||
if (currentSchema && currentSchema.aliases[name]) {
|
||||
alias = currentSchema.aliases[name];
|
||||
// Alias found,
|
||||
translated.push(alias);
|
||||
} else {
|
||||
// Alias not found, so treat as un-aliased key
|
||||
translated.push(name);
|
||||
}
|
||||
|
||||
// Check if aliased path is a schema
|
||||
if (currentSchema.paths[alias])
|
||||
currentSchema = currentSchema.paths[alias].schema;
|
||||
else
|
||||
currentSchema = null;
|
||||
}
|
||||
fields[translated.join('.')] = fields[key];
|
||||
delete fields[key]; // We'll be using the translated key instead
|
||||
}
|
||||
|
||||
return fields;
|
||||
@@ -1705,16 +1742,16 @@ Model.deleteMany = function deleteMany(conditions, options, callback) {
|
||||
* // named john and at least 18
|
||||
* MyModel.find({ name: 'john', age: { $gte: 18 }});
|
||||
*
|
||||
* // executes immediately, passing results to callback
|
||||
* // executes, passing results to callback
|
||||
* MyModel.find({ name: 'john', age: { $gte: 18 }}, function (err, docs) {});
|
||||
*
|
||||
* // name LIKE john and only selecting the "name" and "friends" fields, executing immediately
|
||||
* // executes, name LIKE john and only selecting the "name" and "friends" fields
|
||||
* MyModel.find({ name: /john/i }, 'name friends', function (err, docs) { })
|
||||
*
|
||||
* // passing options
|
||||
* MyModel.find({ name: /john/i }, null, { skip: 10 })
|
||||
*
|
||||
* // passing options and executing immediately
|
||||
* // passing options and executes
|
||||
* MyModel.find({ name: /john/i }, null, { skip: 10 }, function (err, docs) {});
|
||||
*
|
||||
* // executing a query explicitly
|
||||
@@ -1787,7 +1824,7 @@ Model.find = function find(conditions, projection, options, callback) {
|
||||
*
|
||||
* ####Example:
|
||||
*
|
||||
* // find adventure by id and execute immediately
|
||||
* // find adventure by id and execute
|
||||
* Adventure.findById(id, function (err, adventure) {});
|
||||
*
|
||||
* // same as above
|
||||
@@ -2013,7 +2050,7 @@ Model.count = function count(conditions, callback) {
|
||||
/**
|
||||
* Creates a Query for a `distinct` operation.
|
||||
*
|
||||
* Passing a `callback` immediately executes the query.
|
||||
* Passing a `callback` executes the query.
|
||||
*
|
||||
* ####Example
|
||||
*
|
||||
@@ -2103,7 +2140,7 @@ Model.$where = function $where() {
|
||||
/**
|
||||
* Issues a mongodb findAndModify update command.
|
||||
*
|
||||
* Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes immediately if `callback` is passed else a Query object is returned.
|
||||
* Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes if `callback` is passed else a Query object is returned.
|
||||
*
|
||||
* ####Options:
|
||||
*
|
||||
@@ -2236,8 +2273,7 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) {
|
||||
*
|
||||
* Finds a matching document, updates it according to the `update` arg,
|
||||
* passing any `options`, and returns the found document (if any) to the
|
||||
* callback. The query executes immediately if `callback` is passed else a
|
||||
* Query object is returned.
|
||||
* callback. The query executes if `callback` is passed.
|
||||
*
|
||||
* This function triggers the following middleware.
|
||||
*
|
||||
@@ -2335,7 +2371,7 @@ Model.findByIdAndUpdate = function(id, update, options, callback) {
|
||||
* Finds a matching document, removes it, and passes the found document
|
||||
* (if any) to the callback.
|
||||
*
|
||||
* Executes immediately if `callback` is passed else a Query object is returned.
|
||||
* Executes the query if `callback` is passed.
|
||||
*
|
||||
* This function triggers the following middleware.
|
||||
*
|
||||
@@ -2456,7 +2492,7 @@ Model.findByIdAndDelete = function(id, options, callback) {
|
||||
* Finds a matching document, replaces it with the provided doc, and passes the
|
||||
* returned doc to the callback.
|
||||
*
|
||||
* Executes immediately if `callback` is passed else a Query object is returned.
|
||||
* Executes the query if `callback` is passed.
|
||||
*
|
||||
* This function triggers the following query middleware.
|
||||
*
|
||||
@@ -2525,7 +2561,7 @@ Model.findOneAndReplace = function(conditions, options, callback) {
|
||||
*
|
||||
* Finds a matching document, removes it, passing the found document (if any) to the callback.
|
||||
*
|
||||
* Executes immediately if `callback` is passed else a Query object is returned.
|
||||
* Executes the query if `callback` is passed.
|
||||
*
|
||||
* This function triggers the following middleware.
|
||||
*
|
||||
@@ -2608,7 +2644,7 @@ Model.findOneAndRemove = function(conditions, options, callback) {
|
||||
*
|
||||
* Finds a matching document, removes it, passing the found document (if any) to the callback.
|
||||
*
|
||||
* Executes immediately if `callback` is passed, else a `Query` object is returned.
|
||||
* Executes the query if `callback` is passed.
|
||||
*
|
||||
* This function triggers the following middleware.
|
||||
*
|
||||
@@ -3851,6 +3887,7 @@ function populate(model, docs, options, callback) {
|
||||
for (const foreignField of mod.foreignField) {
|
||||
_val = utils.getValue(foreignField, val);
|
||||
if (Array.isArray(_val)) {
|
||||
_val = utils.array.flatten(_val);
|
||||
const _valLength = _val.length;
|
||||
for (let j = 0; j < _valLength; ++j) {
|
||||
let __val = _val[j];
|
||||
@@ -3937,6 +3974,8 @@ function assignVals(o) {
|
||||
justOne: o.justOne
|
||||
});
|
||||
|
||||
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);
|
||||
@@ -3978,6 +4017,7 @@ function assignVals(o) {
|
||||
}
|
||||
|
||||
if (o.isVirtual && docs[i] instanceof Model) {
|
||||
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, rawIds[i], docs[i], setValue);
|
||||
|
||||
+4
@@ -16,6 +16,10 @@ module.exports = function shardingPlugin(schema) {
|
||||
applyWhere.call(this);
|
||||
next();
|
||||
});
|
||||
schema.pre('remove', function(next) {
|
||||
applyWhere.call(this);
|
||||
next();
|
||||
});
|
||||
schema.post('save', function() {
|
||||
storeShard.call(this);
|
||||
});
|
||||
|
||||
+118
-44
@@ -5,12 +5,14 @@
|
||||
*/
|
||||
|
||||
const CastError = require('./error/cast');
|
||||
const DocumentNotFoundError = require('./error/notFound');
|
||||
const Kareem = require('kareem');
|
||||
const ObjectParameterError = require('./error/objectParameter');
|
||||
const QueryCursor = require('./cursor/QueryCursor');
|
||||
const ReadPreference = require('./driver').get().ReadPreference;
|
||||
const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
|
||||
const cast = require('./cast');
|
||||
const castArrayFilters = require('./helpers/update/castArrayFilters');
|
||||
const castUpdate = require('./helpers/query/castUpdate');
|
||||
const completeMany = require('./helpers/query/completeMany');
|
||||
const get = require('./helpers/get');
|
||||
@@ -1728,6 +1730,18 @@ Query.prototype._castConditions = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* ignore
|
||||
*/
|
||||
|
||||
function _castArrayFilters(query) {
|
||||
try {
|
||||
castArrayFilters(query);
|
||||
} catch (err) {
|
||||
query.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thunk around find()
|
||||
*
|
||||
@@ -2388,39 +2402,52 @@ Query.prototype.sort = function(arg) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Declare and/or execute this query as a remove() operation.
|
||||
* Declare and/or execute this query as a remove() operation. `remove()` is
|
||||
* deprecated, you should use [`deleteOne()`](#query_Query-deleteOne)
|
||||
* or [`deleteMany()`](#query_Query-deleteMany) instead.
|
||||
*
|
||||
* This function does not trigger any middleware
|
||||
*
|
||||
* ####Example
|
||||
*
|
||||
* Model.remove({ artist: 'Anne Murray' }, callback)
|
||||
* Character.remove({ name: /Stark/ }, callback);
|
||||
*
|
||||
* This function calls the MongoDB driver's [`Collection#remove()` function](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#remove).
|
||||
* The returned [promise](https://mongoosejs.com/docs/queries.html) resolves to an
|
||||
* object that contains 3 properties:
|
||||
*
|
||||
* - `ok`: `1` if no errors occurred
|
||||
* - `deletedCount`: the number of documents deleted
|
||||
* - `n`: the number of documents deleted. Equal to `deletedCount`.
|
||||
*
|
||||
* ####Example
|
||||
*
|
||||
* const res = await Character.remove({ name: /Stark/ });
|
||||
* // Number of docs deleted
|
||||
* res.deletedCount;
|
||||
*
|
||||
* ####Note
|
||||
*
|
||||
* The operation is only executed when a callback is passed. To force execution without a callback, you must first call `remove()` and then execute it by using the `exec()` method.
|
||||
* Calling `remove()` creates a [Mongoose query](./queries.html), and a query
|
||||
* does not execute until you either pass a callback, call [`Query#then()`](#query_Query-then),
|
||||
* or call [`Query#exec()`](#query_Query-exec).
|
||||
*
|
||||
* // not executed
|
||||
* var query = Model.find().remove({ name: 'Anne Murray' })
|
||||
* const query = Character.remove({ name: /Stark/ });
|
||||
*
|
||||
* // executed
|
||||
* query.remove({ name: 'Anne Murray' }, callback)
|
||||
* query.remove({ name: 'Anne Murray' }).remove(callback)
|
||||
* Character.remove({ name: /Stark/ }, callback);
|
||||
* Character.remove({ name: /Stark/ }).remove(callback);
|
||||
*
|
||||
* // executed without a callback
|
||||
* query.exec()
|
||||
*
|
||||
* // summary
|
||||
* query.remove(conds, fn); // executes
|
||||
* query.remove(conds)
|
||||
* query.remove(fn) // executes
|
||||
* query.remove()
|
||||
* Character.exec();
|
||||
*
|
||||
* @param {Object|Query} [filter] mongodb selector
|
||||
* @param {Function} [callback] optional params are (error, writeOpResult)
|
||||
* @param {Function} [callback] optional params are (error, mongooseDeleteResult)
|
||||
* @return {Query} this
|
||||
* @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
|
||||
* @see remove http://docs.mongodb.org/manual/reference/method/db.collection.remove/
|
||||
* @deprecated
|
||||
* @see deleteWriteOpResult http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~deleteWriteOpResult
|
||||
* @see MongoDB driver remove http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#remove
|
||||
* @api public
|
||||
*/
|
||||
|
||||
@@ -2462,7 +2489,7 @@ Query.prototype._remove = wrapThunk(function(callback) {
|
||||
|
||||
callback = _wrapThunkCallback(this, callback);
|
||||
|
||||
return Query.base.remove.call(this, helpers.handleWriteOpResult(callback));
|
||||
return Query.base.remove.call(this, helpers.handleDeleteWriteOpResult(callback));
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -2474,14 +2501,28 @@ Query.prototype._remove = wrapThunk(function(callback) {
|
||||
*
|
||||
* ####Example
|
||||
*
|
||||
* Character.deleteOne({ name: 'Eddard Stark' }, callback)
|
||||
* Character.deleteOne({ name: 'Eddard Stark' }).then(next)
|
||||
* Character.deleteOne({ name: 'Eddard Stark' }, callback);
|
||||
* Character.deleteOne({ name: 'Eddard Stark' }).then(next);
|
||||
*
|
||||
* This function calls the MongoDB driver's [`Collection#deleteOne()` function](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#deleteOne).
|
||||
* The returned [promise](https://mongoosejs.com/docs/queries.html) resolves to an
|
||||
* object that contains 3 properties:
|
||||
*
|
||||
* - `ok`: `1` if no errors occurred
|
||||
* - `deletedCount`: the number of documents deleted
|
||||
* - `n`: the number of documents deleted. Equal to `deletedCount`.
|
||||
*
|
||||
* ####Example
|
||||
*
|
||||
* const res = await Character.deleteOne({ name: 'Eddard Stark' });
|
||||
* // `1` if MongoDB deleted a doc, `0` if no docs matched the filter `{ name: ... }`
|
||||
* res.deletedCount;
|
||||
*
|
||||
* @param {Object|Query} [filter] mongodb selector
|
||||
* @param {Function} [callback] optional params are (error, writeOpResult)
|
||||
* @param {Function} [callback] optional params are (error, mongooseDeleteResult)
|
||||
* @return {Query} this
|
||||
* @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
|
||||
* @see remove http://docs.mongodb.org/manual/reference/method/db.collection.remove/
|
||||
* @see deleteWriteOpResult http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~deleteWriteOpResult
|
||||
* @see MongoDB Driver deleteOne http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#deleteOne
|
||||
* @api public
|
||||
*/
|
||||
|
||||
@@ -2524,7 +2565,7 @@ Query.prototype._deleteOne = wrapThunk(function(callback) {
|
||||
|
||||
callback = _wrapThunkCallback(this, callback);
|
||||
|
||||
return Query.base.deleteOne.call(this, helpers.handleWriteOpResult(callback));
|
||||
return Query.base.deleteOne.call(this, helpers.handleDeleteWriteOpResult(callback));
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -2539,11 +2580,25 @@ Query.prototype._deleteOne = wrapThunk(function(callback) {
|
||||
* Character.deleteMany({ name: /Stark/, age: { $gte: 18 } }, callback)
|
||||
* Character.deleteMany({ name: /Stark/, age: { $gte: 18 } }).then(next)
|
||||
*
|
||||
* This function calls the MongoDB driver's [`Collection#deleteOne()` function](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#deleteMany).
|
||||
* The returned [promise](https://mongoosejs.com/docs/queries.html) resolves to an
|
||||
* object that contains 3 properties:
|
||||
*
|
||||
* - `ok`: `1` if no errors occurred
|
||||
* - `deletedCount`: the number of documents deleted
|
||||
* - `n`: the number of documents deleted. Equal to `deletedCount`.
|
||||
*
|
||||
* ####Example
|
||||
*
|
||||
* const res = await Character.deleteMany({ name: /Stark/, age: { $gte: 18 } });
|
||||
* // `0` if no docs matched the filter, number of docs deleted otherwise
|
||||
* res.deletedCount;
|
||||
*
|
||||
* @param {Object|Query} [filter] mongodb selector
|
||||
* @param {Function} [callback] optional params are (error, writeOpResult)
|
||||
* @param {Function} [callback] optional params are (error, mongooseDeleteResult)
|
||||
* @return {Query} this
|
||||
* @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
|
||||
* @see remove http://docs.mongodb.org/manual/reference/method/db.collection.remove/
|
||||
* @see deleteWriteOpResult http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~deleteWriteOpResult
|
||||
* @see MongoDB Driver deleteMany http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#deleteMany
|
||||
* @api public
|
||||
*/
|
||||
|
||||
@@ -2586,7 +2641,7 @@ Query.prototype._deleteMany = wrapThunk(function(callback) {
|
||||
|
||||
callback = _wrapThunkCallback(this, callback);
|
||||
|
||||
return Query.base.deleteMany.call(this, helpers.handleWriteOpResult(callback));
|
||||
return Query.base.deleteMany.call(this, helpers.handleDeleteWriteOpResult(callback));
|
||||
});
|
||||
|
||||
/*!
|
||||
@@ -2647,7 +2702,9 @@ function prepareDiscriminatorCriteria(query) {
|
||||
/**
|
||||
* Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) update command.
|
||||
*
|
||||
* Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes immediately if `callback` is passed.
|
||||
* Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found
|
||||
* document (if any) to the callback. The query executes if
|
||||
* `callback` is passed.
|
||||
*
|
||||
* This function triggers the following middleware.
|
||||
*
|
||||
@@ -2778,7 +2835,8 @@ Query.prototype._findOneAndUpdate = wrapThunk(function(callback) {
|
||||
/**
|
||||
* Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) remove command.
|
||||
*
|
||||
* Finds a matching document, removes it, passing the found document (if any) to the callback. Executes immediately if `callback` is passed.
|
||||
* Finds a matching document, removes it, passing the found document (if any) to
|
||||
* the callback. Executes if `callback` is passed.
|
||||
*
|
||||
* This function triggers the following middleware.
|
||||
*
|
||||
@@ -2856,7 +2914,8 @@ Query.prototype.findOneAndRemove = function(conditions, options, callback) {
|
||||
/**
|
||||
* Issues a MongoDB [findOneAndDelete](https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndDelete/) command.
|
||||
*
|
||||
* Finds a matching document, removes it, and passes the found document (if any) to the callback. Executes immediately if `callback` is passed.
|
||||
* Finds a matching document, removes it, and passes the found document (if any)
|
||||
* to the callback. Executes if `callback` is passed.
|
||||
*
|
||||
* This function triggers the following middleware.
|
||||
*
|
||||
@@ -2978,7 +3037,8 @@ Query.prototype._findOneAndDelete = wrapThunk(function(callback) {
|
||||
/**
|
||||
* Issues a MongoDB [findOneAndReplace](https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndReplace/) command.
|
||||
*
|
||||
* Finds a matching document, removes it, and passes the found document (if any) to the callback. Executes immediately if `callback` is passed.
|
||||
* Finds a matching document, removes it, and passes the found document (if any)
|
||||
* to the callback. Executes if `callback` is passed.
|
||||
*
|
||||
* This function triggers the following middleware.
|
||||
*
|
||||
@@ -3147,6 +3207,8 @@ Query.prototype._findAndModify = function(type, callback) {
|
||||
return callback(castedQuery);
|
||||
}
|
||||
|
||||
_castArrayFilters(this);
|
||||
|
||||
const opts = this._optionsForExec(model);
|
||||
|
||||
if ('strict' in opts) {
|
||||
@@ -3385,6 +3447,8 @@ function _updateThunk(op, callback) {
|
||||
|
||||
this._castConditions();
|
||||
|
||||
_castArrayFilters(this);
|
||||
|
||||
if (this.error() != null) {
|
||||
callback(this.error());
|
||||
return null;
|
||||
@@ -3886,7 +3950,7 @@ Query.prototype.map = function(fn) {
|
||||
* @method orFail
|
||||
* @memberOf Query
|
||||
* @instance
|
||||
* @param {Function|Error} [err] optional error to throw if no docs match `filter`
|
||||
* @param {Function|Error} [err] optional error to throw if no docs match `filter`. If not specified, `orFail()` will throw a `DocumentNotFoundError`
|
||||
* @return {Query} this
|
||||
*/
|
||||
|
||||
@@ -3895,42 +3959,36 @@ Query.prototype.orFail = function(err) {
|
||||
switch (this.op) {
|
||||
case 'find':
|
||||
if (res.length === 0) {
|
||||
err = typeof err === 'function' ? err.call(this) : err;
|
||||
throw err;
|
||||
throw _orFailError(err, this);
|
||||
}
|
||||
break;
|
||||
case 'findOne':
|
||||
if (res == null) {
|
||||
err = typeof err === 'function' ? err.call(this) : err;
|
||||
throw err;
|
||||
throw _orFailError(err, this);
|
||||
}
|
||||
break;
|
||||
case 'update':
|
||||
case 'updateMany':
|
||||
case 'updateOne':
|
||||
if (get(res, 'result.nModified') === 0) {
|
||||
err = typeof err === 'function' ? err.call(this) : err;
|
||||
throw err;
|
||||
throw _orFailError(err, this);
|
||||
}
|
||||
break;
|
||||
case 'findOneAndDelete':
|
||||
if (get(res, 'lastErrorObject.n') === 0) {
|
||||
err = typeof err === 'function' ? err.call(this) : err;
|
||||
throw err;
|
||||
throw _orFailError(err, this);
|
||||
}
|
||||
break;
|
||||
case 'findOneAndUpdate':
|
||||
if (get(res, 'lastErrorObject.updatedExisting') === false) {
|
||||
err = typeof err === 'function' ? err.call(this) : err;
|
||||
throw err;
|
||||
throw _orFailError(err, this);
|
||||
}
|
||||
break;
|
||||
case 'deleteMany':
|
||||
case 'deleteOne':
|
||||
case 'remove':
|
||||
if (res.n === 0) {
|
||||
err = typeof err === 'function' ? err.call(this) : err;
|
||||
throw err;
|
||||
throw _orFailError(err, this);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -3942,6 +4000,22 @@ Query.prototype.orFail = function(err) {
|
||||
return this;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Get the error to throw for `orFail()`
|
||||
*/
|
||||
|
||||
function _orFailError(err, query) {
|
||||
if (typeof err === 'function') {
|
||||
err = err.call(query);
|
||||
}
|
||||
|
||||
if (err == null) {
|
||||
err = new DocumentNotFoundError(query.getQuery());
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query
|
||||
*
|
||||
|
||||
+4
-3
@@ -296,11 +296,12 @@ function makeLean(val) {
|
||||
* Handle the `WriteOpResult` from the server
|
||||
*/
|
||||
|
||||
exports.handleWriteOpResult = function handleWriteOpResult(callback) {
|
||||
return function _handleWriteOpResult(error, res) {
|
||||
exports.handleDeleteWriteOpResult = function handleDeleteWriteOpResult(callback) {
|
||||
return function _handleDeleteWriteOpResult(error, res) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
return callback(null, res.result);
|
||||
return callback(null,
|
||||
Object.assign({}, res.result, {deletedCount: res.deletedCount }));
|
||||
};
|
||||
};
|
||||
|
||||
+15
-11
@@ -23,9 +23,11 @@ const validateRef = require('./helpers/populate/validateRef');
|
||||
|
||||
let MongooseTypes;
|
||||
|
||||
const allMiddleware = require('./helpers/query/applyQueryMiddleware').
|
||||
middlewareFunctions.
|
||||
concat(require('./helpers/model/applyHooks').middlewareFunctions);
|
||||
const queryHooks = require('./helpers/query/applyQueryMiddleware').
|
||||
middlewareFunctions;
|
||||
const documentHooks = require('./helpers/model/applyHooks').middlewareFunctions;
|
||||
const hookNames = queryHooks.concat(documentHooks).
|
||||
reduce((s, hook) => s.add(hook), new Set());
|
||||
|
||||
let id = 0;
|
||||
|
||||
@@ -851,7 +853,7 @@ Schema.prototype.pathType = function(path) {
|
||||
}
|
||||
const re = new RegExp('^' + _path.replace(/\.\$\*/g, '.[^.]+') + '$');
|
||||
if (re.test(path)) {
|
||||
return this.paths[_path];
|
||||
return 'real';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,6 +920,10 @@ Schema.prototype.setupTimestamp = function(timestamps) {
|
||||
this.add(schemaAdditions);
|
||||
|
||||
this.pre('save', function(next) {
|
||||
if (get(this, '$__.saveOptions.timestamps') === false) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const defaultTimestamp = (this.ownerDocument ? this.ownerDocument() : this).
|
||||
constructor.base.now();
|
||||
const auto_id = this._id && this._id.auto;
|
||||
@@ -975,7 +981,7 @@ Schema.prototype.setupTimestamp = function(timestamps) {
|
||||
function getPositionalPathType(self, path) {
|
||||
const subpaths = path.split(/\.(\d+)\.|\.(\d+)$/).filter(Boolean);
|
||||
if (subpaths.length < 2) {
|
||||
return self.paths.hasOwnProperty(subpaths[0]) ? self.paths[subpath[0]] : null;
|
||||
return self.paths.hasOwnProperty(subpaths[0]) ? self.paths[subpaths[0]] : null;
|
||||
}
|
||||
|
||||
let val = self.path(subpaths[0]);
|
||||
@@ -985,12 +991,10 @@ function getPositionalPathType(self, path) {
|
||||
}
|
||||
|
||||
const last = subpaths.length - 1;
|
||||
let subpath;
|
||||
let i = 1;
|
||||
|
||||
for (; i < subpaths.length; ++i) {
|
||||
for (let i = 1; i < subpaths.length; ++i) {
|
||||
isNested = false;
|
||||
subpath = subpaths[i];
|
||||
const subpath = subpaths[i];
|
||||
|
||||
if (i === last && val && !/\D/.test(subpath)) {
|
||||
if (val.$isMongooseDocumentArray) {
|
||||
@@ -1095,7 +1099,7 @@ Schema.prototype.queue = function(name, args) {
|
||||
Schema.prototype.pre = function(name) {
|
||||
if (name instanceof RegExp) {
|
||||
const remainingArgs = Array.prototype.slice.call(arguments, 1);
|
||||
for (const fn of allMiddleware) {
|
||||
for (const fn of hookNames) {
|
||||
if (name.test(fn)) {
|
||||
this.pre.apply(this, [fn].concat(remainingArgs));
|
||||
}
|
||||
@@ -1146,7 +1150,7 @@ Schema.prototype.pre = function(name) {
|
||||
Schema.prototype.post = function(name) {
|
||||
if (name instanceof RegExp) {
|
||||
const remainingArgs = Array.prototype.slice.call(arguments, 1);
|
||||
for (const fn of allMiddleware) {
|
||||
for (const fn of hookNames) {
|
||||
if (name.test(fn)) {
|
||||
this.post.apply(this, [fn].concat(remainingArgs));
|
||||
}
|
||||
|
||||
+34
-9
@@ -128,6 +128,17 @@ function SchemaArray(key, cast, options, schemaOptions) {
|
||||
*/
|
||||
SchemaArray.schemaName = 'Array';
|
||||
|
||||
/**
|
||||
* Options for all arrays.
|
||||
*
|
||||
* - `castNonArrays`: `true` by default. If `false`, Mongoose will throw a CastError when a value isn't an array. If `true`, Mongoose will wrap the provided value in an array before casting.
|
||||
*
|
||||
* @static options
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SchemaArray.options = { castNonArrays: true };
|
||||
|
||||
/*!
|
||||
* Inherits from SchemaType.
|
||||
*/
|
||||
@@ -217,12 +228,17 @@ SchemaArray.prototype.cast = function(value, doc, init) {
|
||||
|
||||
return value;
|
||||
}
|
||||
// gh-2442: if we're loading this from the db and its not an array, mark
|
||||
// the whole array as modified.
|
||||
if (!!doc && !!init) {
|
||||
doc.markModified(this.path);
|
||||
|
||||
if (init || SchemaArray.options.castNonArrays) {
|
||||
// gh-2442: if we're loading this from the db and its not an array, mark
|
||||
// the whole array as modified.
|
||||
if (!!doc && !!init) {
|
||||
doc.markModified(this.path);
|
||||
}
|
||||
return this.cast([value], doc, init);
|
||||
}
|
||||
return this.cast([value], doc, init);
|
||||
|
||||
throw new CastError('Array', util.inspect(value), this.path);
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -336,16 +352,25 @@ function cast$all(val) {
|
||||
function cast$elemMatch(val) {
|
||||
const keys = Object.keys(val);
|
||||
const numKeys = keys.length;
|
||||
let key;
|
||||
let value;
|
||||
for (let i = 0; i < numKeys; ++i) {
|
||||
key = keys[i];
|
||||
value = val[key];
|
||||
const key = keys[i];
|
||||
const value = val[key];
|
||||
if (key.indexOf('$') === 0 && value) {
|
||||
val[key] = this.castForQuery(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Is this an embedded discriminator and is the discriminator key set?
|
||||
// If so, use the discriminator schema. See gh-7449
|
||||
const discriminatorKey = get(this,
|
||||
'casterConstructor.schema.options.discriminatorKey');
|
||||
const discriminators = get(this, 'casterConstructor.schema.discriminators', {});
|
||||
if (discriminatorKey != null &&
|
||||
val[discriminatorKey] != null &&
|
||||
discriminators[val[discriminatorKey]] != null) {
|
||||
return cast(discriminators[val[discriminatorKey]], val);
|
||||
}
|
||||
|
||||
return cast(this.casterConstructor.schema, val);
|
||||
}
|
||||
|
||||
|
||||
+14
@@ -61,6 +61,17 @@ function DocumentArray(key, schema, options, schemaOptions) {
|
||||
*/
|
||||
DocumentArray.schemaName = 'DocumentArray';
|
||||
|
||||
/**
|
||||
* Options for all document arrays.
|
||||
*
|
||||
* - `castNonArrays`: `true` by default. If `false`, Mongoose will throw a CastError when a value isn't an array. If `true`, Mongoose will wrap the provided value in an array before casting.
|
||||
*
|
||||
* @static options
|
||||
* @api public
|
||||
*/
|
||||
|
||||
DocumentArray.options = { castNonArrays: true };
|
||||
|
||||
/*!
|
||||
* Inherits from ArrayType.
|
||||
*/
|
||||
@@ -310,6 +321,9 @@ DocumentArray.prototype.cast = function(value, doc, init, prev, options) {
|
||||
const _opts = { transform: false, virtuals: false };
|
||||
|
||||
if (!Array.isArray(value)) {
|
||||
if (!init && !DocumentArray.options.castNonArrays) {
|
||||
throw new CastError('DocumentArray', util.inspect(value), this.path);
|
||||
}
|
||||
// gh-2442 mark whole array as modified if we're initializing a doc from
|
||||
// the db and the path isn't an array in the document
|
||||
if (!!doc && init) {
|
||||
|
||||
+7
-2
@@ -1249,8 +1249,13 @@ SchemaType.prototype._castForQuery = function(val) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Override the function the required validator uses to check whether a string
|
||||
* passes the `required` check.
|
||||
* Override the function the required validator uses to check whether a value
|
||||
* passes the `required` check. Override this on the individual SchemaType.
|
||||
*
|
||||
* ####Example:
|
||||
*
|
||||
* // Use this to allow empty strings to pass the `required` validator
|
||||
* mongoose.Schema.Types.String.checkRequired(v => typeof v === 'string');
|
||||
*
|
||||
* @param {Function} fn
|
||||
* @return {Function}
|
||||
|
||||
+12
-6
@@ -44,12 +44,6 @@ function MongooseDocumentArray(values, path, doc) {
|
||||
// TODO: replace this with `new CoreMongooseArray().concat()` when we remove
|
||||
// support for node 4.x and 5.x, see https://i.imgur.com/UAAHk4S.png
|
||||
const arr = new CoreMongooseArray();
|
||||
if (Array.isArray(values)) {
|
||||
values.forEach(v => {
|
||||
arr.push(v);
|
||||
});
|
||||
}
|
||||
arr._path = path;
|
||||
|
||||
const props = {
|
||||
isMongooseDocumentArray: true,
|
||||
@@ -59,6 +53,18 @@ function MongooseDocumentArray(values, path, doc) {
|
||||
_handlers: void 0
|
||||
};
|
||||
|
||||
if (Array.isArray(values)) {
|
||||
if (values instanceof CoreMongooseArray &&
|
||||
values._path === path &&
|
||||
values._parent === doc) {
|
||||
props._atomics = Object.assign({}, values._atomics);
|
||||
}
|
||||
values.forEach(v => {
|
||||
arr.push(v);
|
||||
});
|
||||
}
|
||||
arr._path = path;
|
||||
|
||||
// Values always have to be passed to the constructor to initialize, since
|
||||
// otherwise MongooseArray#push will mark the array as modified to the parent.
|
||||
const keysMA = Object.keys(MongooseArray.mixin);
|
||||
|
||||
+13
-11
@@ -176,12 +176,13 @@ exports.last = function(arr) {
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
exports.clone = function clone(obj, options) {
|
||||
if (obj === undefined || obj === null) {
|
||||
exports.clone = function clone(obj, options, isArrayChild) {
|
||||
if (obj == null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -199,7 +200,7 @@ exports.clone = function clone(obj, options) {
|
||||
if (obj.constructor) {
|
||||
switch (exports.getFunctionName(obj.constructor)) {
|
||||
case 'Object':
|
||||
return cloneObject(obj, options);
|
||||
return cloneObject(obj, options, isArrayChild);
|
||||
case 'Date':
|
||||
return new obj.constructor(+obj);
|
||||
case 'RegExp':
|
||||
@@ -222,12 +223,14 @@ exports.clone = function clone(obj, options) {
|
||||
|
||||
if (!obj.constructor && exports.isObject(obj)) {
|
||||
// object created with Object.create(null)
|
||||
return cloneObject(obj, options);
|
||||
return cloneObject(obj, options, isArrayChild);
|
||||
}
|
||||
|
||||
if (obj.valueOf) {
|
||||
return obj.valueOf();
|
||||
}
|
||||
|
||||
return cloneObject(obj, options, isArrayChild);
|
||||
};
|
||||
const clone = exports.clone;
|
||||
|
||||
@@ -279,19 +282,18 @@ exports.promiseOrCallback = function promiseOrCallback(callback, fn, ee) {
|
||||
* ignore
|
||||
*/
|
||||
|
||||
function cloneObject(obj, options) {
|
||||
function cloneObject(obj, options, isArrayChild) {
|
||||
const minimize = options && options.minimize;
|
||||
const ret = {};
|
||||
let hasKeys;
|
||||
let val;
|
||||
let k;
|
||||
|
||||
for (k in obj) {
|
||||
for (const k in obj) {
|
||||
if (specialProperties.has(k)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
val = clone(obj[k], options);
|
||||
// Don't pass `isArrayChild` down
|
||||
const val = clone(obj[k], options);
|
||||
|
||||
if (!minimize || (typeof val !== 'undefined')) {
|
||||
hasKeys || (hasKeys = true);
|
||||
@@ -299,13 +301,13 @@ function cloneObject(obj, options) {
|
||||
}
|
||||
}
|
||||
|
||||
return minimize ? hasKeys && ret : ret;
|
||||
return minimize && !isArrayChild ? hasKeys && ret : ret;
|
||||
}
|
||||
|
||||
function cloneArray(arr, options) {
|
||||
const ret = [];
|
||||
for (let i = 0, l = arr.length; i < l; i++) {
|
||||
ret.push(clone(arr[i], options));
|
||||
ret.push(clone(arr[i], options, true));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
+2
-1
@@ -16,6 +16,7 @@
|
||||
* @param {string|function} [options.foreignField] the foreign field to populate on if this is a populated virtual.
|
||||
* @param {boolean} [options.justOne=false] by default, a populated virtual is an array. If you set `justOne`, the populated virtual will be a single doc or `null`.
|
||||
* @param {boolean} [options.getters=false] if you set this to `true`, Mongoose will call any custom getters you defined on this virtual
|
||||
* @param {boolean} [options.count=false] if you set this to `true`, `populate()` will set this virtual to the number of populated documents, as opposed to the documents themselves, using [`Query#countDocuments()`](./api.html#query_Query-countDocuments)
|
||||
* @api public
|
||||
*/
|
||||
|
||||
@@ -31,7 +32,7 @@ function VirtualType(options, name) {
|
||||
*
|
||||
* @param {Function} fn
|
||||
* @return {VirtualType} this
|
||||
* @api public
|
||||
* @api private
|
||||
*/
|
||||
|
||||
VirtualType.prototype._applyDefaultGetters = function() {
|
||||
|
||||
Reference in New Issue
Block a user