본문 바로가기
NestJs

[NestJs] TypeORM을 사용해서 게시물 CRUD 만들기

by teamnova 2024. 4. 5.

안녕하세요. 오늘은 지난 시간 배열을 이용해서 저장하던 게시물을 db에 저장할 수 있게 작업하려고 합니다.

설정은 지난 시간에 모두 마친것으로 알고 진행하겠습니다.

 

먼저 src 폴더 하위에 core라는 폴더를 만들고 그 안에 typeorm-ex.decorator.ts, typeorm-ex.module.ts를 생성해 주세요.

먼저  typeorm-ex.decorator.ts 파일입니다.

import { SetMetadata } from '@nestjs/common';


export const TYPEORM_EX_CUSTOM_REPOSITORY = 'TYPEORM_EX_CUSTOM_REPOSITORY';

export function CustomRepository(entity: Function): ClassDecorator {
  return SetMetadata(TYPEORM_EX_CUSTOM_REPOSITORY, entity);
}

다음은 typeorm-ex.module.ts 파일입니다.

import { DynamicModule, Provider } from '@nestjs/common';
import { getDataSourceToken } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { TYPEORM_EX_CUSTOM_REPOSITORY } from './typeorm-ex.decorator';

export class TypeOrmExModule {
  public static forCustomRepository<T extends new (...args: any[]) => any>(
    repositories: T[],
  ): DynamicModule {
    const providers: Provider[] = [];

    for (const repository of repositories) {
      const entity = Reflect.getMetadata(
        TYPEORM_EX_CUSTOM_REPOSITORY,
        repository,
      );

      if (!entity) {
        continue;
      }

      providers.push({
        inject: [getDataSourceToken()],
        provide: repository,
        useFactory: (dataSource: DataSource): typeof repository => {
          const baseRepository = dataSource.getRepository<any>(entity);
          return new repository(
            baseRepository.target,
            baseRepository.manager,
            baseRepository.queryRunner,
          );
        },
      });
    }

    return {
      exports: providers,
      module: TypeOrmExModule,
      providers,
    };
  }
}

그리고 board 폴더안에 board.entity.ts 파일을 생성해주세요. 데이터 형식을 정할 곳입니다.

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

@Entity({name: 'board'})
export class Board extends BaseEntity {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;

    @Column()
    description: string;
}

이전 createBoardDTO랑 같은 형식으로 해볼게요.

그 다음은 board.repository.ts 파일을 생성해볼게요.

import { CustomRepository } from "src/core/typeorm-ex.decorator";
import { Board } from "./board.entity";
import { Repository } from "typeorm";
import { CreateBoardDto } from "./board.dto";
import { InternalServerErrorException, NotFoundException } from "@nestjs/common";

@CustomRepository(Board)
export class BoardRepository extends Repository<Board> {

    async createBoard(createBoardDto: CreateBoardDto): Promise<Board> {
        const board = this.create(createBoardDto);

        try {
            await this.save(board);
            return board;
        }catch(error){
            throw new InternalServerErrorException();
        }
    }

    async getAll(): Promise<Board[]> {
        const boards = await this.find();
        return boards;
    }

    async checkBoard(id: number): Promise<void> {
        const board = await this.findOne({where: {id}});
        if(!board){
            throw new NotFoundException(`Can't found board by ${id}`);
        }
    }

    async updateBoard(createBoardDto: CreateBoardDto, id: number): Promise<number> {
        await this.checkBoard(id);
        await this.update(id,createBoardDto);
        return id;
    }
    
    async removeBoard(id: number): Promise<number> {
        await this.checkBoard(id);
        await this.delete({id});
        return id;
    }
}

 

그리고 service랑 controller도 수정해볼게요. 

먼저 service 파일입니다.

import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateBoardDto } from './board.dto';
import { BoardRepository } from './board.repository';
import { Board } from './board.entity';

@Injectable()
export class BoardService {
    constructor(
        private boardRepository: BoardRepository
    ){}

    create(createBoardDto: CreateBoardDto): Promise<Board>{
        return this.boardRepository.createBoard(createBoardDto);
    }

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

    update(createBoardDto: CreateBoardDto,id: number): Promise<number> {
        return this.boardRepository.updateBoard(createBoardDto,id);
    }

    delete(id: number): Promise<number>{
        return this.boardRepository.removeBoard(id);
    }
}

그리고 controller파일입니다.

import { Body, Controller, Delete, Get, Param, Post, Put, ValidationPipe } from '@nestjs/common';
import { BoardService } from './board.service';
import { CreateBoardDto } from './board.dto';
import { Board } from './board.entity';

@Controller('board')
export class BoardController {
    constructor(
        private boardService: BoardService
    ){}

    @Post()
    create(@Body(ValidationPipe)createBoardDto: CreateBoardDto): Promise<Board> {
        return this.boardService.create(createBoardDto);
    }

    @Get()
    getAll(): Promise<Board[]>{
        return this.boardService.getAll();
    }

    @Put('/:id')
    update(
        @Body(ValidationPipe)createBoardDto: CreateBoardDto,
        @Param('id')id: number): Promise<number> {
        return this.boardService.update(createBoardDto,+id);
    }

    @Delete('/:id')
    delete(@Param('id')id: number): Promise<number>{
        return this.boardService.delete(+id);
    }
}

그리고 dto 파일에서 id값은 없애 주세요.

그리고나서 테스트는 이전 postman 사용하던거 그대로 사용하시면 동작할 겁니다! 만약 원하는 컬럼이 따로 있다면 직접 수정해보시면서 테스트해보면 이해가 빠를거에요! 감사합니다.