@smendivil/crud v1.0.0
@smendivil/crud
A flexible CRUD module for NestJS applications supporting both TypeORM and In-Memory implementations.
Features
- Generic CRUD operations
- Multiple repository implementations (TypeORM, In-Memory)
- Environment-based configuration
- Full TypeScript support
- 100% test coverage
- Easy integration with NestJS
- Type-safe implementations
- Configurable for development and production
Installation
Install the package and its peer dependencies:
npm install @smendivil/crud @smendivil/entity @nestjs/typeorm typeorm
Quick Start
Basic Usage
- Create your entity:
import { Entity, Column } from 'typeorm'; import { IEntity } from '@smendivil/entity';
@Entity() export class UserEntity implements IEntity { @Column({ primary: true }) id: string;
@Column()
name: string;
@Column()
createdAt: Date;
@Column()
updatedAt: Date;
}
- Import the CRUD module:
import { Module } from '@nestjs/common'; import { CRUDModule } from '@smendivil/crud'; import { UserEntity } from './entities/user.entity';
@Module({ imports: CRUDModule.forRoot(UserEntity), , exports: 'ICRUDService', }) export class UserModule {}
- Use the CRUD service:
import { Controller, Inject } from '@nestjs/common'; import { ICRUDService } from '@smendivil/crud'; import { UserEntity } from './entities/user.entity';
@Controller('users') export class UserController { constructor( @Inject('ICRUDService') private readonly userService: ICRUDService ) {}
@Get(':id')
async findOne(@Param('id') id: string) {
return this.userService.getById(id);
}
}
Environment-Based Configuration
Development Configuration
Use InMemoryCRUDRepository for development:
import { Module } from '@nestjs/common'; import { CRUDModule, InMemoryCRUDRepository } from '@smendivil/crud'; import { UserEntity } from './entities/user.entity';
@Module({ imports: CRUDModule.forRoot(UserEntity, InMemoryCRUDRepository), , }) export class UserModule {}
Production Configuration
Use TypeORMCRUDRepository for production:
import { Module } from '@nestjs/common'; import { CRUDModule, TypeORMCRUDRepository } from '@smendivil/crud'; import { UserEntity } from './entities/user.entity';
@Module({ imports: CRUDModule.forRoot(UserEntity, TypeORMCRUDRepository), , }) export class UserModule {}
Advanced Configuration
Database Configuration
Create a database configuration file:
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
const databaseConfig: { key: string: TypeOrmModuleOptions } = { development: { type: 'sqlite', database: ':memory:', entities: / your entities /, synchronize: true, }, production: { type: 'postgres', host: process.env.DB_HOST, port: Number(process.env.DB_PORT), username: process.env.DB_USERNAME, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, entities: / your entities /, synchronize: false, } };
export default databaseConfig;
Dynamic Module Configuration
Configure the module based on environment:
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ConfigModule, ConfigService } from '@nestjs/config'; import databaseConfig from './config/database.config';
@Module({
imports: [
ConfigModule.forRoot({
load: () => ({ database: databaseConfig }),
}),
TypeOrmModule.forRootAsync({
inject: ConfigService,
useFactory: (configService: ConfigService) => {
const env = process.env.NODE_ENV || 'development';
return configService.get(database.${env}
);
},
}),
// Your other modules
],
})
export class AppModule {}
API Reference
ICRUDService
Base service interface providing CRUD operations:
- create(entity: T): Promise
- getById(id: string): Promise<T | null>
- update(id: string, entity: Partial): Promise<T | null>
- delete(id: string): Promise
- getAll(params?: any): Promise<T[]>
ICRUDRepository
Base repository interface:
- create(entity: T): Promise
- findById(id: string): Promise<T | null>
- update(id: string, entity: Partial): Promise<T | null>
- delete(id: string): Promise
- findAll(params?: any): Promise<T[]>
Available Implementations
- InMemoryCRUDRepository:
- Uses Map for in-memory storage
- Perfect for development and testing
- No database required
- TypeORMCRUDRepository:
- Uses TypeORM for database operations
- Supports multiple databases
- Production-ready implementation
Testing
Unit Testing
Example of testing with the InMemoryCRUDRepository:
import { Test } from '@nestjs/testing'; import { InMemoryCRUDRepository } from '@smendivil/crud'; import { UserEntity } from './entities/user.entity';
describe('UserService', () => { let repository: InMemoryCRUDRepository;
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
providers: [
{
provide: 'ICRUDRepository',
useClass: InMemoryCRUDRepository,
},
],
}).compile();
repository = moduleRef.get('ICRUDRepository');
});
it('should create user', async () => {
const user = new UserEntity();
user.id = '1';
const result = await repository.create(user);
expect(result).toEqual(user);
});
});
Best Practices
- Entity Structure:
- Always implement IEntity interface
- Include id, createdAt, and updatedAt fields
- Use TypeORM decorators when needed
- Repository Selection:
- Use InMemoryCRUDRepository for development/testing
- Use TypeORMCRUDRepository for production
- Configure based on NODE_ENV
- Error Handling:
- Handle null returns from getById
- Manage failed operations gracefully
- Implement proper validation
- Configuration:
- Use environment variables
- Separate development and production configs
- Implement proper type checking
Environment Variables
Required environment variables for production:
NODE_ENV=production DB_TYPE=postgres DB_HOST=localhost DB_PORT=5432 DB_USERNAME=postgres DB_PASSWORD=yourpassword DB_NAME=yourdatabase
Common Issues and Solutions
- TypeORM Connection:
- Ensure proper database configuration
- Check entity registration
- Verify environment variables
- Repository Injection:
- Use proper injection token ('ICRUDRepository')
- Check module imports
- Verify provider registration
- Type Safety:
- Implement IEntity correctly
- Use proper generics
- Check compiler settings
License
MIT
8 months ago