deno.land / x / mongoose@6.7.5 / lib / helpers / updateValidators.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250'use strict';
/*! * Module dependencies. */
const ValidationError = require('../error/validation');const cleanPositionalOperators = require('./schema/cleanPositionalOperators');const flatten = require('./common').flatten;const modifiedPaths = require('./common').modifiedPaths;
/** * Applies validators and defaults to update and findOneAndUpdate operations, * specifically passing a null doc as `this` to validators and defaults * * @param {Query} query * @param {Schema} schema * @param {Object} castedDoc * @param {Object} options * @method runValidatorsOnUpdate * @api private */
module.exports = function(query, schema, castedDoc, options, callback) { const keys = Object.keys(castedDoc || {}); let updatedKeys = {}; let updatedValues = {}; const isPull = {}; const arrayAtomicUpdates = {}; const numKeys = keys.length; let hasDollarUpdate = false; const modified = {}; let currentUpdate; let key; let i;
for (i = 0; i < numKeys; ++i) { if (keys[i].startsWith('$')) { hasDollarUpdate = true; if (keys[i] === '$push' || keys[i] === '$addToSet') { const _keys = Object.keys(castedDoc[keys[i]]); for (let ii = 0; ii < _keys.length; ++ii) { currentUpdate = castedDoc[keys[i]][_keys[ii]]; if (currentUpdate && currentUpdate.$each) { arrayAtomicUpdates[_keys[ii]] = (arrayAtomicUpdates[_keys[ii]] || []). concat(currentUpdate.$each); } else { arrayAtomicUpdates[_keys[ii]] = (arrayAtomicUpdates[_keys[ii]] || []). concat([currentUpdate]); } } continue; } modifiedPaths(castedDoc[keys[i]], '', modified); const flat = flatten(castedDoc[keys[i]], null, null, schema); const paths = Object.keys(flat); const numPaths = paths.length; for (let j = 0; j < numPaths; ++j) { const updatedPath = cleanPositionalOperators(paths[j]); key = keys[i]; // With `$pull` we might flatten `$in`. Skip stuff nested under `$in` // for the rest of the logic, it will get handled later. if (updatedPath.includes('$')) { continue; } if (key === '$set' || key === '$setOnInsert' || key === '$pull' || key === '$pullAll') { updatedValues[updatedPath] = flat[paths[j]]; isPull[updatedPath] = key === '$pull' || key === '$pullAll'; } else if (key === '$unset') { updatedValues[updatedPath] = undefined; } updatedKeys[updatedPath] = true; } } }
if (!hasDollarUpdate) { modifiedPaths(castedDoc, '', modified); updatedValues = flatten(castedDoc, null, null, schema); updatedKeys = Object.keys(updatedValues); }
const updates = Object.keys(updatedValues); const numUpdates = updates.length; const validatorsToExecute = []; const validationErrors = [];
const alreadyValidated = [];
const context = query; function iter(i, v) { const schemaPath = schema._getSchema(updates[i]); if (schemaPath == null) { return; } if (schemaPath.instance === 'Mixed' && schemaPath.path !== updates[i]) { return; }
if (v && Array.isArray(v.$in)) { v.$in.forEach((v, i) => { validatorsToExecute.push(function(callback) { schemaPath.doValidate( v, function(err) { if (err) { err.path = updates[i] + '.$in.' + i; validationErrors.push(err); } callback(null); }, context, { updateValidator: true }); }); }); } else { if (isPull[updates[i]] && schemaPath.$isMongooseArray) { return; }
if (schemaPath.$isMongooseDocumentArrayElement && v != null && v.$__ != null) { alreadyValidated.push(updates[i]); validatorsToExecute.push(function(callback) { schemaPath.doValidate(v, function(err) { if (err) { if (err.errors) { for (const key of Object.keys(err.errors)) { const _err = err.errors[key]; _err.path = updates[i] + '.' + key; validationErrors.push(_err); } } else { err.path = updates[i]; validationErrors.push(err); } }
return callback(null); }, context, { updateValidator: true }); }); } else { validatorsToExecute.push(function(callback) { for (const path of alreadyValidated) { if (updates[i].startsWith(path + '.')) { return callback(null); } }
schemaPath.doValidate(v, function(err) { if (schemaPath.schema != null && schemaPath.schema.options.storeSubdocValidationError === false && err instanceof ValidationError) { return callback(null); }
if (err) { err.path = updates[i]; validationErrors.push(err); } callback(null); }, context, { updateValidator: true }); }); } } } for (i = 0; i < numUpdates; ++i) { iter(i, updatedValues[updates[i]]); }
const arrayUpdates = Object.keys(arrayAtomicUpdates); for (const arrayUpdate of arrayUpdates) { let schemaPath = schema._getSchema(arrayUpdate); if (schemaPath && schemaPath.$isMongooseDocumentArray) { validatorsToExecute.push(function(callback) { schemaPath.doValidate( arrayAtomicUpdates[arrayUpdate], getValidationCallback(arrayUpdate, validationErrors, callback), options && options.context === 'query' ? query : null); }); } else { schemaPath = schema._getSchema(arrayUpdate + '.0'); for (const atomicUpdate of arrayAtomicUpdates[arrayUpdate]) { validatorsToExecute.push(function(callback) { schemaPath.doValidate( atomicUpdate, getValidationCallback(arrayUpdate, validationErrors, callback), options && options.context === 'query' ? query : null, { updateValidator: true }); }); } } }
if (callback != null) { let numValidators = validatorsToExecute.length; if (numValidators === 0) { return _done(callback); } for (const validator of validatorsToExecute) { validator(function() { if (--numValidators <= 0) { _done(callback); } }); }
return; }
return function(callback) { let numValidators = validatorsToExecute.length; if (numValidators === 0) { return _done(callback); } for (const validator of validatorsToExecute) { validator(function() { if (--numValidators <= 0) { _done(callback); } }); } };
function _done(callback) { if (validationErrors.length) { const err = new ValidationError(null);
for (const validationError of validationErrors) { err.addError(validationError.path, validationError); }
return callback(err); } callback(null); }
function getValidationCallback(arrayUpdate, validationErrors, callback) { return function(err) { if (err) { err.path = arrayUpdate; validationErrors.push(err); } callback(null); }; }};
Version Info