@slaega/db-validation is a NestJS validation library that supports multiple ORMs (Prisma, TypeORM, MicroORM, Sequelize). It allows you to declare common database validations through a unified builder and integrate them into your services via decorators with result retrieval.
- Multi-ORM Support: Compatible with Prisma, TypeORM, MicroORM, and Sequelize
 - Unified Builder: A single builder with ORM-specific methods
 - Smart Validations:
exists(404 Not Found) - Returns the entity if foundensureExists(400 Bad Request) - Returns the entity if foundunique(409 Conflict)ensureNotExists(400 Bad Request)- Count validations: 
ensureCountAtLeast,ensureCountAtMost,ensureCountEquals 
 - Decorator with Results: Retrieve validated entities directly in your methods
 - Type-safe: Full TypeScript support for all ORMs
 
yarn add @slaega/db-validation
# or
npm install @slaega/db-validation- NestJS Dependencies (required in all cases)
 
yarn add @nestjs/common @nestjs/core reflect-metadata- ORM-specific Dependencies
 
yarn add @prisma/clientyarn add @nestjs/typeorm typeormyarn add @mikro-orm/core @mikro-orm/nestjsyarn add @nestjs/sequelize sequelize sequelize-typescriptimport { Module } from '@nestjs/common';
import { DbValidationModule } from '@slaega/db-validation';
import { PrismaModule } from './prisma/prisma.module';
import { PrismaService } from './prisma/prisma.service';
@Module({
  imports: [
    PrismaModule,
    DbValidationModule.registerAsync({
      imports: [PrismaModule],
      useFactory: (prisma: PrismaService) => ({
        adapter: new PrismaAdapter(prisma)
      }),
      inject: [PrismaService],
    }),
  ],
})
export class AppModule {}import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { DbValidationModule } from '@slaega/db-validation';
import { DataSource } from 'typeorm';
@Module({
  imports: [
    TypeOrmModule.forRoot({
      // your TypeORM config
    }),
    DbValidationModule.forRoot({
      useFactory: (dataSource: DataSource) => ({
        adapter: new TypeORMAdapter(dataSource)
      }),
      inject: [DataSource]
    })
  ]
})
export class AppModule {}import { Module } from '@nestjs/common';
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { DbValidationModule } from '@slaega/db-validation';
import { MikroORM } from '@mikro-orm/core';
@Module({
  imports: [
    MikroOrmModule.forRoot({
      // your MikroORM config
    }),
    DbValidationModule.forRoot({
      useFactory: (orm: MikroORM) => ({
        adapter: new MikroOrmAdapter(orm)
      }),
      inject: [MikroORM]
    })
  ]
})
export class AppModule {}import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import { DbValidationModule } from '@slaega/db-validation';
import { Sequelize } from 'sequelize-typescript';
@Module({
  imports: [
    SequelizeModule.forRoot({
      // your Sequelize config
    }),
    DbValidationModule.forRoot({
      useFactory: (sequelize: Sequelize) => ({
        adapter: new SequelizeAdapter(sequelize)
      }),
      inject: [Sequelize]
    })
  ]
})
export class AppModule {}The builder can be used directly or in a validation class. Here's the syntax for each ORM:
import { ValidationBuilder } from '@slaega/db-validation';
// Using model names as strings
const builder = ValidationBuilder
  .forPrisma()
  .ensureExists('User', { id: 1 })
  .unique('Post', { title: 'My title' });import { ValidationBuilder } from '@slaega/db-validation';
import { User } from './entities/user.entity';
import { Post } from './entities/post.entity';
// Using Entity classes
const builder = ValidationBuilder
  .forTypeorm()
  .ensureExists(User, { id: 1 })
  .unique(Post, { title: 'My title' });import { ValidationBuilder } from '@slaega/db-validation';
import { User } from './entities/user.entity';
import { Post } from './entities/post.entity';
// Using Entity classes
const builder = ValidationBuilder
  .forMikroOrm()
  .ensureExists(User, { id: 1 })
  .unique(Post, { title: 'My title' });import { ValidationBuilder } from '@slaega/db-validation';
import { User } from './models/user.model';
import { Post } from './models/post.model';
// Using Sequelize models
const builder = ValidationBuilder
  .forSequelize()
  .ensureExists(User, { id: 1 })
  .unique(Post, { title: 'My title' });For better code organization and easier mapping with the @UseDbValidation decorator, create a validation class per service. Each class contains rules for the corresponding service methods:
import { ValidationBuilder } from '@slaega/db-validation';
// With Prisma
// post.validation-rules.ts
export class PostValidationRules {
  // Rule for PostService.create
  create(email: string, input: CreatePostDto) {
    return ValidationBuilder
      .forPrisma()
      .ensureExists('Author', { email }, {
        message: 'Author not found',
        code: 'AUTHOR_NOT_FOUND'
      })
      .ensureNotExists('Post', { title: input.title }, {
        message: 'Title already exists',
        code: 'TITLE_DUPLICATE'
      });
  }
}
// 2. Using in service with result retrieval
@Injectable()
export class PostService {
  constructor(
    private readonly repo: PostRepository,
    private readonly dbValidationService: DbValidationService, // The attribute name doesn't matter
  ) {}
  // Note: The decorator automatically detects DbValidationService in the service
  // If you extend or modify DbValidationService, you must specify the getter:
  // @UseDbValidation(PostValidationRules, 'create', (self) => self.dbValidationService)
  //
  // Otherwise, automatic detection is sufficient:
  @UseDbValidation(PostValidationRules, 'create')
  async createPost(
    email: string,
    input: CreatePostDto,
    options?: ValidationOptions
  ) {
    // Results are in validation order
    const [authorResult, _] = options?.validationResult ?? [];
    // authorResult contains the Author object directly
    const author = authorResult;
    // You can use the validated author data
    return this.repo.create({
      ...input,
      authorId: author.id,
    });
  }
}The validation flow:
- The decorator executes rules defined in 
PostValidationRules.create ensureExistschecks the author and returns its data if foundensureNotExistsverifies the title doesn't exist- Results are passed to the method via 
options.validationResult - You can use validated data (e.g., author) in your logic
 
You can also use the validator directly:
const builder = new PostValidationRules().create(userId, input);
const results = await dbValidatorService.validate(builder);
// Access results
const [userResult] = results; 
console.log(userResult)| Validation | Condition | HTTP Code | Exception | OK Result | 
|---|---|---|---|---|
| exists | Record found | 404 | NotFoundException | ✅ Found object | 
| ensureExists | Record found | 400 | BadRequestException | ✅ Found object | 
| unique | No duplicate | 409 | ConflictException | ✅ true | 
| ensureNotExists | No duplicate | 400 | BadRequestException | ✅ true | 
| ensureCountAtLeast | Count ≥ min | 400 | BadRequestException | ✅ { count: number } | 
| ensureCountAtMost | Count ≤ max | 400 | BadRequestException | ✅ { count: number } | 
| ensureCountEquals | Count = val | 400 | BadRequestException | ✅ { count: number } | 
// For exists/ensureExists
const [userResult] = await service.validate(builder);
console.log(userResult); // { id: 1, email: 'user@example.com', ... }
// For unique/ensureNotExists
const [uniqueResult] = await service.validate(builder);
console.log(uniqueResult); // true
// For count validations
const [countResult] = await service.validate(builder);
console.log(countResult); // { count: 5 }- 
Clone & install
git clone https://github.com/slaega/db-validation.git cd db-validation yarn install - 
Build
yarn build
 - 
Link in a project
yarn link cd ../your-app yarn link @slaega/db-validation yarn install - 
Tests
yarn test yarn test:watch 
- Fork the repo
 - Create a branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -m 'Add feature') - Push to your branch (
git push origin feature/my-feature) - Open a Pull Request
 
This project is under the MIT license. See LICENSE for more details.
Maintained by Slaega. Feel free to open issues on GitHub!