Package Exports
- nestjs-drizzle-crud
- nestjs-drizzle-crud/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (nestjs-drizzle-crud) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
NestJS Drizzle CRUD
A complete, type-safe CRUD abstraction layer for Drizzle ORM in NestJS applications. Supports PostgreSQL and MySQL with advanced features like soft delete, transactions, bulk operations, and full-text search.
Features
- ๐ Complete CRUD Operations - find, create, update, delete, and more
- ๐๏ธ SQL Database Support - PostgreSQL & MySQL with dialect-specific optimizations
- โก Type-Safe - Full TypeScript support with generics
- ๐ Soft Delete - Built-in soft delete with restore functionality
- ๐ฆ Bulk Operations - Mass create, update, delete with transaction support
- ๐ Advanced Querying - Filtering, pagination, sorting, full-text search
- ๐ฏ NestJS Native - Seamless integration with NestJS dependency injection
- ๐งช Test Utilities - Comprehensive testing helpers
- ๐ก๏ธ Production Ready - Error handling, transactions, and validation hooks
Installation
npm install nestjs-drizzle-crudQuick Start
1. Basic Setup
// app.module.ts
import { Module } from '@nestjs/common';
import { DrizzleCrudModule } from 'nestjs-drizzle-crud';
@Module({
imports: [
DrizzleCrudModule.forRoot({
dialect: 'postgresql', // or 'mysql'
defaults: {
softDelete: true,
timestamps: true,
pagination: { defaultLimit: 20, maxLimit: 100 },
},
}),
],
})
export class AppModule {}2. Create a CRUD Service
// user.service.ts
import { Injectable } from '@nestjs/common';
import { SqlBaseCrudService } from 'nestjs-drizzle-crud';
// Your Drizzle table schema
export const users = {
id: 'id',
name: 'name',
email: 'email',
password: 'password',
created_at: 'created_at',
updated_at: 'updated_at',
deleted_at: 'deleted_at',
};
// DTOs and interfaces
export interface User {
id: number;
name: string;
email: string;
password: string;
created_at: Date;
updated_at: Date;
deleted_at: Date | null;
}
export interface CreateUserDto {
name: string;
email: string;
password: string;
}
export interface UpdateUserDto {
name?: string;
email?: string;
password?: string;
}
export interface UserFilters {
name?: string;
email?: string;
}
@Injectable()
export class UserService extends SqlBaseCrudService<User, CreateUserDto, UpdateUserDto, UserFilters> {
constructor(@Inject('DRIZZLE_DB') db: any) {
super({
dialect: 'postgresql',
db,
table: users,
primaryKey: 'id',
primaryKeyType: 'serial',
softDelete: { enabled: true, column: 'deleted_at' },
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
});
}
protected async validateCreate(data: CreateUserDto): Promise<void> {
if (!data.email.includes('@')) {
throw new Error('Invalid email format');
}
}
protected async validateUpdate(id: number, data: UpdateUserDto): Promise<void> {
if (data.email && !data.email.includes('@')) {
throw new Error('Invalid email format');
}
}
protected mapCreateDtoToEntity(data: CreateUserDto): Record<string, any> {
return {
...data,
created_at: new Date(),
updated_at: new Date(),
};
}
protected mapUpdateDtoToEntity(data: UpdateUserDto): Record<string, any> {
return {
...data,
updated_at: new Date(),
};
}
// Custom methods
async findByEmail(email: string): Promise<User | null> {
return this.findOne({ email });
}
}3. Use in Controller
// user.controller.ts
import { Controller, Get, Post, Put, Delete, Body, Param, Query } from '@nestjs/common';
import { UserService } from './user.service';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get()
async findAll(
@Query('page') page: number = 1,
@Query('limit') limit: number = 20
) {
return this.userService.findAll({}, { page, limit });
}
@Get(':id')
async find(@Param('id') id: string) {
return this.userService.find(+id);
}
@Post()
async create(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
@Put(':id')
async update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.userService.update(+id, updateUserDto);
}
@Delete(':id')
async delete(@Param('id') id: string) {
return this.userService.softDelete(+id);
}
}Advanced Usage
Bulk Operations
// Mass create users
const users = await this.userService.massCreate(userDtos);
// Mass update
const updatedUsers = await this.userService.massUpdate(
[1, 2, 3],
{ status: 'active' }
);
// Mass soft delete
await this.userService.massSoftDelete([1, 2, 3]);Full-Text Search (PostgreSQL)
const results = await this.userService.fullTextSearch(
'john doe',
['name', 'email', 'bio']
);Transactions
await this.userService.executeSqlTransaction(async (tx) => {
await this.userService.create(user1, { transaction: tx });
await this.userService.create(user2, { transaction: tx });
});Advanced Filtering
// Complex filters
const results = await this.userService.findAll({
name: { like: 'John%' },
age: { gt: 18, lt: 65 },
status: { in: ['active', 'pending'] }
});
// With relations and selection
const user = await this.userService.find(1, {
relations: ['profile', 'posts'],
select: ['id', 'name', 'email']
});Module Configuration
Async Configuration
DrizzleCrudModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
dialect: configService.get('DATABASE_DIALECT'),
defaults: {
softDelete: true,
timestamps: true,
},
}),
inject: [ConfigService],
}),Multiple Entities
DrizzleCrudModule.forFeature([
{
name: 'User',
table: usersTable,
service: UserService,
config: { primaryKey: 'id' },
},
{
name: 'Post',
table: postsTable,
service: PostService,
config: { softDelete: { enabled: false } },
},
]),Testing
// user.service.spec.ts
import { TestCrudFactory } from 'nestjs-drizzle-crud/test-utils';
describe('UserService', () => {
let service: UserService;
let mockDb: any;
beforeEach(() => {
mockDb = TestCrudFactory.createMockDb();
const mockTable = TestCrudFactory.createMockTable();
service = TestCrudFactory.createTestService(
UserService,
mockDb,
mockTable
);
});
it('should create user', async () => {
const createDto = { name: 'John', email: 'john@test.com' };
const mockEntity = TestCrudFactory.createMockEntity();
mockDb.insert.mockReturnValue({
values: jest.fn().mockReturnThis(),
returning: jest.fn().mockResolvedValue([mockEntity]),
});
const result = await service.create(createDto);
expect(result).toEqual(mockEntity);
});
});API Reference
Core Methods
find(id, options?) - Find by primary key
findOne(where, options?) - Find by criteria
findAll(filters?, pagination?, options?) - Find all with filtering & pagination
create(data, options?) - Create new entity
update(id, data, options?) - Update entity
softDelete(id, options?) - Soft delete entity
restore(id, options?) - Restore soft-deleted entity
delete(id, options?) - Hard delete entity
Bulk Methods
massCreate(data[], options?) - Create multiple entities
massUpdate(ids[], data, options?) - Update multiple entities
massSoftDelete(ids[], options?) - Soft delete multiple entities
massRestore(ids[], options?) - Restore multiple entities
massDelete(ids[], options?) - Hard delete multiple entities
Utility Methods
exists(id, options?) - Check if entity exists
count(filters?, options?) - Count entities
fullTextSearch(term, columns, pagination?, options?) - Full-text search (PostgreSQL)
Configuration Options
interface SqlCrudConfig {
dialect: 'postgresql' | 'mysql';
db: any; // Drizzle database instance
table: any; // Drizzle table
// Primary key configuration
primaryKey: string;
primaryKeyType: 'serial' | 'bigserial' | 'int' | 'bigint' | 'uuid';
// Soft delete
softDelete?: {
enabled: boolean;
column: string;
};
// Timestamps
timestamps?: {
createdAt: string;
updatedAt: string;
};
// Pagination
pagination?: {
defaultLimit: number;
maxLimit: number;
};
}Supported Versions
NestJS: >=10.0.0
Drizzle ORM: >=0.28.0
Node.js: >=18.0.0
PostgreSQL: >=12.0
MySQL: >=8.0
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT
This README provides:
- Clear installation instructions
- Quick start guide with code examples
- Advanced usage patterns
- Comprehensive API documentation
- Testing examples
- Configuration reference
- Version compatibility
It's ready to use and will help users understand how to implement your package quickly!