diff --git a/lib/document.js b/lib/document.js index 45da5eb3f1..3f6a26b67e 100644 --- a/lib/document.js +++ b/lib/document.js @@ -198,7 +198,7 @@ function Document(obj, fields, options) { const _this = this; const keys = Object.keys(this._doc); - keys.forEach(function(key) { + keys.forEach(function (key) { // Avoid methods, virtuals, existing fields, and `$` keys. The latter is to avoid overwriting // Mongoose internals. if (!(key in schema.tree) && !(key in schema.methods) && !(key in schema.virtuals) && !key.startsWith('$')) { @@ -264,10 +264,10 @@ Document.prototype.$isMongooseDocumentPrototype = true; */ Object.defineProperty(Document.prototype, 'isNew', { - get: function() { + get: function () { return this.$isNew; }, - set: function(value) { + set: function (value) { this.$isNew = value; } }); @@ -282,10 +282,10 @@ Object.defineProperty(Document.prototype, 'isNew', { */ Object.defineProperty(Document.prototype, 'errors', { - get: function() { + get: function () { return this.$errors; }, - set: function(value) { + set: function (value) { this.$errors = value; } }); @@ -303,8 +303,8 @@ Document.prototype.$isNew = true; utils.each( ['on', 'once', 'emit', 'listeners', 'removeListener', 'setMaxListeners', 'removeAllListeners', 'addListener'], - function(emitterFn) { - Document.prototype[emitterFn] = function() { + function (emitterFn) { + Document.prototype[emitterFn] = function () { // Delay creating emitter until necessary because emitters take up a lot of memory, // especially for subdocuments. if (!this.$__.emitter) { @@ -373,13 +373,13 @@ Document.prototype.schema; Object.defineProperty(Document.prototype, '$locals', { configurable: false, enumerable: false, - get: function() { + get: function () { if (this.$__.locals == null) { this.$__.locals = {}; } return this.$__.locals; }, - set: function(v) { + set: function (v) { this.$__.locals = v; } }); @@ -469,10 +469,10 @@ Document.prototype.$errors; */ Object.defineProperty(Document.prototype, '$op', { - get: function() { + get: function () { return this.$__.op || null; }, - set: function(value) { + set: function (value) { this.$__.op = value; } }); @@ -556,7 +556,7 @@ function $applyDefaultsToNested(val, path, doc) { * @instance */ -Document.prototype.$__buildDoc = function(obj, fields, skipId, exclude, hasIncludedChildren) { +Document.prototype.$__buildDoc = function (obj, fields, skipId, exclude, hasIncludedChildren) { const doc = {}; const paths = Object.keys(this.$__schema.paths). @@ -620,7 +620,7 @@ Document.prototype.$__buildDoc = function(obj, fields, skipId, exclude, hasInclu * Converts to POJO when you use the document for querying */ -Document.prototype.toBSON = function() { +Document.prototype.toBSON = function () { return this.toObject(internalToObjectOptions); }; @@ -642,7 +642,7 @@ Document.prototype.toBSON = function() { * @instance */ -Document.prototype.init = function(doc, opts, fn) { +Document.prototype.init = function (doc, opts, fn) { if (typeof opts === 'function') { fn = opts; opts = null; @@ -663,7 +663,7 @@ Document.prototype.init = function(doc, opts, fn) { * @api public */ -Document.prototype.$init = function() { +Document.prototype.$init = function () { return this.constructor.prototype.init.apply(this, arguments); }; @@ -676,7 +676,10 @@ Document.prototype.$init = function() { * @api private */ -Document.prototype.$__init = function(doc, opts) { +Document.prototype.$__init = function (doc, opts) { + if (doc == null) { + throw new ObjectParameterError(doc, 'doc', 'init'); + } this.$isNew = false; opts = opts || {}; @@ -1121,10 +1124,10 @@ Document.prototype.$set = function $set(path, val, type, options) { // On initial set, delete any nested keys if we're going to overwrite // them to ensure we keep the user's key order. if (type === true && - !prefix && - valForKey != null && - pathtype === 'nested' && - this._doc[key] != null) { + !prefix && + valForKey != null && + pathtype === 'nested' && + this._doc[key] != null) { delete this._doc[key]; } @@ -1135,7 +1138,7 @@ Document.prototype.$set = function $set(path, val, type, options) { } else if (strict) { // Don't overwrite defaults with undefined keys (gh-3981) (gh-9039) if (constructing && valForKey === void 0 && - this.$get(pathName) !== void 0) { + this.$get(pathName) !== void 0) { continue; } @@ -1167,8 +1170,8 @@ Document.prototype.$set = function $set(path, val, type, options) { const orderedKeys = Object.keys(this.$__schema.tree); for (let i = 0, len = orderedKeys.length; i < len; ++i) { (key = orderedKeys[i]) && - (this._doc.hasOwnProperty(key)) && - (orderedDoc[key] = undefined); + (this._doc.hasOwnProperty(key)) && + (orderedDoc[key] = undefined); } this._doc = Object.assign(orderedDoc, this._doc); @@ -1242,8 +1245,8 @@ Document.prototype.$set = function $set(path, val, type, options) { this.$set(path + '.' + key, val[key], constructing, { ...options, _skipMarkModified: true }); } if (priorVal != null && - (!wasModified || hasInitialVal) && - utils.deepEqual(hasInitialVal ? this.$__.savedState[path] : priorVal, val)) { + (!wasModified || hasInitialVal) && + utils.deepEqual(hasInitialVal ? this.$__.savedState[path] : priorVal, val)) { this.unmarkModified(path); } else { this.markModified(path); @@ -1424,13 +1427,13 @@ Document.prototype.$set = function $set(path, val, type, options) { let popOpts; const typeKey = this.$__schema.options.typeKey; if (schema.options && - Array.isArray(schema.options[typeKey]) && - schema.options[typeKey].length && - schema.options[typeKey][0] && - schema.options[typeKey][0].ref && - _isManuallyPopulatedArray(val, schema.options[typeKey][0].ref)) { + Array.isArray(schema.options[typeKey]) && + schema.options[typeKey].length && + schema.options[typeKey][0] && + schema.options[typeKey][0].ref && + _isManuallyPopulatedArray(val, schema.options[typeKey][0].ref)) { popOpts = { [populateModelSymbol]: val[0].constructor }; - this.$populated(path, val.map(function(v) { return v._doc._id; }), popOpts); + this.$populated(path, val.map(function (v) { return v._doc._id; }), popOpts); for (const doc of val) { doc.$__.wasPopulated = { value: doc._doc._id }; @@ -1455,12 +1458,12 @@ Document.prototype.$set = function $set(path, val, type, options) { } if (Array.isArray(val) && - !Array.isArray(schema) && - schema.$isMongooseDocumentArray && - val.length !== 0 && - val[0] != null && - val[0].$__ != null && - val[0].$__.populated != null) { + !Array.isArray(schema) && + schema.$isMongooseDocumentArray && + val.length !== 0 && + val[0] != null && + val[0].$__ != null && + val[0].$__.populated != null) { const populatedPaths = Object.keys(val[0].$__.populated); for (const populatedPath of populatedPaths) { this.$populated(path + '.' + populatedPath, @@ -1523,9 +1526,9 @@ Document.prototype.$set = function $set(path, val, type, options) { this.$__.session[sessionNewDocuments].get(this).modifiedPaths && !this.$__.session[sessionNewDocuments].get(this).modifiedPaths.has(savedStatePath); if (savedState != null && - savedState.hasOwnProperty(savedStatePath) && - (!isInTransaction || isModifiedWithinTransaction) && - utils.deepEqual(val, savedState[savedStatePath])) { + savedState.hasOwnProperty(savedStatePath) && + (!isInTransaction || isModifiedWithinTransaction) && + utils.deepEqual(val, savedState[savedStatePath])) { this.unmarkModified(path); } } @@ -1624,7 +1627,7 @@ Document.prototype.set = Document.prototype.$set; * @instance */ -Document.prototype.$__shouldModify = function(pathToMark, path, options, constructing, parts, schema, val, priorVal) { +Document.prototype.$__shouldModify = function (pathToMark, path, options, constructing, parts, schema, val, priorVal) { if (options && options._skipMarkModified) { return false; } @@ -1650,8 +1653,8 @@ Document.prototype.$__shouldModify = function(pathToMark, path, options, constru // gh-3992: if setting a populated field to a doc, don't mark modified // if they have the same _id if (this.$populated(path) && - val instanceof Document && - deepEqual(val._doc._id, priorVal)) { + val instanceof Document && + deepEqual(val._doc._id, priorVal)) { return false; } @@ -1660,10 +1663,10 @@ Document.prototype.$__shouldModify = function(pathToMark, path, options, constru } if (!constructing && - val !== null && - val !== undefined && - path in this.$__.activePaths.getStatePaths('default') && - deepEqual(val, schema.getDefault(this, constructing))) { + val !== null && + val !== undefined && + path in this.$__.activePaths.getStatePaths('default') && + deepEqual(val, schema.getDefault(this, constructing))) { // a path with a default was $unset on the server // and the user is setting it to the same value again return true; @@ -1688,7 +1691,7 @@ Document.prototype.$__shouldModify = function(pathToMark, path, options, constru * @instance */ -Document.prototype.$__set = function(pathToMark, path, options, constructing, parts, schema, val, priorVal) { +Document.prototype.$__set = function (pathToMark, path, options, constructing, parts, schema, val, priorVal) { Embedded = Embedded || require('./types/arraySubdocument'); const shouldModify = this.$__shouldModify(pathToMark, path, options, constructing, parts, @@ -1710,7 +1713,7 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa // Update embedded document parent references (gh-5189) if (utils.isMongooseDocumentArray(val)) { - val.forEach(function(item) { + val.forEach(function (item) { item && item.__parentArray && (item.__parentArray = val); }); } @@ -1790,7 +1793,7 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa * @api private */ -Document.prototype.$__getValue = function(path) { +Document.prototype.$__getValue = function (path) { if (typeof path !== 'string' && !Array.isArray(path)) { throw new TypeError( `Invalid \`path\`. Must be either string or array. Got "${path}" (type ${typeof path})` @@ -1882,7 +1885,7 @@ Document.prototype.$inc = function $inc(path, val) { * @api private */ -Document.prototype.$__setValue = function(path, val) { +Document.prototype.$__setValue = function (path, val) { utils.setValue(path, val, this._doc); return this; }; @@ -1907,7 +1910,7 @@ Document.prototype.$__setValue = function(path, val) { * @api public */ -Document.prototype.get = function(path, type, options) { +Document.prototype.get = function (path, type, options) { let adhoc; if (options == null) { options = {}; @@ -2003,7 +2006,7 @@ Document.prototype.$get = Document.prototype.get; * @instance */ -Document.prototype.$__path = function(path) { +Document.prototype.$__path = function (path) { const adhocs = this.$__.adhocPaths; const adhocType = adhocs && adhocs.hasOwnProperty(path) ? adhocs[path] : null; @@ -2029,7 +2032,7 @@ Document.prototype.$__path = function(path) { * @api public */ -Document.prototype.markModified = function(path, scope) { +Document.prototype.markModified = function (path, scope) { this.$__saveInitialState(path); this.$__.activePaths.modify(path); @@ -2068,7 +2071,7 @@ Document.prototype.$__saveInitialState = function $__saveInitialState(path) { * @api public */ -Document.prototype.unmarkModified = function(path) { +Document.prototype.unmarkModified = function (path) { this.$__.activePaths.init(path); if (this.$__.pathsToScopes != null) { delete this.$__.pathsToScopes[path]; @@ -2091,7 +2094,7 @@ Document.prototype.unmarkModified = function(path) { * @api public */ -Document.prototype.$ignore = function(path) { +Document.prototype.$ignore = function (path) { this.$__.activePaths.ignore(path); }; @@ -2118,7 +2121,7 @@ Document.prototype.$ignore = function(path) { * @api public */ -Document.prototype.directModifiedPaths = function() { +Document.prototype.directModifiedPaths = function () { return Object.keys(this.$__.activePaths.getStatePaths('modify')); }; @@ -2147,7 +2150,7 @@ Document.prototype.directModifiedPaths = function() { * @return {Boolean} */ -Document.prototype.$isEmpty = function(path) { +Document.prototype.$isEmpty = function (path) { const isEmptyOptions = { minimize: true, virtuals: false, @@ -2200,7 +2203,7 @@ function _isEmpty(v) { * @api public */ -Document.prototype.modifiedPaths = function(options) { +Document.prototype.modifiedPaths = function (options) { options = options || {}; const directModifiedPaths = Object.keys(this.$__.activePaths.getStatePaths('modify')); @@ -2282,7 +2285,7 @@ Document.prototype[documentModifiedPaths] = Document.prototype.modifiedPaths; * @api public */ -Document.prototype.isModified = function(paths, options, modifiedPaths) { +Document.prototype.isModified = function (paths, options, modifiedPaths) { if (paths) { const ignoreAtomics = options && options.ignoreAtomics; const directModifiedPathsObj = this.$__.activePaths.states.modify; @@ -2301,7 +2304,7 @@ Document.prototype.isModified = function(paths, options, modifiedPaths) { } const modified = modifiedPaths || this[documentModifiedPaths](); - const isModifiedChild = paths.some(function(path) { + const isModifiedChild = paths.some(function (path) { return !!~modified.indexOf(path); }); @@ -2315,8 +2318,8 @@ Document.prototype.isModified = function(paths, options, modifiedPaths) { return true; }); } - return isModifiedChild || paths.some(function(path) { - return directModifiedPaths.some(function(mod) { + return isModifiedChild || paths.some(function (path) { + return directModifiedPaths.some(function (mod) { return mod === path || path.startsWith(mod + '.'); }); }); @@ -2354,7 +2357,7 @@ Document.prototype[documentIsModified] = Document.prototype.isModified; * @api public */ -Document.prototype.$isDefault = function(path) { +Document.prototype.$isDefault = function (path) { if (path == null) { return this.$__.activePaths.some('default'); } @@ -2393,7 +2396,7 @@ Document.prototype.$isDefault = function(path) { * @api public */ -Document.prototype.$isDeleted = function(val) { +Document.prototype.$isDeleted = function (val) { if (arguments.length === 0) { return !!this.$__.isDeleted; } @@ -2416,7 +2419,7 @@ Document.prototype.$isDeleted = function(val) { * @api public */ -Document.prototype.isDirectModified = function(path) { +Document.prototype.isDirectModified = function (path) { if (path == null) { return this.$__.activePaths.some('modify'); } @@ -2455,7 +2458,7 @@ Document.prototype.isDirectModified = function(path) { * @api public */ -Document.prototype.isInit = function(path) { +Document.prototype.isInit = function (path) { if (path == null) { return this.$__.activePaths.some('init'); } @@ -2710,7 +2713,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate _evaluateRequiredFunctions(doc); // only validate required fields when necessary - let paths = new Set(Object.keys(doc.$__.activePaths.getStatePaths('require')).filter(function(path) { + let paths = new Set(Object.keys(doc.$__.activePaths.getStatePaths('require')).filter(function (path) { if (!doc.$__isSelected(path) && !doc.$isModified(path)) { return false; } @@ -2777,10 +2780,10 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate throw new Error('Cannot validate subdocument that does not have a parent'); } if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) && - // Avoid using isDirectModified() here because that does additional checks on whether the parent path - // is direct modified, which can cause performance issues re: gh-14897 - !subdocParent.$__.activePaths.getStatePaths('modify').hasOwnProperty(fullPathToSubdoc) && - !subdocParent.$isDefault(fullPathToSubdoc)) { + // Avoid using isDirectModified() here because that does additional checks on whether the parent path + // is direct modified, which can cause performance issues re: gh-14897 + !subdocParent.$__.activePaths.getStatePaths('modify').hasOwnProperty(fullPathToSubdoc) && + !subdocParent.$isDefault(fullPathToSubdoc)) { paths.add(fullPathToSubdoc); if (doc.$__.pathsToScopes == null) { @@ -2893,21 +2896,21 @@ function _addArrayPathsToValidate(doc, paths) { } if (!_pathType.$isMongooseArray || - // To avoid potential performance issues, skip doc arrays whose children - // are not required. `getPositionalPathType()` may be slow, so avoid - // it unless we have a case of #6364 - (!Array.isArray(_pathType) && - _pathType.$isMongooseDocumentArray && - !(_pathType && _pathType.schemaOptions && _pathType.schemaOptions.required))) { + // To avoid potential performance issues, skip doc arrays whose children + // are not required. `getPositionalPathType()` may be slow, so avoid + // it unless we have a case of #6364 + (!Array.isArray(_pathType) && + _pathType.$isMongooseDocumentArray && + !(_pathType && _pathType.schemaOptions && _pathType.schemaOptions.required))) { continue; } // gh-11380: optimization. If the array isn't a document array and there's no validators // on the array type, there's no need to run validation on the individual array elements. if (_pathType.$isMongooseArray && - !_pathType.$isMongooseDocumentArray && // Skip document arrays... - !_pathType.embeddedSchemaType.$isMongooseArray && // and arrays of arrays - _pathType.embeddedSchemaType.validators.length === 0) { + !_pathType.$isMongooseDocumentArray && // Skip document arrays... + !_pathType.embeddedSchemaType.$isMongooseArray && // and arrays of arrays + _pathType.embeddedSchemaType.validators.length === 0) { continue; } @@ -2962,8 +2965,8 @@ Document.prototype.$__validate = async function $__validate(pathsToValidate, opt } const hasValidateModifiedOnlyOption = options && - (typeof options === 'object') && - ('validateModifiedOnly' in options); + (typeof options === 'object') && + ('validateModifiedOnly' in options); const pathsToSkip = (options && options.pathsToSkip) || null; @@ -3014,7 +3017,7 @@ Document.prototype.$__validate = async function $__validate(pathsToValidate, opt for (const key in validationError.errors) { // Make sure cast errors persist if (!this[documentArrayParent] && - validationError.errors[key] instanceof MongooseError.CastError) { + validationError.errors[key] instanceof MongooseError.CastError) { this.invalidate(key, validationError.errors[key]); } } @@ -3132,8 +3135,8 @@ Document.prototype.$__validate = async function $__validate(pathsToValidate, opt await schemaType.doValidate(val, scope, doValidateOptions); } catch (err) { const isSubdoc = schemaType.$isSingleNested || - schemaType.$isArraySubdocument || - schemaType.$isMongooseDocumentArray; + schemaType.$isArraySubdocument || + schemaType.$isMongooseDocumentArray; if (isSubdoc && err instanceof ValidationError) { return; } @@ -3209,7 +3212,7 @@ function _handlePathsToSkip(paths, pathsToSkip) { * @api public */ -Document.prototype.validateSync = function(pathsToValidate, options) { +Document.prototype.validateSync = function (pathsToValidate, options) { const _this = this; if (arguments.length === 1 && typeof arguments[0] === 'object' && !Array.isArray(arguments[0])) { @@ -3218,8 +3221,8 @@ Document.prototype.validateSync = function(pathsToValidate, options) { } const hasValidateModifiedOnlyOption = options && - (typeof options === 'object') && - ('validateModifiedOnly' in options); + (typeof options === 'object') && + ('validateModifiedOnly' in options); let shouldValidateModifiedOnly; if (hasValidateModifiedOnlyOption) { @@ -3360,7 +3363,7 @@ Document.prototype.validateSync = function(pathsToValidate, options) { * @api public */ -Document.prototype.invalidate = function(path, err, val, kind) { +Document.prototype.invalidate = function (path, err, val, kind) { if (!this.$__.validationError) { this.$__.validationError = new ValidationError(this); } @@ -3396,7 +3399,7 @@ Document.prototype.invalidate = function(path, err, val, kind) { * @method $markValid */ -Document.prototype.$markValid = function(path) { +Document.prototype.$markValid = function (path) { if (!this.$__.validationError || !this.$__.validationError.errors[path]) { return; } @@ -3496,7 +3499,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) { * @api private */ -Document.prototype.$isValid = function(path) { +Document.prototype.$isValid = function (path) { if (this.$__.validationError == null || Object.keys(this.$__.validationError.errors).length === 0) { return true; } @@ -3536,7 +3539,7 @@ Document.prototype.$__reset = function reset() { } // clear atomics - this.$__dirty().forEach(function(dirt) { + this.$__dirty().forEach(function (dirt) { const type = dirt.value; if (type && type[arrayAtomicsSymbol]) { @@ -3559,7 +3562,7 @@ Document.prototype.$__reset = function reset() { this.$__.validationError = undefined; this.$errors = undefined; _this = this; - this.$__schema.requiredPaths().forEach(function(path) { + this.$__schema.requiredPaths().forEach(function (path) { _this.$__.activePaths.require(path); }); @@ -3606,9 +3609,9 @@ Document.prototype.$__undoReset = function $__undoReset() { * @instance */ -Document.prototype.$__dirty = function() { +Document.prototype.$__dirty = function () { const _this = this; - let all = this.$__.activePaths.map('modify', function(path) { + let all = this.$__.activePaths.map('modify', function (path) { return { path: path, value: _this.$__getValue(path), @@ -3618,7 +3621,7 @@ Document.prototype.$__dirty = function() { // gh-2558: if we had to set a default and the value is not undefined, // we have to save as well - all = all.concat(this.$__.activePaths.map('default', function(path) { + all = all.concat(this.$__.activePaths.map('default', function (path) { if (path === '_id' || _this.$__getValue(path) == null) { return; } @@ -3633,7 +3636,7 @@ Document.prototype.$__dirty = function() { // Ignore "foo.a" if "foo" is dirty already. const minimal = []; - all.forEach(function(item) { + all.forEach(function (item) { if (!item) { return; } @@ -3650,8 +3653,8 @@ Document.prototype.$__dirty = function() { if (top == null) { minimal.push(item); } else if (top != null && - top[arrayAtomicsSymbol] != null && - top.hasAtomics()) { + top[arrayAtomicsSymbol] != null && + top.hasAtomics()) { // special case for top level MongooseArrays // the `top` array itself and a sub path of `top` are being set. // the only way to honor all of both modifications is through a $set @@ -3673,7 +3676,7 @@ Document.prototype.$__dirty = function() { * @instance */ -Document.prototype.$__setSchema = function(schema) { +Document.prototype.$__setSchema = function (schema) { compile(schema.tree, this, undefined, schema.options); // Apply default getters if virtual doesn't have any (gh-6262) @@ -3699,20 +3702,20 @@ Document.prototype.$__setSchema = function(schema) { * @instance */ -Document.prototype.$__getArrayPathsToValidate = function() { +Document.prototype.$__getArrayPathsToValidate = function () { DocumentArray || (DocumentArray = require('./types/documentArray')); // validate all document arrays. return this.$__.activePaths - .map('init', 'modify', function(i) { + .map('init', 'modify', function (i) { return this.$__getValue(i); }.bind(this)) - .filter(function(val) { + .filter(function (val) { return val && Array.isArray(val) && utils.isMongooseDocumentArray(val) && val.length; - }).reduce(function(seed, array) { + }).reduce(function (seed, array) { return seed.concat(array); }, []) - .filter(function(doc) { + .filter(function (doc) { return doc; }); }; @@ -3729,7 +3732,7 @@ Document.prototype.$__getArrayPathsToValidate = function() { * @instance */ -Document.prototype.$getAllSubdocs = function(options) { +Document.prototype.$getAllSubdocs = function (options) { if (options?.useCache && this.$__.saveOptions?.__subdocs) { return this.$__.saveOptions.__subdocs; } @@ -3821,7 +3824,7 @@ Document.prototype.$__handleReject = function handleReject(err) { * @instance */ -Document.prototype.$toObject = function(options, json) { +Document.prototype.$toObject = function (options, json) { const defaultOptions = this.$__schema._defaultToObjectOptions(json); const hasOnlyPrimitiveValues = this.$__hasOnlyPrimitiveValues(); @@ -4141,7 +4144,7 @@ Document.prototype.$__toObjectShallow = function $__toObjectShallow(schemaFields * @instance */ -Document.prototype.toObject = function(options) { +Document.prototype.toObject = function (options) { return this.$toObject(options); }; @@ -4413,7 +4416,7 @@ function omitDeselectedFields(self, json) { * @instance */ -Document.prototype.toJSON = function(options) { +Document.prototype.toJSON = function (options) { return this.$toObject(options, true); }; @@ -4421,7 +4424,7 @@ Document.prototype.toJSON = function(options) { * ignore */ -Document.prototype.ownerDocument = function() { +Document.prototype.ownerDocument = function () { return this; }; @@ -4437,7 +4440,7 @@ Document.prototype.ownerDocument = function() { * @instance */ -Document.prototype.parent = function() { +Document.prototype.parent = function () { if (this.$isSubdocument || this.$__.wasPopulated) { return this.$__.parent; } @@ -4467,7 +4470,7 @@ Document.prototype.$parent = Document.prototype.parent; * @instance */ -Document.prototype.inspect = function(options) { +Document.prototype.inspect = function (options) { const isPOJO = utils.isPOJO(options); let opts; if (isPOJO) { @@ -4501,7 +4504,7 @@ if (inspect.custom) { * @instance */ -Document.prototype.toString = function() { +Document.prototype.toString = function () { const ret = this.inspect(); if (typeof ret === 'string') { return ret; @@ -4523,7 +4526,7 @@ Document.prototype.toString = function() { * @instance */ -Document.prototype.equals = function(doc) { +Document.prototype.equals = function (doc) { if (!doc) { return false; } @@ -4608,7 +4611,7 @@ Document.prototype.populate = async function populate() { if (this.$__isNested) { topLevelModel = this.$__[scopeSymbol].constructor; const nestedPath = this.$__.nestedPath; - paths.forEach(function(populateOptions) { + paths.forEach(function (populateOptions) { populateOptions.path = nestedPath + '.' + populateOptions.path; }); } @@ -4683,7 +4686,7 @@ Document.prototype.$getPopulatedDocs = function $getPopulatedDocs() { * @api public */ -Document.prototype.populated = function(path, val, options) { +Document.prototype.populated = function (path, val, options) { // val and options are internal if (val == null || val === true) { if (!this.$__.populated) { @@ -4796,7 +4799,7 @@ Document.prototype.$assertPopulated = function $assertPopulated(path, values) { * @instance */ -Document.prototype.depopulate = function(path) { +Document.prototype.depopulate = function (path) { if (typeof path === 'string') { path = path.indexOf(' ') === -1 ? [path] : path.split(' '); } @@ -4884,7 +4887,7 @@ Document.prototype.depopulate = function(path) { * @instance */ -Document.prototype.$__fullPath = function(path) { +Document.prototype.$__fullPath = function (path) { // overridden in SubDocuments return path || ''; }; @@ -4930,7 +4933,7 @@ Document.prototype.$__fullPath = function(path) { * @instance */ -Document.prototype.getChanges = function() { +Document.prototype.getChanges = function () { const delta = this.$__delta(); const changes = delta ? delta[1] : {}; return changes; @@ -5101,10 +5104,10 @@ function checkDivergentArray(doc, path, array) { // would be similarly destructive as we never received all // elements of the array and potentially would overwrite data. const check = pop.options.match || - pop.options.options && utils.object.hasOwnProperty(pop.options.options, 'limit') || // 0 is not permitted - pop.options.options && pop.options.options.skip || // 0 is permitted - pop.options.select && // deselected _id? - (pop.options.select._id === 0 || + pop.options.options && utils.object.hasOwnProperty(pop.options.options, 'limit') || // 0 is not permitted + pop.options.options && pop.options.options.skip || // 0 is permitted + pop.options.select && // deselected _id? + (pop.options.select._id === 0 || /\s?-_id\s?/.test(pop.options.select)); if (check) { @@ -5202,7 +5205,7 @@ function handleAtomics(self, where, delta, data, value) { } if (typeof value.$__getAtomics === 'function') { - value.$__getAtomics().forEach(function(atomic) { + value.$__getAtomics().forEach(function (atomic) { const op = atomic[0]; const val = atomic[1]; operand(self, where, delta, data, val, op); @@ -5284,7 +5287,7 @@ function shouldSkipVersioning(self, path) { * @instance */ -Document.prototype.$clone = function() { +Document.prototype.$clone = function () { const Model = this.constructor; const clonedDoc = new Model(); clonedDoc.$isNew = this.$isNew; diff --git a/test/schema.test.js b/test/schema.test.js index 0711b419e4..75816b1d73 100644 --- a/test/schema.test.js +++ b/test/schema.test.js @@ -1645,12 +1645,11 @@ describe('schema', function() { const Test = mongoose.model('gh3935', testSchema); const test = new Test({ test: true }); - assert.ok(test.validateSync()); - assert.equal(test.validateSync().errors.test.name, 'CastError'); + const validationResult = test.validateSync(); + assert.ok(validationResult); + assert.equal(validationResult.errors.test.name, 'CastError'); - }); - it('trim: false works with strings (gh-4042)', function() { const testSchema = new Schema({ test: { type: String, trim: false }