mongoose
Version:
Mongoose MongoDB ODM
202 lines (174 loc) • 5.87 kB
JavaScript
'use strict';
const isNestedProjection = require('../projection/isNestedProjection');
module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip, options) {
const schemaPaths = doc.$__schema.paths;
const skipParentChangeTracking = options?.skipParentChangeTracking;
const skipId = doc.$__.skipId;
// Whether any path has a function default that must run **after** setters,
// so callers doing a before-setters pass can skip the after-setters pass
// entirely when this comes back `false`.
let hasPostSetterDefaults = false;
for (const p in schemaPaths) {
let def;
let curPath = '';
if (p === '_id' && skipId) {
continue;
}
const type = schemaPaths[p];
// `getDefault()` returns undefined when `defaultValue` is undefined, in which
// case this loop never modifies the doc, so skip traversing the path entirely.
if (type.defaultValue === undefined) {
continue;
}
if (typeof type.defaultValue === 'function' && !type.defaultValue.$runBeforeSetters) {
hasPostSetterDefaults = true;
}
const path = type.splitPath();
const len = path.length;
if (path[len - 1] === '$*') {
continue;
}
let included = false;
let doc_ = doc._doc;
if (len === 1) {
if (exclude === true) {
if (p in fields) {
continue;
}
} else if (exclude === false && fields) {
const hasSubpaths = type.$isSingleNested || type.$isMongooseDocumentArray;
if ((p in fields && !isNestedProjection(fields[p])) || (hasSubpaths && hasIncludedChildren != null && hasIncludedChildren[p])) {
included = true;
} else if (hasIncludedChildren != null && !hasIncludedChildren[p]) {
continue;
}
}
if (doc_[p] !== void 0) {
continue;
}
if (isBeforeSetters != null) {
if (typeof type.defaultValue === 'function') {
if (!type.defaultValue.$runBeforeSetters && isBeforeSetters) {
continue;
}
if (type.defaultValue.$runBeforeSetters && !isBeforeSetters) {
continue;
}
} else if (!isBeforeSetters) {
// Non-function defaults should always run **before** setters
continue;
}
}
if (pathsToSkip && pathsToSkip[p]) {
continue;
}
if (fields && exclude !== null && !(exclude === true || included)) {
continue;
}
try {
def = type.getDefault(doc, false);
} catch (err) {
doc.invalidate(p, err);
continue;
}
if (typeof def !== 'undefined') {
doc_[p] = def;
applyChangeTracking(doc, p, skipParentChangeTracking);
}
continue;
}
for (let j = 0; j < len; ++j) {
if (doc_ == null) {
break;
}
const piece = path[j];
curPath = curPath.length ? curPath + '.' + piece : 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 && !isNestedProjection(fields[curPath])) || (j === len - 1 && 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 (isBeforeSetters != null) {
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;
applyChangeTracking(doc, p, skipParentChangeTracking);
}
} 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;
applyChangeTracking(doc, p, skipParentChangeTracking);
}
}
} else {
try {
def = type.getDefault(doc, false);
} catch (err) {
doc.invalidate(p, err);
break;
}
if (typeof def !== 'undefined') {
doc_[piece] = def;
applyChangeTracking(doc, p, skipParentChangeTracking);
}
}
} else {
doc_ = doc_[piece];
}
}
}
return hasPostSetterDefaults;
};
/*!
* ignore
*/
function applyChangeTracking(doc, fullPath, skipParentChangeTracking) {
doc.$__.activePaths.default(fullPath);
if (!skipParentChangeTracking && doc.$isSubdocument && doc.$isSingleNested && doc.$parent() != null) {
doc.$parent().$__.activePaths.default(doc.$__pathRelativeToParent(fullPath));
}
}