본문 바로가기
개발/Nest

리포지토리 패턴

by 안뇽! 2024. 11. 16.
반응형

리포지토리 패턴

DB와 비즈니스 로직간의 중재자 역할을 하는 계층을 제공한다. 이를 통해 DB 작업을 다른 로직들과 분리 할 수 있다.

Nest에서는 TypeORM을 이용하여 커스텀 레포지토리를 만들 수 있다.(원래 제공되던 @EntityRepository() 가 depricated 되었다.)

DB에 접근하는 repository

TypeORM을 이용하여 DB에 접근한다.

// board.repository.ts

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

@Injectable()
export class BoardsRepository {
  private boardsRepository: Repository<Board>;

  constructor(private readonly dataSource: DataSource) {
    this.boardsRepository = this.dataSource.getRepository(Board);
  }

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

  async getBoardById(id: number): Promise<Board> {
    const found = await this.boardsRepository.findOneBy({ id });

    return found;
  }

  async createBoard(createBoard: CreateBoardDto) {
    const { title, description, status = BoardStatus.PUBLIC } = createBoard;
    const newBoard = this.boardsRepository.create({
      title,
      description,
      status,
    });
    await this.boardsRepository.save(newBoard);
    return newBoard;
  }

  async deleteBoard(id: number): Promise<DeleteResult> {
    const result = await this.boardsRepository.delete({ id });
    return result;
  }

  async saveBoard(board: Board): Promise<Board> {
    return this.boardsRepository.save(board);
  }
}

 

Service 로직

실제 비즈니스 로직을 다룬다.

// boards.service.ts

import { Injectable, NotFoundException } from '@nestjs/common';
import { BoardStatus } from 'src/boards/board-status.enum';
import { Board } from 'src/boards/board.entity';
import { BoardsRepository } from 'src/boards/board.repository';
import { CreateBoardDto } from 'src/boards/dto/create-board.dto';

@Injectable()
export class BoardsService {
  constructor(private readonly boardsRepository: BoardsRepository) {}

  async getAllBoards(): Promise<Board[]> {
    const boards = await this.boardsRepository.getAllBoards();

    return boards;
  }

  async getBoardById(id: number): Promise<Board> {
    const found = await this.boardsRepository.getBoardById(id);

    if (!found) {
      throw new NotFoundException(`Board with ID ${id} not found`);
    }

    return found;
  }

  async createBoard(createBoard: CreateBoardDto): Promise<Board> {
    const { title, description, status } = createBoard;

    const board = this.boardsRepository.createBoard({
      title,
      description,
      status,
    });

    return board;
  }

  async deleteBoard(id: number): Promise<void> {
    const deleteResult = await this.boardsRepository.deleteBoard(id);

    if (deleteResult.affected === 0) {
      throw new NotFoundException(`Board with ID ${id} not found`);
    }
  }

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

    board.status = status;

    await this.boardsRepository.saveBoard(board);

    return board;
  }
}

 

Controller

프론트를 마주하는 레이어. 요청을 받고 응답을 반환한다.

// boards.controller.ts

import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  ParseIntPipe,
  Patch,
  Post,
  UsePipes,
  ValidationPipe,
} from '@nestjs/common';
import { BoardStatus } from 'src/boards/board-status.enum';
import { Board } from 'src/boards/board.entity';
import { BoardsService } from 'src/boards/boards.service';
import { CreateBoardDto } from 'src/boards/dto/create-board.dto';
import { BoardStatusValidationPipe } from 'src/boards/pipes/board-status-validation.pipe';

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

  @Get()
  getAllBoards(): Promise<Board[]> {
    return this.boardsService.getAllBoards();
  }
  @Get('/:id')
  getBoardById(@Param('id') id: number): Promise<Board> {
    return this.boardsService.getBoardById(id);
  }

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

  @Delete('/:id')
  deleteBoard(@Param('id', ParseIntPipe) id): Promise<void> {
    return this.boardsService.deleteBoard(id);
  }

  @Patch('/status/:id')
  updateBoardStatus(
    @Param('id', ParseIntPipe) id: number,
    @Body('status', BoardStatusValidationPipe) status: BoardStatus,
  ): Promise<Board> {
    return this.boardsService.updateBoardStatus(id, status);
  }
}
반응형