W14D4,5 TypeORM

Jin Bae·2023년 2월 20일
0

스파르타코딩클럽

목록 보기
34/35

TypeORM is an ORM that can be used in Typescript.

Setup

Install TypeORM (TypeORM v0.3.0 is compatible with Windows apparently?):

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

If installation fails due to clashing with class-validator, try:

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

Import and add TypeORM settings to app.module.ts.

import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm' // Import TypeORM
import { AppController } from './app.controller'
import { AppService } from './app.service'
import { BoardModule } from './board/board.module'

@Module({
  imports: [
    BoardModule,
    // Import and add TypeORM settings
    TypeOrmModule.forRoot({ // forRoot declares to use the following settings in all modules
      //데이터베이스 설정
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'admin',
      password: 'password',
      database: 'board',
      entities: [],
      synchronize: true, // 개발 버전에서 스키마를 용이하게 수정하게 해준다 (production에서는 false로 수정 필요)
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Hiding the TypeORM settings

Hardcoding the config

Create a folder in /src named config, then create a file named typeorm.config.service.ts.

// src/config/typeorm.config.service.ts
import { Injectable } from "@nestjs/common";
import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from "@nestjs/typeorm";

@Injectable()
export class TypeOrmConfigService implements TypeOrmOptionsFactory {
  createTypeOrmOptions(): TypeOrmModuleOptions {
    return {
      type: "mysql",
      host: "localhost",
      port: 3306,
      username: "여러분들의 데이터베이스 아이디",
      password: "여러분들의 데이터베이스 비밀번호",
      database: "board", // 중요: board 데이터베이스는 미리 생성해놓아야 합니다!
      entities: [__dirname + "/**/*.entity{.ts,.js}"],
      synchronize: true, // Production 환경에서는 false로 설정해야 합니다.
    };
  }
}

Because this is a service, remember that it needs to be Injectable.

Change app.module.ts to the following:

// src/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 TypeOrmConfigService

@Module({
  imports: [
    BoardModule,
    TypeOrmModule.forRootAsync({ // When the useClass property is added, forRoot() changes to forRootAsync() because when the Nest.js app starts, it must follow an asynchronous connection to the database. In short, it allows to complete the database connection settings asynchronously, AND THEN start the app.
      //데이터베이스 설정
      useClass: TypeOrmConfigService,
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Hiding sensitive settings with the @nestjs/config package

To hide the settings for TypeORM, use @nestjs/config.

npm i @nestjs/config

Create .env in the root folder.
🔔 Remember this file must be included in .gitignore.

DATABASE_HOST='localhost',
DATABASE_PORT=3306,
DATABASE_USERNAME='admin',
DATABASE_PASSWORD='password',
DATABASE_NAME='board',

Import the .env settings to typeorm.config.service.ts.

import { Injectable } from '@nestjs/common'
import { ConfigService } from '@nestjs/config/dist' // Import ConfigService
import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from '@nestjs/typeorm'

@Injectable()
export class TypeOrmConfigService implements TypeOrmOptionsFactory {
  // Declare ConfigService as a constructor DI
  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: [],
      synchronize: true,
    }
  }
}

Update app.module.ts to use ConfigModule.

import { Module } from '@nestjs/common'
import { ConfigModule } from '@nestjs/config' // Import ConfigModule
import { ConfigService } from '@nestjs/config/dist' // Import ConfigService
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'

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }), //Import ConfigModule. Make sure this is declared first so that the .env file values are read before the TypeOrmConfigService settings are read
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      useClass: TypeOrmConfigService,
      inject: [ConfigService],
    }),
    BoardModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Creating the entity

Add article.entity.ts in /src.

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 }) // Select is set as false as the password is sensitive data
  password: string

  @CreateDateColumn()
  createdAt: Date

  @UpdateDateColumn()
  updatedAt: Date

  @DeleteDateColumn()
  deletedAt: Date | null // Aims to soft delete data. Getting deletedAt != null has the same effect as deleting data.
}

Adding the repository

To add the repository to board.service.ts, inject depdency in the constructor.

// Additional imports
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { Article } from './article.entity'

@Injectable()
export class BoardService {
  constructor(
    @InjectRepository(Article) private articleRepository: Repository<Article>,
  ) {}
  
  // Rest ommitted
}

Update board.module.ts.

// Additional import
import { Article } from './article.entity'

@Module({
  imports: [TypeOrmModule.forFeature([Article])], // Import the entity
  controllers: [BoardController],
  providers: [BoardService],
})

🔔 To use a repository in a certain module service, remember to add the imports property in the @Module decorator.

0개의 댓글