1. TypeOrm 설정
TypeORM은 typescript계의 Sequelizer라고 생각하면 된다. 쉽게 말해 타입스크립트에서 사용하는 ORM. Nest 환경에서는 아래의 명령어로 typeorm을 추가할 수 있다.
npm i @nestjs/typeorm typeorm mysql2
npm i @nestjs/config joi
그리고 추가적으로 validation을 위해 joi 패키지도 설치했다.
import Joi from 'joi';
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { Post } from './post/entities/post.entity';
import { PostModule } from './post/post.module';
const typeOrmModuleOptions = {
useFactory: async (
configService: ConfigService,
): Promise<TypeOrmModuleOptions> => ({
type: 'mysql',
host: configService.get('DB_HOST'),
port: configService.get('DB_PORT'),
username: configService.get('DB_USERNAME'),
password: configService.get('DB_PASSWORD'),
database: configService.get('DB_NAME'),
entities: [Post],
synchronize: configService.get('DB_SYNC'),
logging: true,
}),
inject: [ConfigService],
};
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
validationSchema: Joi.object({
DB_HOST: Joi.string().required(),
DB_PORT: Joi.number().required(),
DB_USERNAME: Joi.string().required(),
DB_PASSWORD: Joi.string().required(),
DB_NAME: Joi.string().required(),
DB_SYNC: Joi.boolean().required(),
}),
}),
TypeOrmModule.forRootAsync(typeOrmModuleOptions),
PostModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
- imports 부분에 ConfigModule 부분
- isGlobal: true는 전역적으로 적용한다고 선언
- validationSchema에 정의된 스키마대로 .env에 정의되어 있어야 서버가 정상 동작함
- typeOrmModuleOptions 옵션
- 하드코딩된 설정을 주입하는게 아니라 동적으로 .env 파일에서 설정을 불러와서 주입
- useFactory 기법을 사용하는데, TypeOrmModule.forRootAsync 함수에 전달되는 설정 객체를 동적으로 생성하기 위하여 사용하는 것. inject: [ConfigService]라는 옵션을 통해 의존성 주입
- TypeOrmModule.forRootAsync - 동적으로 설정 주입 / forRoot : 하드코딩된 설정 사용
2. 엔티티 & 레포지토리
1) 개념
- 엔티티 : 데이터베이스의 특정 테이블을 대표하는 객체로 ORM에서 사용됨. 이 객체를 통해 ORM 프레임워크가 DB와 통신, 테이블의 각 로우를 객체로 표현하며, 해당 객체의 속성을 테이블의 컬럼과 매핑됨.
- 리포지토리: DDD(Domain-Driven Disign)에서 나온 개녕으로, 엔티티와 DB위 중간 계층을 형성하는 객체. 개발자가 DB와의 통신과정을 알지 못해도 추상화된 리포지토리의 함수를 사용하여 원하는 결과를 DB에서 불러올 수 있게 함. 리포지토리를 사용하면 도메인 로직은 DB의 세부 구현에서 분리되므로 유지보수성과 확장성이 향상
이전에 express에서 구현했던 3-layered-architecture는 레포지토리 부분이 파일로 존재했기에 처음엔 이해하는 것이 어려웠다. 아직 추상화라는 개념이 익숙치 않아서 그런 듯한데, 코드를 작성해보며 해결해야하는 과제라고 생각한다.
// post.entity.ts
import { IsNumber, IsString } from 'class-validator';
import {
Column,
CreateDateColumn,
DeleteDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
@Entity({
name: 'posts',
})
export class Post {
@PrimaryGeneratedColumn()
id: number;
@IsString()
@Column('varchar', { length: 50, nullable: false })
title: string;
@IsString()
@Column('varchar', { length: 1000, nullable: false })
content: string;
@IsNumber()
@Column('int', { select: false, nullable: false })
password: number;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
@DeleteDateColumn()
deletedAt?: Date;
}
예시 코드를 보면 @Entity 어노테이션은 해당 클래스가 어떤 테이블에 매핑되는지 나타내고 @PrimaryGeneratedColumn은 PK를 나타내며, @Column과 @DateColumn도 볼 수 있다. 비밀번호에 select 옵션은 일반적인 조회로 비밀번호를 얻어올 수 없게 하기 위한 설정으로, select절로 특정하지 않으면 반환하지 않게 해줘서 민감 정보를 보호할 수 있게 한다.
@DeleteDateColumn은 레코드가 삭제된 날짜가 자동으로 기록되는데, 해당 엔티티가 삭제되는 순간 실제로 삭제(Hard Delete)되는 게 아니라 논리적으로 삭제(Soft Delete) 되는 것이다.전체 게시물을 가져올 때 DeletedAt !== Null인 게시물만 가져와도 삭제된 것과 같은 결과를 낼 수 있다.
2) 리포지토리 생성
// post.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Post } from './entities/post.entity';
import { PostController } from './post.controller';
import { PostService } from './post.service';
@Module({
imports: [TypeOrmModule.forFeature([Post])],
controllers: [PostController],
providers: [PostService],
})
export class PostModule {}
특정 모듈 서비스에서 사용하고 싶은 리포지토리가 있다면 @Module 데코레이터의 imports 속성에 반드시 넣어야 DI가 활성화된다. 이제 Service 파일에서 생성자(constructure)를 통해 repository를 사용할 수 있게 된다. 생성자에서 @InjectRepository 어노테이션을 사용하여 리포지토리를 주입할 수 있고 일반 리포지토리로 DB연산이 부족하면 일반 리포지토리를 상속한 커스텀 리포지토리를 쓸 수 있다.
'Sparta > TIL' 카테고리의 다른 글
24.03.18 TIL - 정렬 for Javascript (0) | 2024.03.19 |
---|---|
24.03.15 TIL - ELK stack (0) | 2024.03.18 |
24.03.11 TIL - nest.js 패키지 (0) | 2024.03.12 |
24.03.08 TIL - Nest.js 파일 구조 (0) | 2024.03.09 |
24.03.07 TIL - Typescript(3) (0) | 2024.03.08 |