Skip to content

Commit

Permalink
Merge branch '6.5' into vkarpov15/gh-11915
Browse files Browse the repository at this point in the history
  • Loading branch information
Uzlopak committed Jul 18, 2022
2 parents 00cf1c7 + 491521e commit 7280d25
Show file tree
Hide file tree
Showing 25 changed files with 764 additions and 427 deletions.
3 changes: 3 additions & 0 deletions lib/connection.js
Expand Up @@ -491,6 +491,9 @@ Connection.prototype.transaction = function transaction(fn, options) {
doc.set(doc.schema.options.versionKey, state.versionKey);
}

if (state.modifiedPaths.length > 0 && doc.$__.activePaths.states.modify == null) {
doc.$__.activePaths.states.modify = {};
}
for (const path of state.modifiedPaths) {
doc.$__.activePaths.paths[path] = 'modify';
doc.$__.activePaths.states.modify[path] = true;
Expand Down
198 changes: 50 additions & 148 deletions lib/document.js
Expand Up @@ -19,6 +19,7 @@ const VirtualType = require('./virtualtype');
const $__hasIncludedChildren = require('./helpers/projection/hasIncludedChildren');
const promiseOrCallback = require('./helpers/promiseOrCallback');
const castNumber = require('./cast/number');
const applyDefaults = require('./helpers/document/applyDefaults');
const cleanModifiedSubpaths = require('./helpers/document/cleanModifiedSubpaths');
const compile = require('./helpers/document/compile').compile;
const defineKey = require('./helpers/document/compile').defineKey;
Expand Down Expand Up @@ -94,7 +95,11 @@ function Document(obj, fields, skipId, options) {
}

this.$__ = new InternalCache();
this.$isNew = 'isNew' in options ? options.isNew : true;

// Avoid setting `isNew` to `true`, because it is `true` by default
if (options.isNew != null && options.isNew !== true) {
this.$isNew = options.isNew;
}

if (options.priorDoc != null) {
this.$__.priorDoc = options.priorDoc;
Expand All @@ -117,13 +122,12 @@ function Document(obj, fields, skipId, options) {
const schema = this.$__schema;

if (typeof fields === 'boolean' || fields === 'throw') {
this.$__.strictMode = fields;
if (fields !== true) {
this.$__.strictMode = fields;
}
fields = undefined;
} else {
} else if (schema.options.strict !== true) {
this.$__.strictMode = schema.options.strict;
if (fields != null) {
this.$__.selected = fields;
}
}

const requiredPaths = schema.requiredPaths(true);
Expand All @@ -135,9 +139,9 @@ function Document(obj, fields, skipId, options) {

// determine if this doc is a result of a query with
// excluded fields
if (utils.isPOJO(fields)) {
if (utils.isPOJO(fields) && Object.keys(fields).length > 0) {
exclude = isExclusive(fields);
this.$__.fields = fields;
this.$__.selected = fields;
this.$__.exclude = exclude;
}

Expand All @@ -151,7 +155,7 @@ function Document(obj, fields, skipId, options) {
// By default, defaults get applied **before** setting initial values
// Re: gh-6155
if (defaults) {
$__applyDefaults(this, fields, exclude, hasIncludedChildren, true, null);
applyDefaults(this, fields, exclude, hasIncludedChildren, true, null);
}
}
if (obj) {
Expand All @@ -175,7 +179,7 @@ function Document(obj, fields, skipId, options) {
this.$__.skipDefaults = options.skipDefaults;
}
} else if (defaults) {
$__applyDefaults(this, fields, exclude, hasIncludedChildren, false, options.skipDefaults);
applyDefaults(this, fields, exclude, hasIncludedChildren, false, options.skipDefaults);
}

if (!this.$__.strictMode && obj) {
Expand Down Expand Up @@ -211,6 +215,13 @@ Object.defineProperty(Document.prototype, 'errors', {
this.$errors = value;
}
});

/*!
* ignore
*/

Document.prototype.$isNew = true;

/*!
* Document exposes the NodeJS event emitter API, so you can use
* `on`, `once`, etc.
Expand Down Expand Up @@ -442,122 +453,6 @@ Object.defineProperty(Document.prototype, '$op', {
}
});

/*!
* ignore
*/

function $__applyDefaults(doc, fields, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip) {
const paths = Object.keys(doc.$__schema.paths);
const plen = paths.length;

for (let i = 0; i < plen; ++i) {
let def;
let curPath = '';
const p = paths[i];

if (p === '_id' && doc.$__.skipId) {
continue;
}

const type = doc.$__schema.paths[p];
const path = type.splitPath();
const len = path.length;
let included = false;
let doc_ = doc._doc;
for (let j = 0; j < len; ++j) {
if (doc_ == null) {
break;
}

const piece = path[j];
curPath += (!curPath.length ? '' : '.') + piece;

if (exclude === true) {
if (curPath in fields) {
break;
}
} else if (exclude === false && fields && !included) {
const hasSubpaths = type.$isSingleNested || type.$isMongooseDocumentArray;
if (curPath in fields || (hasSubpaths && hasIncludedChildren != null && hasIncludedChildren[curPath])) {
included = true;
} else if (hasIncludedChildren != null && !hasIncludedChildren[curPath]) {
break;
}
}

if (j === len - 1) {
if (doc_[piece] !== void 0) {
break;
}

if (typeof type.defaultValue === 'function') {
if (!type.defaultValue.$runBeforeSetters && isBeforeSetters) {
break;
}
if (type.defaultValue.$runBeforeSetters && !isBeforeSetters) {
break;
}
} else if (!isBeforeSetters) {
// Non-function defaults should always run **before** setters
continue;
}

if (pathsToSkip && pathsToSkip[curPath]) {
break;
}

if (fields && exclude !== null) {
if (exclude === true) {
// apply defaults to all non-excluded fields
if (p in fields) {
continue;
}

try {
def = type.getDefault(doc, false);
} catch (err) {
doc.invalidate(p, err);
break;
}

if (typeof def !== 'undefined') {
doc_[piece] = def;
doc.$__.activePaths.default(p);
}
} else if (included) {
// selected field
try {
def = type.getDefault(doc, false);
} catch (err) {
doc.invalidate(p, err);
break;
}

if (typeof def !== 'undefined') {
doc_[piece] = def;
doc.$__.activePaths.default(p);
}
}
} else {
try {
def = type.getDefault(doc, false);
} catch (err) {
doc.invalidate(p, err);
break;
}

if (typeof def !== 'undefined') {
doc_[piece] = def;
doc.$__.activePaths.default(p);
}
}
} else {
doc_ = doc_[piece];
}
}
}
}

/*!
* ignore
*/
Expand Down Expand Up @@ -774,10 +669,11 @@ Document.prototype.$__init = function(doc, opts) {
this.$emit('init', this);
this.constructor.emit('init', this);

const hasIncludedChildren = this.$__.exclude === false && this.$__.fields ?
$__hasIncludedChildren(this.$__.fields) :
const hasIncludedChildren = this.$__.exclude === false && this.$__.selected ?
$__hasIncludedChildren(this.$__.selected) :
null;
$__applyDefaults(this, this.$__.fields, this.$__.exclude, hasIncludedChildren, false, this.$__.skipDefaults);

applyDefaults(this, this.$__.selected, this.$__.exclude, hasIncludedChildren, false, this.$__.skipDefaults);

return this;
};
Expand Down Expand Up @@ -845,7 +741,13 @@ function init(self, obj, doc, opts, prefix) {

if (schemaType && !wasPopulated) {
try {
doc[i] = schemaType.cast(obj[i], self, true);
if (opts && opts.setters) {
// Call applySetters with `init = false` because otherwise setters are a noop
const overrideInit = false;
doc[i] = schemaType.applySetters(obj[i], self, overrideInit);
} else {
doc[i] = schemaType.cast(obj[i], self, true);
}
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
Expand Down Expand Up @@ -1621,7 +1523,7 @@ Document.prototype.$__shouldModify = function(pathToMark, path, options, constru
return true;
}

if (val === void 0 && path in this.$__.activePaths.states.default) {
if (val === void 0 && path in this.$__.activePaths.getStatePaths('default')) {
// we're just unsetting the default value which was never saved
return false;
}
Expand All @@ -1641,7 +1543,7 @@ Document.prototype.$__shouldModify = function(pathToMark, path, options, constru
if (!constructing &&
val !== null &&
val !== undefined &&
path in this.$__.activePaths.states.default &&
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
Expand Down Expand Up @@ -2007,7 +1909,7 @@ Document.prototype.$ignore = function(path) {
*/

Document.prototype.directModifiedPaths = function() {
return Object.keys(this.$__.activePaths.states.modify);
return Object.keys(this.$__.activePaths.getStatePaths('modify'));
};

/**
Expand Down Expand Up @@ -2085,7 +1987,7 @@ function _isEmpty(v) {
Document.prototype.modifiedPaths = function(options) {
options = options || {};

const directModifiedPaths = Object.keys(this.$__.activePaths.states.modify);
const directModifiedPaths = Object.keys(this.$__.activePaths.getStatePaths('modify'));
const result = new Set();

let i = 0;
Expand Down Expand Up @@ -2164,7 +2066,7 @@ Document.prototype[documentModifiedPaths] = Document.prototype.modifiedPaths;

Document.prototype.isModified = function(paths, modifiedPaths) {
if (paths) {
const directModifiedPaths = Object.keys(this.$__.activePaths.states.modify);
const directModifiedPaths = Object.keys(this.$__.activePaths.getStatePaths('modify'));
if (directModifiedPaths.length === 0) {
return false;
}
Expand Down Expand Up @@ -2214,15 +2116,15 @@ Document.prototype.$isDefault = function(path) {
}

if (typeof path === 'string' && path.indexOf(' ') === -1) {
return this.$__.activePaths.states.default.hasOwnProperty(path);
return this.$__.activePaths.getStatePaths('default').hasOwnProperty(path);
}

let paths = path;
if (!Array.isArray(paths)) {
paths = paths.split(' ');
}

return paths.some(path => this.$__.activePaths.states.default.hasOwnProperty(path));
return paths.some(path => this.$__.activePaths.getStatePaths('default').hasOwnProperty(path));
};

/**
Expand Down Expand Up @@ -2275,15 +2177,15 @@ Document.prototype.isDirectModified = function(path) {
}

if (typeof path === 'string' && path.indexOf(' ') === -1) {
return this.$__.activePaths.states.modify.hasOwnProperty(path);
return this.$__.activePaths.getStatePaths('modify').hasOwnProperty(path);
}

let paths = path;
if (!Array.isArray(paths)) {
paths = paths.split(' ');
}

return paths.some(path => this.$__.activePaths.states.modify.hasOwnProperty(path));
return paths.some(path => this.$__.activePaths.getStatePaths('modify').hasOwnProperty(path));
};

/**
Expand All @@ -2300,15 +2202,15 @@ Document.prototype.isInit = function(path) {
}

if (typeof path === 'string' && path.indexOf(' ') === -1) {
return this.$__.activePaths.states.init.hasOwnProperty(path);
return this.$__.activePaths.getStatePaths('init').hasOwnProperty(path);
}

let paths = path;
if (!Array.isArray(paths)) {
paths = paths.split(' ');
}

return paths.some(path => this.$__.activePaths.states.init.hasOwnProperty(path));
return paths.some(path => this.$__.activePaths.getStatePaths('init').hasOwnProperty(path));
};

/**
Expand Down Expand Up @@ -2536,7 +2438,7 @@ Document.prototype.$validate = Document.prototype.validate;
*/

function _evaluateRequiredFunctions(doc) {
const requiredFields = Object.keys(doc.$__.activePaths.states.require);
const requiredFields = Object.keys(doc.$__.activePaths.getStatePaths('require'));
let i = 0;
const len = requiredFields.length;
for (i = 0; i < len; ++i) {
Expand Down Expand Up @@ -2564,7 +2466,7 @@ function _getPathsToValidate(doc) {

_evaluateRequiredFunctions(doc);
// only validate required fields when necessary
let paths = new Set(Object.keys(doc.$__.activePaths.states.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;
}
Expand All @@ -2574,9 +2476,9 @@ function _getPathsToValidate(doc) {
return true;
}));

Object.keys(doc.$__.activePaths.states.init).forEach(addToPaths);
Object.keys(doc.$__.activePaths.states.modify).forEach(addToPaths);
Object.keys(doc.$__.activePaths.states.default).forEach(addToPaths);
Object.keys(doc.$__.activePaths.getStatePaths('init')).forEach(addToPaths);
Object.keys(doc.$__.activePaths.getStatePaths('modify')).forEach(addToPaths);
Object.keys(doc.$__.activePaths.getStatePaths('default')).forEach(addToPaths);
function addToPaths(p) { paths.add(p); }

const subdocs = doc.$getAllSubdocs();
Expand Down Expand Up @@ -3298,8 +3200,8 @@ Document.prototype.$__reset = function reset() {

this.$__.backup = {};
this.$__.backup.activePaths = {
modify: Object.assign({}, this.$__.activePaths.states.modify),
default: Object.assign({}, this.$__.activePaths.states.default)
modify: Object.assign({}, this.$__.activePaths.getStatePaths('modify')),
default: Object.assign({}, this.$__.activePaths.getStatePaths('default'))
};
this.$__.backup.validationError = this.$__.validationError;
this.$__.backup.errors = this.$errors;
Expand Down

0 comments on commit 7280d25

Please sign in to comment.