1

I want a custom ValidatorConstraint to validate if a column with a value exist in a table. I want to inject DataSource of TypeORM for make the query, but when I make this.dataSource in my validator returns me "undefined".

This is my DTO:

import { ApiProperty } from '@nestjs/swagger';
import { IsInt, IsNotEmpty, IsString, Max, Min } from 'class-validator';
import { Exists } from "../../common/decorators/exists.decorator";

export class CreateTeacherReviewDto {

    @ApiProperty()
    @IsNotEmpty()
    @IsInt()
    @Exists(['teacher:id'])
    readonly teacherId: number;
}

This is my custom validator:

import { BadRequestException, Injectable } from '@nestjs/common';
import {
    registerDecorator,
    ValidationArguments,
    ValidationOptions,
    ValidatorConstraint,
    ValidatorConstraintInterface,
} from 'class-validator';
import { DataSource } from "typeorm";

export function Exists(property: any, validationOptions?: ValidationOptions) {
    return (object: any, propertyName: string) => {
        registerDecorator({
            target: object.constructor,
            propertyName,
            options: validationOptions,
            constraints: [property],
            validator: ExistsConstraint,
        });
    };
}

@ValidatorConstraint({ name: 'Exists', async: true })
@Injectable()
export class ExistsConstraint implements ValidatorConstraintInterface {
    constructor(protected dataSource: DataSource) {}

    async validate(value: number | string, args: ValidationArguments) {
        const { constraints } = args;
        if (constraints.length === 0) {
            throw new BadRequestException(`Failed validating ${value} exists.`);
        }

        const str = constraints[0][0].split(':');
        const tableName = str[0];
        const columnName = str[1];

        console.log(this.dataSource); // In this line returns me undefined

        return false;

    }

    defaultMessage(args: ValidationArguments) {
        const { property, value } = args;

        return `${property} ${value} is already taken.`;
    }
}

My dependencies in package.json:

"dependencies": {
        "@nestjs/common": "^8.0.0",
        "@nestjs/config": "^2.1.0",
        "@nestjs/core": "^8.0.0",
        "@nestjs/jwt": "^8.0.1",
        "@nestjs/mapped-types": "*",
        "@nestjs/passport": "^8.2.2",
        "@nestjs/platform-express": "^8.0.0",
        "@nestjs/swagger": "^5.2.1",
        "@nestjs/typeorm": "^8.1.4",
        "bcrypt": "^5.0.1",
        "class-transformer": "^0.5.1",
        "class-validator": "^0.13.2",
        "mysql2": "^2.3.3",
        "passport": "^0.6.0",
        "passport-jwt": "^4.0.0",
        "reflect-metadata": "^0.1.13",
        "rimraf": "^3.0.2",
        "rxjs": "^7.2.0",
        "swagger-ui-express": "^4.4.0",
        "typeorm": "^0.3.6"
    },

And my tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "target": "es2017",
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true,
    "skipLibCheck": true,
    "strictNullChecks": false,
    "noImplicitAny": false,
    "strictBindCallApply": false,
    "forceConsistentCasingInFileNames": false,
    "noFallthroughCasesInSwitch": false
  }
}
Rodrigo
  • 11
  • 3

2 Answers2

0

Inject the ExistsConstraint in SharedModule as provider, and it should works

0

add this code to your main.ts should be work

  useContainer(app.select(AppModule), { fallbackOnErrors: true });

Mondly
  • 21
  • 1
  • 5
  • 2
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – turivishal Dec 18 '22 at 07:42