Skip to content

Commit

Permalink
Merge branch 'master' into 6.0
Browse files Browse the repository at this point in the history
Re: #9909
  • Loading branch information
vkarpov15 committed Feb 16, 2021
2 parents 127567d + 94a2a7f commit 623fff8
Show file tree
Hide file tree
Showing 29 changed files with 354 additions and 101 deletions.
9 changes: 9 additions & 0 deletions History.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
5.11.16 / 2021-02-12
====================
* fix(document): skip applying array element setters when init-ing an array #9889
* fix: upgrade to mongodb driver 3.6.4 #9893 [jooeycheng](https://github.com/jooeycheng)
* fix: avoid copying Object.prototype properties when cloning #9876
* fix(aggregate): automatically convert functions to strings when using `$function` operator #9897
* fix: call pre-remove hooks for subdocuments #9895 #9885 [IslandRhythms](https://github.com/IslandRhythms)
* docs: fix confusing sentence in Schema docs #9914 [namenyi](https://github.com/namenyi)

5.11.15 / 2021-02-03
====================
* fix(document): fix issues with `isSelected` as an path in a nested schema #9884 #9873 [IslandRhythms](https://github.com/IslandRhythms)
Expand Down
2 changes: 1 addition & 1 deletion docs/guide.pug
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ block content
const personSchema = new Schema({
n: {
type: String,
// Now accessing `name` will get you the value of `n`, and setting `n` will set the value of `name`
// Now accessing `name` will get you the value of `n`, and setting `name` will set the value of `n`
alias: 'name'
}
});
Expand Down
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,7 @@ declare module 'mongoose' {
}

interface SchemaTypeOptions<T> {
type: T;
type: T | SchemaDefinitionWithBuiltInClass<T>;

/** Defines a virtual with the given name that gets/sets this path. */
alias?: string;
Expand Down
4 changes: 2 additions & 2 deletions lib/aggregate.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const AggregationCursor = require('./cursor/AggregationCursor');
const Query = require('./query');
const applyGlobalMaxTimeMS = require('./helpers/query/applyGlobalMaxTimeMS');
const promiseOrCallback = require('./helpers/promiseOrCallback');
const stringifyAccumulatorOptions = require('./helpers/aggregate/stringifyAccumulatorOptions');
const stringifyFunctionOperators = require('./helpers/aggregate/stringifyFunctionOperators');
const util = require('util');
const utils = require('./utils');
const read = Query.prototype.read;
Expand Down Expand Up @@ -961,7 +961,7 @@ Aggregate.prototype.exec = function(callback) {

return promiseOrCallback(callback, cb => {
prepareDiscriminatorPipeline(this);
stringifyAccumulatorOptions(this._pipeline);
stringifyFunctionOperators(this._pipeline);

model.hooks.execPre('aggregate', this, error => {
if (error) {
Expand Down
2 changes: 1 addition & 1 deletion lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ Connection.prototype.startSession = _wrapConnHelper(function startSession(option
* @method transaction
* @param {Function} fn Function to execute in a transaction
* @param {mongodb.TransactionOptions} [options] Optional settings for the transaction
* @return {Promise<Any>} promise that resolves to the returned value of `fn`
* @return {Promise<Any>} promise that is fulfilled if Mongoose successfully committed the transaction, or rejects if the transaction was aborted or if Mongoose failed to commit the transaction. If fulfilled, the promise resolves to a MongoDB command result.
* @api public
*/

Expand Down
5 changes: 0 additions & 5 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -2258,7 +2258,6 @@ function _getPathsToValidate(doc) {
const skipSchemaValidators = {};

_evaluateRequiredFunctions(doc);

// only validate required fields when necessary
let paths = new Set(Object.keys(doc.$__.activePaths.states.require).filter(function(path) {
if (!doc.$__isSelected(path) && !doc.isModified(path)) {
Expand Down Expand Up @@ -2342,7 +2341,6 @@ function _getPathsToValidate(doc) {
}
}


for (const path of paths) {
// Single nested paths (paths embedded under single nested subdocs) will
// be validated on their own when we call `validate()` on the subdoc itself.
Expand Down Expand Up @@ -2436,11 +2434,9 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
pathDetails[0].filter((path) => this.isModified(path)) :
pathDetails[0];
const skipSchemaValidators = pathDetails[1];

if (Array.isArray(pathsToValidate)) {
paths = _handlePathsToValidate(paths, pathsToValidate);
}

if (paths.length === 0) {
return process.nextTick(function() {
const error = _complete();
Expand Down Expand Up @@ -2610,7 +2606,6 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
if (Array.isArray(pathsToValidate)) {
paths = _handlePathsToValidate(paths, pathsToValidate);
}

const validating = {};

paths.forEach(function(path) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

module.exports = function stringifyAccumulatorOptions(pipeline) {
module.exports = function stringifyFunctionOperators(pipeline) {
if (!Array.isArray(pipeline)) {
return;
}
Expand All @@ -17,9 +17,21 @@ module.exports = function stringifyAccumulatorOptions(pipeline) {
}
}

const stageType = Object.keys(stage)[0];
if (stageType && typeof stage[stageType] === 'object') {
const stageOptions = stage[stageType];
for (const key of Object.keys(stageOptions)) {
if (stageOptions[key] != null &&
stageOptions[key].$function != null &&
typeof stageOptions[key].$function.body === 'function') {
stageOptions[key].$function.body = stageOptions[key].$function.body.toString();
}
}
}

if (stage.$facet != null) {
for (const key of Object.keys(stage.$facet)) {
stringifyAccumulatorOptions(stage.$facet[key]);
stringifyFunctionOperators(stage.$facet[key]);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/helpers/clone.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ function cloneObject(obj, options, isArrayChild) {
const ret = {};
let hasKeys;

for (const k in obj) {
for (const k of Object.keys(obj)) {
if (specialProperties.has(k)) {
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/helpers/populate/assignVals.js
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ function valueFilter(val, assignmentOpts, populateOptions) {
if (populateOptions.justOne === false) {
return [];
}
return val;
return val == null ? val : null;
}

/*!
Expand Down
2 changes: 1 addition & 1 deletion lib/helpers/query/castFilterPath.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ module.exports = function castFilterPath(query, schematype, val) {
if (nested && schematype && !schematype.caster) {
const _keys = Object.keys(nested);
if (_keys.length && isOperator(_keys[0])) {
for (const key in nested) {
for (const key of Object.keys(nested)) {
nested[key] = schematype.castForQueryWrapper({
$conditional: key,
val: nested[key],
Expand Down
3 changes: 1 addition & 2 deletions lib/helpers/update/castArrayFilters.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ module.exports = function castArrayFilters(query) {
if (filter == null) {
throw new Error(`Got null array filter in ${arrayFilters}`);
}

for (const key in filter) {
for (const key of Object.keys(filter)) {
if (filter[key] == null) {
continue;
}
Expand Down
11 changes: 10 additions & 1 deletion lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,10 @@ function _ensureIndexes(model, options, callback) {
if ('background' in options) {
indexOptions.background = options.background;
}
if (model.schema.options.hasOwnProperty('collation') &&
!indexOptions.hasOwnProperty('collation')) {
indexOptions.collation = model.schema.options.collation;
}

const methodName = useCreateIndex ? 'createIndex' : 'ensureIndex';
model.collection[methodName](indexFields, indexOptions, utils.tick(function(err, name) {
Expand Down Expand Up @@ -4441,7 +4445,12 @@ function _assign(model, vals, mod, assignmentOpts) {
if (Array.isArray(rawDocs[key])) {
rawDocs[key].push(val);
rawOrder[key].push(i);
} else {
} else if (isVirtual ||
rawDocs[key].constructor !== val.constructor ||
String(rawDocs[key]._id) !== String(val._id)) {
// May need to store multiple docs with the same id if there's multiple models
// if we have discriminators or a ref function. But avoid converting to an array
// if we have multiple queries on the same model because of `perDocumentLimit` re: gh-9906
rawDocs[key] = [rawDocs[key], val];
rawOrder[key] = [rawOrder[key], i];
}
Expand Down
44 changes: 4 additions & 40 deletions lib/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -1480,13 +1480,11 @@ Query.prototype.setOptions = function(options, overwrite) {
Query.prototype.explain = function(verbose) {
if (arguments.length === 0) {
this.options.explain = true;
return this;
}
if (verbose === false) {
} else if (verbose === false) {
delete this.options.explain;
return this;
} else {
this.options.explain = verbose;
}
this.options.explain = verbose;
return this;
};

Expand Down Expand Up @@ -1775,40 +1773,6 @@ Query.prototype.lean = function(v) {
};

/**
<<<<<<< HEAD
* Returns an object containing the Mongoose-specific options for this query,
* including `lean` and `populate`.
*
* Mongoose-specific options are different from normal options (`sort`, `limit`, etc.)
* because they are **not** sent to the MongoDB server.
*
* ####Example:
*
* const q = new Query();
* q.mongooseOptions().lean; // undefined
*
* q.lean();
* q.mongooseOptions().lean; // true
*
* This function is useful for writing [query middleware](/docs/middleware.html).
* Below is a full list of properties the return value from this function may have:
*
* - `populate`
* - `lean`
* - `strict`
* - `nearSphere`
*
* @return {Object} Mongoose-specific options
* @param public
*/

Query.prototype.mongooseOptions = function() {
return this._mongooseOptions;
};

/**
=======
>>>>>>> master
* Adds a `$set` to this query's update without changing the operation.
* This is useful for query middleware so you can add an update regardless
* of whether you use `updateOne()`, `updateMany()`, `findOneAndUpdate()`, etc.
Expand Down Expand Up @@ -5011,7 +4975,7 @@ Query.prototype.tailable = function(val, opts) {
}

if (opts && typeof opts === 'object') {
for (const key in opts) {
for (const key of Object.keys(opts)) {
if (key === 'awaitdata') {
// For backwards compatibility
this.options[key] = !!opts[key];
Expand Down
10 changes: 5 additions & 5 deletions lib/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -687,18 +687,18 @@ Schema.prototype.path = function(path, obj) {
}

if (schemaType.$isSingleNested) {
for (const key in schemaType.schema.paths) {
for (const key of Object.keys(schemaType.schema.paths)) {
this.singleNestedPaths[path + '.' + key] = schemaType.schema.paths[key];
}
for (const key in schemaType.schema.singleNestedPaths) {
for (const key of Object.keys(schemaType.schema.singleNestedPaths)) {
this.singleNestedPaths[path + '.' + key] =
schemaType.schema.singleNestedPaths[key];
}
for (const key in schemaType.schema.subpaths) {
for (const key of Object.keys(schemaType.schema.subpaths)) {
this.singleNestedPaths[path + '.' + key] =
schemaType.schema.subpaths[key];
}
for (const key in schemaType.schema.nested) {
for (const key of Object.keys(schemaType.schema.nested)) {
this.singleNestedPaths[path + '.' + key] = 'nested';
}

Expand Down Expand Up @@ -1143,7 +1143,7 @@ Schema.prototype.hasMixedParent = function(path) {
path = '';
for (let i = 0; i < subpaths.length; ++i) {
path = i > 0 ? path + '.' + subpaths[i] : subpaths[i];
if (path in this.paths &&
if (this.paths.hasOwnProperty(path) &&
this.paths[path] instanceof MongooseTypes.Mixed) {
return this.paths[path];
}
Expand Down
11 changes: 9 additions & 2 deletions lib/schema/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,12 +262,19 @@ SchemaArray.prototype.enum = function() {
*/

SchemaArray.prototype.applyGetters = function(value, scope) {
if (this.caster.options && this.caster.options.ref) {
if (scope != null && scope.populated(this.path)) {
// means the object id was populated
return value;
}

return SchemaType.prototype.applyGetters.call(this, value, scope);
const ret = SchemaType.prototype.applyGetters.call(this, value, scope);
if (Array.isArray(ret)) {
const len = ret.length;
for (let i = 0; i < len; ++i) {
ret[i] = this.caster.applyGetters(ret[i], scope);
}
}
return ret;
};

SchemaArray.prototype._applySetters = function(value, scope, init, priorVal) {
Expand Down
8 changes: 8 additions & 0 deletions lib/schema/documentarray.js
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,14 @@ DocumentArrayPath.prototype.clone = function() {
return schematype;
};

/*!
* ignore
*/

DocumentArrayPath.prototype.applyGetters = function(value, scope) {
return SchemaType.prototype.applyGetters.call(this, value, scope);
};

/*!
* Scopes paths selected in a query to this array.
* Necessary for proper default application of subdocument values.
Expand Down
3 changes: 3 additions & 0 deletions lib/schematype.js
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,9 @@ SchemaType.prototype.getDefault = function(scope, init) {

SchemaType.prototype._applySetters = function(value, scope, init, priorVal) {
let v = value;
if (init) {
return v;
}
const setters = this.setters;

for (const setter of utils.clone(setters).reverse()) {
Expand Down
28 changes: 27 additions & 1 deletion lib/types/DocumentArray/methods/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,33 @@ const methods = {
};
},

_markModified: ArrayMethods._markModified
_markModified(elem, embeddedPath) {
const parent = this[arrayParentSymbol];
let dirtyPath;

if (parent) {
dirtyPath = this[arrayPathSymbol];

if (arguments.length) {
if (embeddedPath != null) {
// an embedded doc bubbled up the change
const index = elem.__index;
dirtyPath = dirtyPath + '.' + index + '.' + embeddedPath;
} else {
// directly set an index
dirtyPath = dirtyPath + '.' + elem;
}
}

if (dirtyPath != null && dirtyPath.endsWith('.$')) {
return this;
}

parent.markModified(dirtyPath, arguments.length > 0 ? elem : parent);
}

return this;
}
};

module.exports = methods;
Expand Down
14 changes: 2 additions & 12 deletions lib/types/array/ArrayWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,25 +284,15 @@ class ArrayWrapper extends Array {
* @memberOf MongooseArray
*/

_markModified(elem, embeddedPath) {
_markModified(elem) {
const parent = this[arrayParentSymbol];
let dirtyPath;

if (parent) {
dirtyPath = this[arrayPathSymbol];

const index = elem != null && elem.__index >= 0 ?
elem.__index :
this.indexOf(elem);

if (arguments.length) {
if (embeddedPath != null) {
// an embedded doc bubbled up the change
dirtyPath = dirtyPath + '.' + index + '.' + embeddedPath;
} else {
// directly set an index
dirtyPath = dirtyPath + '.' + elem;
}
dirtyPath = dirtyPath + '.' + elem;
}

if (dirtyPath != null && dirtyPath.endsWith('.$')) {
Expand Down
Loading

0 comments on commit 623fff8

Please sign in to comment.