swaf/dist/db/Validator.js

261 lines
31 KiB
JavaScript
Raw Normal View History

2020-04-22 15:52:17 +02:00
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
export default class Validator {
constructor() {
this.steps = [];
this.validationAttributes = [];
}
/**
* @param thingName The name of the thing to validate.
* @param value The value to verify.
* @param onlyFormat {@code true} to only validate format properties, {@code false} otherwise.
* @param connection A connection to use in case of wrapped transactions.
*/
execute(thingName, value, onlyFormat, connection) {
return __awaiter(this, void 0, void 0, function* () {
const bag = new ValidationBag();
for (const step of this.steps) {
if (onlyFormat && !step.isFormat)
continue;
const result = step.verifyStep(value, thingName, connection);
if ((result === false || result instanceof Promise && (yield result) === false) && step.throw) {
const error = step.throw();
error.thingName = thingName;
error.value = value;
bag.addMessage(error);
}
else if (step.interrupt !== undefined && step.interrupt(value)) {
break;
}
}
if (bag.hasMessages()) {
throw bag;
}
});
}
defined() {
this.validationAttributes.push('required');
this.addStep({
verifyStep: val => val !== undefined,
throw: () => new UndefinedValueValidationError(),
isFormat: true,
});
return this;
}
acceptUndefined() {
this.addStep({
verifyStep: () => true,
throw: null,
interrupt: val => val === undefined || val === null,
isFormat: true,
});
return this;
}
equals(other) {
this.addStep({
verifyStep: val => val === other,
throw: () => new BadValueValidationError(other),
isFormat: true,
});
return this;
}
regexp(regexp) {
this.validationAttributes.push(`pattern="${regexp}"`);
this.addStep({
verifyStep: val => regexp.test(val),
throw: () => new InvalidFormatValidationError(),
isFormat: true,
});
return this;
}
length(length) {
this.addStep({
verifyStep: val => val.length === length,
throw: () => new BadLengthValidationError(length),
isFormat: true,
});
return this;
}
/**
* @param minLength included
* @param maxLength included
*/
between(minLength, maxLength) {
this.addStep({
verifyStep: val => {
const length = val.length;
return length >= minLength && length <= maxLength;
},
throw: () => new BadLengthValidationError(minLength, maxLength),
isFormat: true,
});
return this;
}
/**
* @param min included
*/
min(min) {
this.validationAttributes.push(`min="${min}"`);
this._min = min;
this.addStep({
verifyStep: val => {
return val >= min;
},
throw: () => new OutOfRangeValidationError(this._min, this._max),
isFormat: true,
});
return this;
}
/**
* @param max included
*/
max(max) {
this.validationAttributes.push(`max="${max}"`);
this._max = max;
this.addStep({
verifyStep: val => {
return val <= max;
},
throw: () => new OutOfRangeValidationError(this._min, this._max),
isFormat: true,
});
return this;
}
unique(model, querySupplier) {
this.addStep({
verifyStep: (val, thingName, c) => __awaiter(this, void 0, void 0, function* () {
let query;
if (querySupplier) {
query = querySupplier().where(thingName, val);
}
else {
query = model.constructor.select('1').where(thingName, val);
}
if (typeof model.id === 'number')
query = query.whereNot('id', model.id);
return (yield query.execute(c)).results.length === 0;
}),
throw: () => new AlreadyExistsValidationError(model.table),
isFormat: false,
});
return this;
}
exists(modelClass, foreignKey) {
this.addStep({
verifyStep: (val, thingName, c) => __awaiter(this, void 0, void 0, function* () { return (yield modelClass.select('1').where(foreignKey !== undefined ? foreignKey : thingName, val).execute(c)).results.length >= 1; }),
throw: () => new UnknownRelationValidationError(modelClass.table, foreignKey),
isFormat: false,
});
return this;
}
addStep(step) {
this.steps.push(step);
}
getValidationAttributes() {
return this.validationAttributes;
}
step(step) {
this.validationAttributes.push(`step="${step}"`);
return this;
}
}
export class ValidationBag extends Error {
constructor() {
super(...arguments);
this.messages = {};
}
addMessage(err) {
if (!err.thingName) {
throw new Error('Null thing name');
}
this.messages[err.thingName] = {
name: err.name,
message: err.message,
value: err.value,
};
}
hasMessages() {
return Object.keys(this.messages).length > 0;
}
getMessages() {
return this.messages;
}
}
export class ValidationError extends Error {
get name() {
return this.constructor.name;
}
}
export class BadLengthValidationError extends ValidationError {
constructor(expectedLength, maxLength) {
super();
this.expectedLength = expectedLength;
this.maxLength = maxLength;
}
get message() {
return `${this.thingName} expected length: ${this.expectedLength}${this.maxLength !== undefined ? ` to ${this.maxLength}` : ''}; ` +
`actual length: ${this.value.length}.`;
}
}
export class BadValueValidationError extends ValidationError {
constructor(expectedValue) {
super();
this.expectedValue = expectedValue;
}
get message() {
return `Expected: ${this.expectedValue}; got: ${this.value}.`;
}
}
export class OutOfRangeValidationError extends ValidationError {
constructor(min, max) {
super();
this.min = min;
this.max = max;
}
get message() {
if (this.min === undefined) {
return `${this.thingName} must be at most ${this.max}`;
}
else if (this.max === undefined) {
return `${this.thingName} must be at least ${this.min}`;
}
return `${this.thingName} must be between ${this.min} and ${this.max}.`;
}
}
export class InvalidFormatValidationError extends ValidationError {
get message() {
return `"${this.value}" is not a valid ${this.thingName}.`;
}
}
export class UndefinedValueValidationError extends ValidationError {
get message() {
return `${this.thingName} is required.`;
}
}
export class AlreadyExistsValidationError extends ValidationError {
constructor(table) {
super();
this.table = table;
}
get message() {
return `${this.value} already exists in ${this.table}.${this.thingName}.`;
}
}
export class UnknownRelationValidationError extends ValidationError {
constructor(table, foreignKey) {
super();
this.table = table;
this.foreignKey = foreignKey;
}
get message() {
return `${this.thingName}=${this.value} relation was not found in ${this.table}${this.foreignKey !== undefined ? `.${this.foreignKey}` : ''}.`;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVmFsaWRhdG9yLmpzIiwic291cmNlUm9vdCI6Ii4vIiwic291cmNlcyI6WyJkYi9WYWxpZGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBSUEsTUFBTSxDQUFDLE9BQU8sT0FBTyxTQUFTO0lBQTlCO1FBQ3FCLFVBQUssR0FBd0IsRUFBRSxDQUFDO1FBQ2hDLHlCQUFvQixHQUFhLEVBQUUsQ0FBQztJQXlLekQsQ0FBQztJQXBLRzs7Ozs7T0FLRztJQUNHLE9BQU8sQ0FBQyxTQUFpQixFQUFFLEtBQW9CLEVBQUUsVUFBbUIsRUFBRSxVQUF1Qjs7WUFDL0YsTUFBTSxHQUFHLEdBQUcsSUFBSSxhQUFhLEVBQUUsQ0FBQztZQUVoQyxLQUFLLE1BQU0sSUFBSSxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUU7Z0JBQzNCLElBQUksVUFBVSxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVE7b0JBQUUsU0FBUztnQkFFM0MsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUFDO2dCQUM3RCxJQUFJLENBQUMsTUFBTSxLQUFLLEtBQUssSUFBSSxNQUFNLFlBQVksT0FBTyxJQUFJLENBQUMsTUFBTSxNQUFNLENBQUMsS0FBSyxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFO29CQUMzRixNQUFNLEtBQUssR0FBb0IsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUM1QyxLQUFLLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztvQkFDNUIsS0FBSyxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7b0JBQ3BCLEdBQUcsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7aUJBQ3pCO3FCQUFNLElBQUksSUFBSSxDQUFDLFNBQVMsS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRTtvQkFDOUQsTUFBTTtpQkFDVDthQUNKO1lBRUQsSUFB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