NestJS 활용하기(4) - DB와 typeORM 연동

이태훈·2023년 11월 4일
0

NestJS

목록 보기
4/6

typeORM이란?

TypeScript와 JavaScript를 위한 ORM 라이브러리로, 데이터베이스 작업을 할 때 객체 지향적인 접근을 통해 복잡한 SQL 쿼리 없이 데이터를 관리할 수 있도록 도와주는 도구이다.

설치 방법

npm install typeorm @nestjs/typeorm --save

typeORM document : https://typeorm.io/

이용 방법

scr폴더 내에 configs 폴더를 만들고 typeorm.config.ts 파일을 생성한다. 그 이후 TypeOrmModuleOptions 타입을 가지는 class를 생성한 후 db연결에 필요한 정보들을 아래와 같이 입력한다.

import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import * as config from 'config'

const dbConfig = config.get('db');

export const typeORMConfig: TypeOrmModuleOptions = {
  type: dbConfig.type,
  host: process.env.RDS_HOSTNAME || dbConfig.host,
  port: process.env.RDS_PORT || dbConfig.port,
  username: process.env.RDS_USERNAME || dbConfig.username,
  password: process.env.RDS_PASSWORD || dbConfig.passowrd,
  database: process.env.RDS_DB_NAME || dbConfig.database,
  entities: [__dirname + '/../**/*.entity.{js,ts}'],
  synchronize: dbConfig.synchronize,
};

이러한 정보들은 환경변수나 codebase 설정 파일을 통해 불러 온 값을 저장해준다.
여기서 entites의 경우 해당 경로에 있는 entity 파일을 통해 데이터베이스 테이블을 생성해주는 부분이며, synchronize는 true 값을 주면 애플리케이션을 다시 실행할 때 entity의 변경이 있는 경우 해당 테이블을 drop하고 다시 생성해준다.

이후 app.module.ts에 imports에 아래와 같이 typeORMConfig를 추가해주어야 한다.

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { BoardsModule } from './boards/boards.module';
import { typeORMConfig } from './configs/typeorm.config';

@Module({
  imports: [
    TypeOrmModule.forRoot(typeORMConfig).
    BoardModule
  ]
})
export class AppModule {}

Entity

데이터베이스 테이블과 매핑되는 클래스로, @Entity() 데코레이터를 통해 해당 클래스가 엔티티임을 명시하며 테이블의 구조를 정의하고 테이블의 각 레코드는 entity의 인스턴스로 표현된다. 이를 활용하여 데이터베이스 테이블을 직접 다루는 대신 객체 지향적인 방식으로 데이터를 처리할 수 있다.

import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from 'typeorm';

@Entity() 
export class User extends BaseEntity {
  @PrimaryGeneratedColumn() // 데이터베이스가 자동으로 생성해주는 기본 키
  id: number;

  @Column() // 클래스의 속성이 테이블의 컬럼에 매핑됨을 명시
  firstName: string;

  @Column()
  lastName: string;

  @Column({ unique: true }) // 옵션을 통해 해당 컬럼이 유니크함을 설정 가능
  email: string;
}

위와 같이 BaseEntity를 상속함으로써, save(), remove(), findOne()과 같은 BaseEntity에 정의된 메서드로 데이터베이스 작업을 수행할 수 있다.

Repository

데이터베이스와의 상호작용을 추상화하는데 사용되며, service에서 repository를 호출하여 데이터베이스와 관련된 작업을 수행하고 return 해주는 형태로 사용한다.

import { DataSource, Repository } from 'typeorm';
import { Board } from './board.entity';
import { CreateBoardDto } from './dto/create-board.dto';
import { BoardStatus } from './board-status.enum';
import { Injectable } from '@nestjs/common';

@Injectable()
export class BoardRepository extends Repository<Board> {
  constructor(private dataSource: DataSource) {
    super(Board, dataSource.createEntityManager());
  }
// 옛날 버전에서는 이렇게 사용했지만 현재는 @EntityRepository 데코레이터를 사용하지 않음
// @EntityRepository(Board)
// export class BoardRepository extends Repository<Board> {

  async createBoard(createBoardDto: CreateBoardDto): Promise<Board> {
    const { title, description } = createBoardDto;
    const board = this.create({
      title,
      description,
      status: BoardStatus.PUBLIC,
      user
    });

    await this.save(board);
    return board;
  }
}

이렇게 Repository를 생성한 후 해당 Repository를 board.module.ts에 providers 배열에 아래와 같이 추가해주어야 한다.

import { Module } from '@nestjs/common';
import { BoardsController } from './boards.controller';
import { BoardsService } from './boards.service';
import { BoardRepository } from './board.repository';
import { AuthModule } from 'src/auth/auth.module';

@Module({
  controllers: [BoardsController],
  providers: [BoardsService, BoardRepository],
  
  // 과거 버전
  // imports: [ TypeOrmModule.forFeature([BoardRepository])],
  // controllers: [BoardsController],
  // providers: [BoardsService],
  
})
export class BoardsModule {}

그 다음 service에 해당 Repository를 아래와 같이 주입해준다.

import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { Board } from './board.entity';

@Injectable()
export class BoardService {
  constructor(
  
  // 과거 버전은 아래와 같은 데코레이터가 필요
  // @InjectRepository(BoardRepository)
  
  private boardRepository: Repository<board>
  ) {}


  // 이후 메소드들...
}

최신 버전으로 업데이트 되며 과거에 사용하던 버전의 코드와 일부 달라지는 부분이 생겨 에러가 발생하여 최신 버전에서 동작할 수 있도록 코드를 일부 변경하였다.

이렇게 하고 나면 typeORM을 사용하여 쿼리를 사용하지 않고도 DB와 관련된 작업을 처리할 수 있따. 조금 더 복잡한 쿼리를 사용해야 하는 경우에는 쿼리 빌더를 사용할 수 있다. 자세한 내용의 위의 typeORM 링크를 참고하길 바란다.

profile
지속가능한 개발자를 꿈꿉니다

0개의 댓글