"use strict"; var __defProp = Object.defineProperty; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; const _ = require("lodash"); const Utils = require("./utils"); const sequelizeError = require("./errors"); const DataTypes = require("./data-types"); const BelongsTo = require("./associations/belongs-to"); const validator = require("./utils/validator-extras").validator; const { promisify } = require("util"); class InstanceValidator { constructor(modelInstance, options) { options = __spreadValues({ hooks: true }, options); if (options.fields && !options.skip) { options.skip = _.difference(Object.keys(modelInstance.constructor.rawAttributes), options.fields); } else { options.skip = options.skip || []; } this.options = options; this.modelInstance = modelInstance; this.validator = validator; this.errors = []; this.inProgress = false; } async _validate() { if (this.inProgress) throw new Error("Validations already in progress."); this.inProgress = true; await Promise.all([ this._perAttributeValidators(), this._customValidators() ]); if (this.errors.length) { throw new sequelizeError.ValidationError(null, this.errors); } } async validate() { return await (this.options.hooks ? this._validateAndRunHooks() : this._validate()); } async _validateAndRunHooks() { const runHooks = this.modelInstance.constructor.runHooks.bind(this.modelInstance.constructor); await runHooks("beforeValidate", this.modelInstance, this.options); try { await this._validate(); } catch (error) { const newError = await runHooks("validationFailed", this.modelInstance, this.options, error); throw newError || error; } await runHooks("afterValidate", this.modelInstance, this.options); return this.modelInstance; } async _perAttributeValidators() { const validators = []; _.forIn(this.modelInstance.rawAttributes, (rawAttribute, field) => { if (this.options.skip.includes(field)) { return; } const value = this.modelInstance.dataValues[field]; if (value instanceof Utils.SequelizeMethod) { return; } if (!rawAttribute._autoGenerated && !rawAttribute.autoIncrement) { this._validateSchema(rawAttribute, field, value); } if (Object.prototype.hasOwnProperty.call(this.modelInstance.validators, field)) { validators.push(this._singleAttrValidate(value, field, rawAttribute.allowNull)); } }); return await Promise.all(validators); } async _customValidators() { const validators = []; _.each(this.modelInstance.constructor.options.validate, (validator2, validatorType) => { if (this.options.skip.includes(validatorType)) { return; } const valprom = this._invokeCustomValidator(validator2, validatorType).catch(() => { }); validators.push(valprom); }); return await Promise.all(validators); } async _singleAttrValidate(value, field, allowNull) { if ((value === null || value === void 0) && !allowNull) { return; } const validators = []; _.forIn(this.modelInstance.validators[field], (test, validatorType) => { if (["isUrl", "isURL", "isEmail"].includes(validatorType)) { if (typeof test === "object" && test !== null && test.msg) { test = { msg: test.msg }; } else if (test === true) { test = {}; } } if (typeof test === "function") { validators.push(this._invokeCustomValidator(test, validatorType, true, value, field)); return; } if (value === null || value === void 0) { return; } const validatorPromise = this._invokeBuiltinValidator(value, test, validatorType, field); validatorPromise.catch(() => { }); validators.push(validatorPromise); }); return Promise.all(validators.map((validator2) => validator2.catch((rejection) => { const isBuiltIn = !!rejection.validatorName; this._pushError(isBuiltIn, field, rejection, value, rejection.validatorName, rejection.validatorArgs); }))); } async _invokeCustomValidator(validator2, validatorType, optAttrDefined, optValue, optField) { let isAsync = false; const validatorArity = validator2.length; let asyncArity = 1; let errorKey = validatorType; let invokeArgs; if (optAttrDefined) { asyncArity = 2; invokeArgs = optValue; errorKey = optField; } if (validatorArity === asyncArity) { isAsync = true; } if (isAsync) { try { if (optAttrDefined) { return await promisify(validator2.bind(this.modelInstance, invokeArgs))(); } return await promisify(validator2.bind(this.modelInstance))(); } catch (e) { return this._pushError(false, errorKey, e, optValue, validatorType); } } try { return await validator2.call(this.modelInstance, invokeArgs); } catch (e) { return this._pushError(false, errorKey, e, optValue, validatorType); } } async _invokeBuiltinValidator(value, test, validatorType, field) { const valueString = String(value); if (typeof validator[validatorType] !== "function") { throw new Error(`Invalid validator function: ${validatorType}`); } const validatorArgs = this._extractValidatorArgs(test, validatorType, field); if (!validator[validatorType](valueString, ...validatorArgs)) { throw Object.assign(new Error(test.msg || `Validation ${validatorType} on ${field} failed`), { validatorName: validatorType, validatorArgs }); } } _extractValidatorArgs(test, validatorType, field) { let validatorArgs = test.args || test; const isLocalizedValidator = typeof validatorArgs !== "string" && ["isAlpha", "isAlphanumeric", "isMobilePhone"].includes(validatorType); if (!Array.isArray(validatorArgs)) { if (validatorType === "isImmutable") { validatorArgs = [validatorArgs, field, this.modelInstance]; } else if (isLocalizedValidator || validatorType === "isIP") { validatorArgs = []; } else { validatorArgs = [validatorArgs]; } } else { validatorArgs = validatorArgs.slice(0); } return validatorArgs; } _validateSchema(rawAttribute, field, value) { if (rawAttribute.allowNull === false && (value === null || value === void 0)) { const association = Object.values(this.modelInstance.constructor.associations).find((association2) => association2 instanceof BelongsTo && association2.foreignKey === rawAttribute.fieldName); if (!association || !this.modelInstance.get(association.associationAccessor)) { const validators = this.modelInstance.validators[field]; const errMsg = _.get(validators, "notNull.msg", `${this.modelInstance.constructor.name}.${field} cannot be null`); this.errors.push(new sequelizeError.ValidationErrorItem(errMsg, "notNull Violation", field, value, this.modelInstance, "is_null")); } } if (rawAttribute.type instanceof DataTypes.STRING || rawAttribute.type instanceof DataTypes.TEXT || rawAttribute.type instanceof DataTypes.CITEXT) { if (Array.isArray(value) || _.isObject(value) && !(value instanceof Utils.SequelizeMethod) && !Buffer.isBuffer(value)) { this.errors.push(new sequelizeError.ValidationErrorItem(`${field} cannot be an array or an object`, "string violation", field, value, this.modelInstance, "not_a_string")); } } } _pushError(isBuiltin, errorKey, rawError, value, fnName, fnArgs) { const message = rawError.message || rawError || "Validation error"; const error = new sequelizeError.ValidationErrorItem(message, "Validation error", errorKey, value, this.modelInstance, fnName, isBuiltin ? fnName : void 0, isBuiltin ? fnArgs : void 0); error[InstanceValidator.RAW_KEY_NAME] = rawError; this.errors.push(error); } } InstanceValidator.RAW_KEY_NAME = "original"; module.exports = InstanceValidator; module.exports.InstanceValidator = InstanceValidator; module.exports.default = InstanceValidator; //# sourceMappingURL=instance-validator.js.map