TypeORM is an ORM that can be used in Typescript.
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 {}
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 {}
@nestjs/config
packageTo 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 {}
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.
}
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.