๐Ÿ˜พnest.js TypeORM ์—ฐ๊ฒฐ & DB ์—ฐ๊ฒฐ

yyยท2024๋…„ 1์›” 30์ผ
0

์žก๋™์‚ฐ์ด

๋ชฉ๋ก ๋ณด๊ธฐ
14/21
post-thumbnail

nest๊ฐ•์˜๋ฅผ ๋ณด๋ฉด ์ผ๋‹จ ์ธ๋ฉ”๋ชจ๋ฆฌ๋กœ ์ฝ”๋“œ๋ฅผ ์งœ๋‹ค๊ฐ€ ๋‚˜์ค‘์— DB ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค์ค€๋‹ค. expressํ•  ๋•Œ๋Š” ๊ทธ๋ƒฅ ๋ฐ”๋กœ ์•Œ๋ ค์คฌ๋Š”๋ฐ...์ƒ๊ฐํ•ด๋ณด๋ฉด nest์—์„œ DB๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š”๊ฒŒ ๋ณต์žกํ•ด์„œ ์•„๋‹๊นŒ ์‹ถ๋‹ค.
์šฐ์„  nest.js์—์„œ DB์—ฐ๊ฒฐํ• ๋•Œ ์‰ฝ๊ฒŒ ํ•ด์ฃผ๋Š” orm์„ ์„ค์น˜ํ•ด๋ณด์ž.


TypeORM

โœ”๏ธ TypeORM ์„ค์น˜

window ๋ฒ„์ „ ๊ธฐ์ค€

npm i typeorm@0.3.0
npm i @nestjs/typeorm mysql

ํ˜น์‹œ ์„ค์น˜ํ•  ๋•Œ class-validator๋•Œ๋ฌธ์— ์‹คํŒจํ–ˆ๋‹ค๋ฉด class-validator๋ฅผ ์ง€์šฐ๊ณ  ๋‚˜์ค‘์— class-validator๋ฅผ ์„ค์น˜ํ•˜๋Š”๊ฒƒ๋„ ๋ฐฉ๋ฒ•์ด๋‹ค. ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์ฐจ๋ก€๋Œ€๋กœ ์‹คํ–‰ํ•ด๋ณด๋ฉด ๋ ๋“ฏ.


npm uninstall class-validator
npm i typeorm@0.3.0
npm i @nestjs/typeorm mysql
npm i class-validator

โœ”๏ธ DB ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •

1. ํŒจํ‚ค์ง€ ์„ค์น˜

  • .env ๋Œ€์‹  nest.js์—์„œ@nestjs/config ํŒจํ‚ค์ง€ ์‚ฌ์šฉ
npm i @nestjs/config

2. .env ํŒŒ์ผ ์ƒ์„ฑ

  • root ๋””๋ ‰ํ† ๋ฆฌ์— .envํŒŒ์ผ ์ƒ์„ฑ ํ›„ ๋‚ด์šฉ ์ž…๋ ฅ
DATABASE_HOST="localhost"
DATABASE_PORT=3306
DATABASE_USERNAME="์—ฌ๋Ÿฌ๋ถ„๋“ค์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์•„์ด๋””"
DATABASE_PASSWORD="์—ฌ๋Ÿฌ๋ถ„๋“ค์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋น„๋ฐ€๋ฒˆํ˜ธ"
DATABASE_NAME="board"
DATABASE_SYNCHRONIZE=true

3. config ์„ค์ •

  • 1) app.module.ts ์ˆ˜์ •
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { BoardModule } from "./board/board.module";
import { TypeOrmConfigService } from "./config/typeorm.config.service";
import { ConfigModule, ConfigService } from "@nestjs/config";
import { Article } from "./board/article.entity";

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }), // ์ถ”๊ฐ€ (์ฐธ๊ณ  : ๋งจ ์œ„๋กœ ์™€์•ผํ•จ)
    TypeOrmModule.forRootAsync({ // ์ถ”๊ฐ€
      imports: [ConfigModule],
      useClass: TypeOrmConfigService,
      inject: [ConfigService],
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

  • 2) config / typeorm.config.service.ts ์ƒ์„ฑ
    config ํด๋”๋ฅผ ๋งŒ๋“ค๊ณ , typeorm.config.service.ts ํŒŒ์ผ์„ ์ƒ์„ฑ.
    ์—ฌ๊ธฐ์— .env ๋‚ด์šฉ์„ ๋ถˆ๋Ÿฌ์„œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ์จ ์‚ฌ์šฉํ•  ์˜ˆ์ •.
import { Injectable } from "@nestjs/common";
import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from "@nestjs/typeorm";
import { ConfigService } from "@nestjs/config";
import { Article } from "src/board/article.entity";

@Injectable()
export class TypeOrmConfigService implements TypeOrmOptionsFactory {
  constructor(private readonly configService: ConfigService) {}

  createTypeOrmOptions(): TypeOrmModuleOptions {
    return {
      type: "mysql",
      host: this.configService.get<string>("DATABASE_HOST"),
      port: this.configService.get<number>("DATABASE_PORT"),
      username: this.configService.get<string>("DATABASE_USERNAME"),
      password: this.configService.get<string>("DATABASE_PASSWORD"),
      database: this.configService.get<string>("DATABASE_NAME"),
      entities: [__dirname + "/**/*.entity{.ts,.js}"],
      synchronize: this.configService.get<boolean>("DATABASE_SYNCHRONIZE"),
    };
  }
}


Entity, Repository ์ƒ์„ฑ

โœ”๏ธ Entity ( a.k.a table, schema )

๊ธฐ์กด ํ…Œ์ด๋ธ”, ์Šคํ‚ค๋งˆ์˜ ๊ฒฝ์šฐ ๋ณ„๋„๋กœ ์Šคํ‚ค๋งˆ๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋นผ์คฌ์ง€๋งŒ, nest์—์„œ๋Š” ๊ฐ ํ•ด๋‹นํ•˜๋Š” ํด๋” ๋‚ด์— ๊ฐ๊ฐ ๋งŒ๋“ค์–ด ์ฃผ๋Š”๋“ฏ. (์˜ˆ์‹œ๋กœ board๊ด€๋ จ entity๋Š” board ํด๋” ๋‚ด์— board.entity.ts๋ฅผ ์ƒ์„ฑ, user์— ๊ด€๋ จ๋œ entity๋Š” userํด๋”์— user.entity๋ฅผ ์ƒ์„ฑ)

์ด๊ฑด cli๋กœ ์ง€์›ํ•˜์ง€์•Š๊ธฐ๋•Œ๋ฌธ์— ์ง์ ‘ ํด๋”์— ํŒŒ์ผ ์ƒ์„ฑ์„ ํ•ด์ค˜์•ผํ•œ๋‹ค.

์•„๋ž˜๋Š” article๊ณผ ๊ด€๋ จ๋œ ์˜ˆ์‹œ์ด๋‹ค.

// article.entity.ts
import {
  Column,
  CreateDateColumn,
  DeleteDateColumn,
  Entity,
  PrimaryGeneratedColumn,
  UpdateDateColumn,
} from "typeorm";

@Entity({ schema: "board", name: "articles" })
export class Article {
  @PrimaryGeneratedColumn({ type: "int", name: "id" })
  id: number;

  @Column("varchar", { length: 10 })
  author: string;

  @Column("varchar", { length: 50 })
  title: string;

  @Column("varchar", { length: 1000 })
  content: string;

  @Column("varchar", { select: false })
  password: string;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @DeleteDateColumn()
  deletedAt: Date | null;
}

โœ”๏ธ Repository ์ƒ์„ฑ

nest์—์„œ Repository๋Š” ๋‘๊ฐ€์ง€๋กœ ๋‚˜๋‰œ๋‹ค.
1. ์ผ๋ฐ˜ ๋ ˆํฌ์ง€ํ† ๋ฆฌ

  • ์ฃผ๋กœ ORM (Object-Relational Mapping) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ ๋ ˆํฌ์ง€ํ† ๋ฆฌ.
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ CRUD(Create, Read, Update, Delete) ์ž‘์—…์„ ๋””ํดํŠธ ์ œ๊ณต๋˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฒ˜๋ฆฌ
  • ์•„๋ž˜ ์ผ๋ฐ˜ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ช…์„ธ๋ฅผ ๋ณด๋ฉด์„œ ์–ด๋Š ์˜์—ญ๊นŒ์ง€ ์ผ๋ฐ˜ ๋ ˆํฌ์— ํ•ด๋‹น๋˜๋Š”์ง€ ํ™•์ธํ•˜๋ฉด ๋ ๋“ฏ.
    โœจ ์ผ๋ฐ˜ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ช…์„ธ โœจ

2. ์ปค์Šคํ…€ ๋ ˆํฌ์ง€ํ† ๋ฆฌ

  • ์‚ฌ์šฉ์ž ์ •์˜ ๋œ ๋ฉ”์„œ๋“œ๋‚˜ ์ฟผ๋ฆฌ๋ฅผ ํฌํ•จํ•˜์—ฌ ํŠน์ • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด๋‚˜ ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ๋ ˆํฌ์ง€ํ† ๋ฆฌ
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ž‘์„ฑํ•œ ์ถ”๊ฐ€ ๋ฉ”์„œ๋“œ ๋ฐ ์ฟผ๋ฆฌ๋ฅผ ์ œ๊ณต
  • ํŠน์ • ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๊ธฐ ์œ„ํ•ด ORM์˜ ์ œ๊ณต ๊ธฐ๋Šฅ ์ด์ƒ์˜ ์œ ์—ฐ์„ฑ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‚ฌ์šฉ
  • ์ผ๋ฐ˜ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ์‚ฐ์ด ๋ถ€์กฑํ•˜๋ฉด ์ผ๋ฐ˜ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ƒ์†ํ•œ ์ปค์Šคํ…€ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋จ.


โœ”๏ธ Repository์˜ ์˜์กด์„ฑ ์ฃผ์ž… -> Service ํŒŒ์ผ

  • service ํŒŒ์ผ ์ˆ˜์ •
  constructor(
    @InjectRepository(Article) private articleRepository: Repository<Article>
  ) {}

  • module ํŒŒ์ผ ์ˆ˜์ •
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { Article } from "./article.entity";
import { BoardController } from "./board.controller";
import { BoardService } from "./board.service";

@Module({
  // โญโญโญ ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉํ•  ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์‚ฌ์šฉ์„ imports์— ๋„ฃ์–ด์ฃผ๊ธฐ โญโญโญ 
  imports: [TypeOrmModule.forFeature([Article])],
  controllers: [BoardController],
  providers: [BoardService],
})
export class BoardModule {}
profile
์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ๋ฟ ๋‚ด๊ฐ€ ๋ชปํ•  ๊ฑด ์—†๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€