NestJs TypeORM
포스트
취소

NestJs TypeORM

ORM이란?

객체와 관계형 데이터베이스의 데이터를 자동으로 변형 및 연결하는 작업입니다. ORM을 이용한 개발은 객체와 데이터베이스의 변형에 유연하게 사용할 수 있습니다.

TypeORM이란?

TypeORM은 node.js에서 실행되고 typescript로 작성된 객체 관계형 매퍼 라이브러리입니다. TypeORM은 MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana 및 WebSQL과 같은 여러 데이터베이스를 지원합니다.

Pure Javascript와의 코드 비교

  • TypeORM

    1
    
    const boards = Board.find({ title: "Hello", status: "PUBLIC" });
    
  • Pure Javascript

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    db.query(
      'SELECT * FROM boards WHERE title = "Hello" AND status = "PUBLIC"',
      (err, result) => {
        if (err) {
          throw new Error("Error");
        }
        boards = result.rows;
      }
    );
    

특징과 이점

  • 모델을 기반으로 데이터베이스 테이블 체계를 자동으로 생성합니다.
  • 데이터베이스에서 개체를 쉽게 삽입, 업데이트 및 삭제할 수 있습니다.
  • 테이블 간의 매핑을 만듭니다.
  • 간단한 CLI 명령을 제공합니다.
  • 간단한 코딩으로 ORM 프레임워크를 사용하기 쉽습니다.
  • 다른 모듈과 쉽게 통합됩니다.

설치 모듈

  • @nestjs/typeorm: NestJs에서 TypeORM을 사용하기 위해 연동시켜주는 모듈
  • typeorm: TypeORM 모듈
  • pg: Postgres 모듈
1
yarn add pg typeorm @nestjs/typeorm

공식문서

설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// configs/typeorm.config.ts
import { TypeOrmModuleOptions } from "@nestjs/typeorm";

export const typeORMConfig: TypeOrmModuleOptions = {
  type: "postgres",
  host: "localhost",
  port: 5432,
  username: "postgres",
  password: "P@ssw0rd",
  database: "board-app",
  entities: [__dirname + "/../**/*.entity.{js,ts}"],
  synchronize: true
};

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

@Module({
  imports: [TypeOrmModule.forRoot(typeORMConfig), BoardsModule],
  controllers: [],
  providers: []
})
export class AppModule {}

설정파일을 작성해주고 애플리케이션 모듈에 import 시켜줍니다.

Entity 생성하기

엔티티 생성 소스 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm";
import { BoardStatus } from "./board.model";

@Entity()
export class Board extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column()
  description: string;

  @Column()
  status: BoardStatus;
}
  • @Entity(): Board 클래스가 엔티티임을 나타내는 데 사용됩니다.
  • @PrimaryGeneratedColumn(): id 열이 Board 엔티티의 기본 키 열임을 나타내는 데 사용됩니다.
  • Column(): Board 엔티티의 title 및 description과 같은 다른 열을 나타내는 데 사용됩니다.

Repository란?

리포지토리는 엔티티 개체와 함께 작동하며 엔티티 찾기, 삽입, 삭제 등을 처리합니다.

공식 문서

CRUD 예제 코드

Module

1
2
3
4
5
6
7
8
9
10
11
12
import { Module } from "@nestjs/common";
import { BoardsController } from "./boards.controller";
import { BoardsService } from "./boards.service";
import { TypeOrmModule } from "@nestjs/typeorm";
import { Board } from "./board.entity";

@Module({
  imports: [TypeOrmModule.forFeature([Board])],
  controllers: [BoardsController],
  providers: [BoardsService]
})
export class BoardsModule {}

Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import { Injectable, NotFoundException } from "@nestjs/common";
import { CreateBoardDto } from "./dto/create-board.dto";
import { Board } from "./board.entity";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { BoardStatus } from "./board-status.enum";

@Injectable()
export class BoardsService {
  constructor(
    @InjectRepository(Board)
    private boardRepository: Repository<Board>
  ) {}

  async getAllBoards(): Promise<Board[]> {
    return this.boardRepository.find();
  }

  async createBoard(createBoardDto: CreateBoardDto): Promise<Board> {
    const { title, description } = createBoardDto;
    const newBoard = this.boardRepository.create({
      title,
      description,
      status: BoardStatus.PUBLIC
    });
    await this.boardRepository.save(newBoard);
    return newBoard;
  }

  async getBoardById(id: number): Promise<Board> {
    const board = await this.boardRepository.findOneBy({ id });
    if (!board) {
      throw new NotFoundException(`Can't found Board with id ${id}`);
    }
    return board;
  }

  async deleteBoard(id: number): Promise<void> {
    await this.getBoardById(id);
    await this.boardRepository.delete(id);
  }

  async updateBoardStatus(id: number, status: BoardStatus): Promise<Board> {
    const board = await this.getBoardById(id);
    board.status = status;
    await this.boardRepository.save(board);
    return board;
  }
}

Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
  UsePipes,
  ValidationPipe
} from "@nestjs/common";
import { BoardsService } from "./boards.service";
import { CreateBoardDto } from "./dto/create-board.dto";
import { BoardStatusValidationPipe } from "./pipes/board-status-validation.pipe";
import { Board } from "./board.entity";
import { BoardStatus } from "./board-status.enum";

@Controller("boards")
export class BoardsController {
  constructor(private boardsService: BoardsService) {}

  @Get()
  async getAllBoards(): Promise<Board[]> {
    return this.boardsService.getAllBoards();
  }

  @Post()
  @UsePipes(ValidationPipe)
  async createBoard(@Body() createBoardDto: CreateBoardDto): Promise<Board> {
    return this.boardsService.createBoard(createBoardDto);
  }

  @Get("/:id")
  async getBoardById(@Param("id") id: number): Promise<Board> {
    return this.boardsService.getBoardById(id);
  }

  @Delete("/:id")
  async deleteBoard(@Param("id") id: number): Promise<void> {
    await this.boardsService.deleteBoard(id);
  }

  @Patch("/:id/status")
  async updateBoardStatus(
    @Param("id") id: number,
    @Body("status", BoardStatusValidationPipe) status: BoardStatus
  ): Promise<Board> {
    return this.boardsService.updateBoardStatus(id, status);
  }
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.