esercizio

This commit is contained in:
Dmitri 2025-11-16 18:24:18 +01:00
parent 82c87e9358
commit 7986151af4
Signed by: kanopo
GPG Key ID: 759ADD40E3132AC7
7 changed files with 170 additions and 17 deletions

56
package-lock.json generated
View File

@ -225,6 +225,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz",
"integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==",
"dev": true,
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "^7.18.6",
@ -1524,6 +1525,7 @@
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.2.0.tgz",
"integrity": "sha512-Ndcqak/ETYi+n1c5lFRPbxKLyUuM6DIOxcvfEFGfi0f6ad4dWDXRDx7z/n8V0l8+Y8djvvOHgf3t0e93w963Qg==",
"peer": true,
"dependencies": {
"iterare": "1.2.1",
"tslib": "2.4.1",
@ -1557,6 +1559,7 @@
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.2.0.tgz",
"integrity": "sha512-eVN7aXAavV+ImVt8mO+rQ5YyUP6lJtQKUtQHxHKzz6Wg+9Y67WWZS2uDcDX5NNcNijbWky5bqad86fgcK9Oqig==",
"hasInstallScript": true,
"peer": true,
"dependencies": {
"@nuxtjs/opencollective": "0.3.2",
"fast-safe-stringify": "2.1.1",
@ -1594,6 +1597,7 @@
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-9.2.0.tgz",
"integrity": "sha512-J1+nnzjC9ATSb0jSHBqAE6D4o+PIbGPItEfYTOZ0rkE5bvqnRfgO4q94SXhfri+5PaNx2vM8tOZsKaD0QmQRGQ==",
"peer": true,
"dependencies": {
"body-parser": "1.20.1",
"cors": "2.8.5",
@ -2022,7 +2026,8 @@
"version": "16.18.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.3.tgz",
"integrity": "sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg==",
"dev": true
"dev": true,
"peer": true
},
"node_modules/@types/parse-json": {
"version": "4.0.0",
@ -2142,6 +2147,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz",
"integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==",
"dev": true,
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0",
@ -2466,6 +2472,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
"dev": true,
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@ -2886,6 +2893,7 @@
"url": "https://tidelift.com/funding/github/npm/browserslist"
}
],
"peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001400",
"electron-to-chromium": "^1.4.251",
@ -3053,6 +3061,7 @@
"url": "https://paulmillr.com/funding/"
}
],
"peer": true,
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@ -3096,12 +3105,14 @@
"node_modules/class-transformer": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
"peer": true
},
"node_modules/class-validator": {
"version": "0.13.2",
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz",
"integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==",
"peer": true,
"dependencies": {
"libphonenumber-js": "^1.9.43",
"validator": "^13.7.0"
@ -3600,6 +3611,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz",
"integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==",
"dev": true,
"peer": true,
"dependencies": {
"@eslint/eslintrc": "^1.3.3",
"@humanwhocodes/config-array": "^0.11.6",
@ -4966,6 +4978,7 @@
"resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz",
"integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==",
"dev": true,
"peer": true,
"dependencies": {
"@jest/core": "^28.1.3",
"@jest/types": "^28.1.3",
@ -6666,6 +6679,7 @@
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz",
"integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==",
"dev": true,
"peer": true,
"bin": {
"prettier": "bin-prettier.js"
},
@ -6881,7 +6895,8 @@
"node_modules/reflect-metadata": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
"peer": true
},
"node_modules/regexpp": {
"version": "3.2.0",
@ -7042,6 +7057,7 @@
"version": "7.5.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
"integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
"peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
@ -7093,6 +7109,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@ -7807,6 +7824,7 @@
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
"dev": true,
"peer": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@ -7979,6 +7997,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
"dev": true,
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@ -8549,6 +8568,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz",
"integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==",
"dev": true,
"peer": true,
"requires": {
"@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "^7.18.6",
@ -9555,6 +9575,7 @@
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.2.0.tgz",
"integrity": "sha512-Ndcqak/ETYi+n1c5lFRPbxKLyUuM6DIOxcvfEFGfi0f6ad4dWDXRDx7z/n8V0l8+Y8djvvOHgf3t0e93w963Qg==",
"peer": true,
"requires": {
"iterare": "1.2.1",
"tslib": "2.4.1",
@ -9565,6 +9586,7 @@
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.2.0.tgz",
"integrity": "sha512-eVN7aXAavV+ImVt8mO+rQ5YyUP6lJtQKUtQHxHKzz6Wg+9Y67WWZS2uDcDX5NNcNijbWky5bqad86fgcK9Oqig==",
"peer": true,
"requires": {
"@nuxtjs/opencollective": "0.3.2",
"fast-safe-stringify": "2.1.1",
@ -9579,6 +9601,7 @@
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-9.2.0.tgz",
"integrity": "sha512-J1+nnzjC9ATSb0jSHBqAE6D4o+PIbGPItEfYTOZ0rkE5bvqnRfgO4q94SXhfri+5PaNx2vM8tOZsKaD0QmQRGQ==",
"peer": true,
"requires": {
"body-parser": "1.20.1",
"cors": "2.8.5",
@ -9943,7 +9966,8 @@
"version": "16.18.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.3.tgz",
"integrity": "sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg==",
"dev": true
"dev": true,
"peer": true
},
"@types/parse-json": {
"version": "4.0.0",
@ -10047,6 +10071,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz",
"integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==",
"dev": true,
"peer": true,
"requires": {
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0",
@ -10294,7 +10319,8 @@
"version": "8.8.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
"dev": true
"dev": true,
"peer": true
},
"acorn-import-assertions": {
"version": "1.8.0",
@ -10604,6 +10630,7 @@
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
"integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
"dev": true,
"peer": true,
"requires": {
"caniuse-lite": "^1.0.30001400",
"electron-to-chromium": "^1.4.251",
@ -10711,6 +10738,7 @@
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"dev": true,
"peer": true,
"requires": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@ -10743,12 +10771,14 @@
"class-transformer": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
"peer": true
},
"class-validator": {
"version": "0.13.2",
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz",
"integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==",
"peer": true,
"requires": {
"libphonenumber-js": "^1.9.43",
"validator": "^13.7.0"
@ -11130,6 +11160,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz",
"integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==",
"dev": true,
"peer": true,
"requires": {
"@eslint/eslintrc": "^1.3.3",
"@humanwhocodes/config-array": "^0.11.6",
@ -12145,6 +12176,7 @@
"resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz",
"integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==",
"dev": true,
"peer": true,
"requires": {
"@jest/core": "^28.1.3",
"@jest/types": "^28.1.3",
@ -13414,7 +13446,8 @@
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz",
"integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==",
"dev": true
"dev": true,
"peer": true
},
"prettier-linter-helpers": {
"version": "1.0.0",
@ -13572,7 +13605,8 @@
"reflect-metadata": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
"peer": true
},
"regexpp": {
"version": "3.2.0",
@ -13675,6 +13709,7 @@
"version": "7.5.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
"integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
"peer": true,
"requires": {
"tslib": "^2.1.0"
}
@ -13705,6 +13740,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"peer": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@ -14234,6 +14270,7 @@
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
"dev": true,
"peer": true,
"requires": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@ -14353,7 +14390,8 @@
"version": "4.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
"dev": true
"dev": true,
"peer": true
},
"universalify": {
"version": "2.0.0",

View File

@ -1,14 +1,19 @@
import { Controller, Post, Body } from '@nestjs/common';
import { InfoService } from './info.service';
import { UpdateInfoRequest } from './interfaces';
import { UpdateFormRequest, UpdateInfoRequest } from './interfaces';
import { BaseResponse } from '../interfaces';
@Controller('info')
export class InfoController {
constructor(private readonly infoService: InfoService) {}
constructor(private readonly infoService: InfoService) { }
@Post('/validate')
getConfig(@Body() bodyRequest: UpdateInfoRequest): Promise<BaseResponse> {
return this.infoService.validateInfo(bodyRequest);
}
@Post('/validate-form')
getForm(@Body() bodyRequest: UpdateFormRequest): Promise<BaseResponse> {
return this.infoService.validateForm(bodyRequest);
}
}

View File

@ -1,10 +1,11 @@
import { Module } from '@nestjs/common';
import { InfoController } from './info.controller';
import { InfoService } from './info.service';
import { IsAgeMatchingBirthDateConstraint } from './validators/age-match-date-birth';
@Module({
imports: [],
controllers: [InfoController],
providers: [InfoService],
providers: [InfoService, IsAgeMatchingBirthDateConstraint],
})
export class InfoModule {}
export class InfoModule { }

View File

@ -1,9 +1,9 @@
import { Injectable } from '@nestjs/common';
import { plainToClass } from 'class-transformer';
import { validate } from 'class-validator';
import { UpdateInfoRequest as UpdateInfoRequestInterface } from './interfaces';
import { UpdateFormRequest, UpdateInfoRequest as UpdateInfoRequestInterface } from './interfaces';
import { BaseResponse } from '../interfaces';
import { UpdateInfoRequest } from './models';
import { UpdateFormValidator, UpdateInfoRequest } from './models';
@Injectable()
export class InfoService {
@ -23,4 +23,21 @@ export class InfoService {
data,
};
}
async validateForm(
rawData: UpdateFormRequest,
): Promise<BaseResponse> {
const data = plainToClass(UpdateFormValidator, rawData);
const validationErrors = await validate(data);
if (validationErrors.length > 0) {
return {
success: false,
errors: validationErrors,
};
}
return {
success: true,
data,
};
}
}

View File

@ -1,3 +1,10 @@
export interface UpdateInfoRequest {
name: string;
}
export interface UpdateFormRequest {
name: string
age: number
married?: boolean
dateOfBirth: Date
}

View File

@ -1,5 +1,7 @@
import { UpdateInfoRequest as UpdateInfoRequestInterface } from '../interfaces';
import { IsNotEmpty, IsString, MinLength } from 'class-validator';
import { UpdateFormRequest, UpdateInfoRequest as UpdateInfoRequestInterface } from '../interfaces';
import { IsDate, IsNotEmpty, IsNumber, IsString, Max, MaxLength, Min, MinLength } from 'class-validator';
import { Type } from 'class-transformer';
import { IsAgeMatchingBirthDate } from '../validators/age-match-date-birth';
export class UpdateInfoRequest implements UpdateInfoRequestInterface {
@IsNotEmpty()
@ -7,3 +9,25 @@ export class UpdateInfoRequest implements UpdateInfoRequestInterface {
@MinLength(3)
name: string;
}
export class UpdateFormValidator implements UpdateFormRequest {
@IsNotEmpty()
@IsString()
@MinLength(5)
@MaxLength(50)
name: string;
@IsNotEmpty()
@IsNumber()
@Max(150)
@Min(1)
@IsAgeMatchingBirthDate({ message: "mismatch betwean date of birth and age" })
age: number
married?: boolean
@IsNotEmpty()
@Type(() => Date)
@IsDate()
dateOfBirth: Date
}

View File

@ -0,0 +1,61 @@
import {
ValidatorConstraint,
ValidatorConstraintInterface,
ValidationArguments,
registerDecorator,
ValidationOptions,
} from 'class-validator';
import { Injectable } from '@nestjs/common';
// Funzione helper per calcolare l'età
function calculateAge(birthDate: Date): number {
if (!birthDate || !(birthDate instanceof Date)) return -1;
const today = new Date();
let age = today.getFullYear() - birthDate.getFullYear();
const m = today.getMonth() - birthDate.getMonth();
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
age--;
}
return age;
}
@ValidatorConstraint({ name: 'isAgeMatchingBirthDate', async: false })
@Injectable()
export class IsAgeMatchingBirthDateConstraint implements ValidatorConstraintInterface {
// Questo è il metodo che esegue la validazione
validate(age: number, args: ValidationArguments) {
// args.object è l'intero oggetto DTO che viene validato
const object = args.object as any;
const dateOfBirth = object.dateOfBirth;
// Se dateOfBirth non è una data valida, questo validatore non fallisce.
// Ci penseranno @IsDate e @IsNotEmpty a bloccare la richiesta prima.
if (!(dateOfBirth instanceof Date)) {
return true;
}
const calculatedAge = calculateAge(dateOfBirth);
return age === calculatedAge;
}
// Questo metodo fornisce il messaggio di errore di default
defaultMessage(args: ValidationArguments) {
const calculatedAge = calculateAge((args.object as any).dateOfBirth);
return `The provided age ($value) is incorrect. Based on the date of birth, it should be ${calculatedAge}.`;
}
}
export function IsAgeMatchingBirthDate(validationOptions?: ValidationOptions) {
return function(object: Object, propertyName: string) {
registerDecorator({
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
constraints: [],
validator: IsAgeMatchingBirthDateConstraint,
});
};
}