add constraint

This commit is contained in:
2025-05-23 23:07:18 +08:00
parent 067ed5d40e
commit 116b92fe98
5 changed files with 141 additions and 6 deletions
@@ -0,0 +1,38 @@
import {
registerDecorator,
ValidationArguments,
ValidationOptions,
ValidatorConstraint,
ValidatorConstraintInterface,
} from 'class-validator';
@ValidatorConstraint({ name: 'isMatch' })
export class MatchConstraint implements ValidatorConstraintInterface {
validate(value: any, validationArguments?: ValidationArguments): Promise<boolean> | boolean {
const [relatedProperty, reverse] = validationArguments.constraints;
const relatedValue = (validationArguments.object as any)[relatedProperty];
return (value === relatedValue) !== reverse;
}
defaultMessage?(validationArguments?: ValidationArguments): string {
const [relatedProperty, reverse] = validationArguments.constraints;
return `${relatedProperty} and ${validationArguments.property} ${
reverse ? `is` : `don't`
} match`;
}
}
export function isMatch(
relatedProperty: string,
reverse = false,
validationOptions?: ValidationOptions,
) {
return (object: RecordAny, propertyName: string) => {
registerDecorator({
target: object.constructor,
propertyName,
options: validationOptions,
constraints: [relatedProperty, reverse],
validator: MatchConstraint,
});
};
}
@@ -0,0 +1,48 @@
import {
ValidationArguments,
ValidatorConstraintInterface,
ValidationOptions,
registerDecorator,
} from 'class-validator';
type ModelType = 1 | 2 | 3 | 4 | 5;
export class PasswordConstraint implements ValidatorConstraintInterface {
validate(value: any, validationArguments?: ValidationArguments): Promise<boolean> | boolean {
const validateModel: ModelType = validationArguments.constraints[0] ?? 1;
switch (validateModel) {
case 1:
return /\d/.test(value) && /[A-Za-z]/.test(value);
case 2:
return /\d/.test(value) && /[a-z]/.test(value);
case 3:
return /\d/.test(value) && /[A-Z]/.test(value);
case 4:
return /\d/.test(value) && /[A-Z]/.test(value) && /[a-z]/.test(value);
case 5:
return (
/\d/.test(value) &&
/[A-Z]/.test(value) &&
/[a-z]/.test(value) &&
/[!@#$%^&]/.test(value)
);
default:
return /\d/.test(value) && /[A-Za-z]/.test(value);
}
}
defaultMessage?(validationArguments?: ValidationArguments): string {
return "($value) 's format error";
}
}
export function IsPassword(model?: ModelType, validationOptions?: ValidationOptions) {
return (object: RecordAny, propertyName: string) => {
registerDecorator({
target: object.constructor,
propertyName,
options: validationOptions,
constraints: [model],
validator: PasswordConstraint,
});
};
}
@@ -0,0 +1,39 @@
import { registerDecorator, ValidationArguments, ValidationOptions } from 'class-validator';
// eslint-disable-next-line import/no-extraneous-dependencies
import { isMobilePhone, IsMobilePhoneOptions, MobilePhoneLocale } from 'validator';
export function isMatchPhone(
value: any,
locale: MobilePhoneLocale,
options?: IsMobilePhoneOptions,
): boolean {
if (!value) {
return false;
}
const phoneArr: string[] = value.split('.');
if (phoneArr.length !== 2) {
return false;
}
return isMobilePhone(phoneArr.join(''), locale, options);
}
export function IsMatchPhone(
locales?: MobilePhoneLocale | MobilePhoneLocale[],
options?: IsMobilePhoneOptions,
validationOptions?: ValidationOptions,
) {
return (object: RecordAny, propertyName: string) => {
registerDecorator({
target: object.constructor,
propertyName,
options: validationOptions,
constraints: [locales || 'any', options],
validator: {
validate: (value: any, args: ValidationArguments): boolean =>
isMatchPhone(value, args.constraints[0], args.constraints[1]),
defaultMessage: (_args: ValidationArguments) =>
'$property must be a phone number,eg: +86.12345678901',
},
});
};
}