Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save msonowal/2b15b6109369916f0069f6f31025e8d9 to your computer and use it in GitHub Desktop.
Save msonowal/2b15b6109369916f0069f6f31025e8d9 to your computer and use it in GitHub Desktop.
Unique Validator Example for NestJS
import { ValidationArguments, ValidatorConstraintInterface } from 'class-validator';
import { Connection, EntitySchema, FindConditions, ObjectType } from 'typeorm';
interface UniqueValidationArguments<E> extends ValidationArguments {
constraints: [
ObjectType<E> | EntitySchema<E> | string,
((validationArguments: ValidationArguments) => FindConditions<E>) | keyof E,
];
}
export abstract class UniqueValidator implements ValidatorConstraintInterface {
protected constructor(protected readonly connection: Connection) {}
public async validate<E>(value: string, args: UniqueValidationArguments<E>) {
const [EntityClass, findCondition = args.property] = args.constraints;
return (
(await this.connection.getRepository(EntityClass).count({
where:
typeof findCondition === 'function'
? findCondition(args)
: {
[findCondition || args.property]: value,
},
})) <= 0
);
}
public defaultMessage(args: ValidationArguments) {
const [EntityClass] = args.constraints;
const entity = EntityClass.name || 'Entity';
return `${entity} with the same '${args.property}' already exist`;
}
}
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigService } from './config.service';
import useFactory from './db.factory';
import { Unique } from './validator';
@Module({
imports: [
TypeOrmModule.forRootAsync({
imports: [LoggerModule],
inject: [ConfigService],
useFactory,
}),
],
providers: [Unique],
})
export class DbModule {}
import { IsInt, IsOptional, IsString, MinLength, Validate } from 'class-validator';
import { Category } from './category.entity';
import { Unique } from './validator';
export class CategoryDto {
@IsInt()
// checks if value of CategoryDto.id is unique by searching in Category.id in DB
@Validate(Unique, [Category])
public id: string;
@IsString()
// checks if value of CategoryDto.title is unique by searching in Category.title in DB
@Validate(Unique, [Category])
public title: string;
@IsString()
// checks if value of CategoryDto.someField is unique by searching in Category.title in DB
@Validate(Unique, [Category, 'title'])
public someField: string;
@Column()
@IsNotEmpty()
@IsString()
// checks if pair of provided title+description is unique in DB
@Validate(
Unique,
[
Category,
({ object: { title, description } }: { object: CategoryForm }) => ({
title,
description,
}),
],
{
message: ({
targetName,
}: ValidationArguments) =>
`${targetName} with the same pair of title and description already exist`,
},
)
public description: string;
}
import { ValidatorConstraint } from 'class-validator';
import { Injectable } from '@nestjs/common';
import { InjectConnection } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { UniqueValidator } from '../../utils/validator';
@ValidatorConstraint({ name: 'unique', async: true })
@Injectable()
export class UniqueAnotherConnection extends UniqueValidator {
constructor(
@InjectConnection('another-connection')
protected readonly connection: Connection,
) {
super(connection);
}
}
import { ValidatorConstraint } from 'class-validator';
import { Injectable } from '@nestjs/common';
import { InjectConnection } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { UniqueValidator } from '../../../utils/validator';
@ValidatorConstraint({ name: 'unique', async: true })
@Injectable()
export class Unique extends UniqueValidator {
constructor(@InjectConnection() protected readonly connection: Connection) {
super(connection);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment