티스토리 뷰
데이터베이스 세팅
- 이번 연습 프로젝트에서는 비용에서 자유로운 RDBMS 중 하나인 postgreSQL을 사용해보기로 하였습니다.
postgreSQL 설치
- 다운로드 페이지에서 설치 파일을 다운로드 받은 뒤 진행하다보면 선택적으로 설치할 수 있는 파일 목록이 보이는데요!
- postgreSQL server: postgreSQL을 사용하기 위한 프로그램
- pgAdmin4: 데이터베이스 GUI
- Stack Builder: 여러 추가 프로그램을 설치할 수 있는 도구
- Command Line Tools: 명령어로 데이터베이스를 조작할 수 있는 도구
- 필요에 따라 선택적으로 설치를 하면 됩니다.
데이터베이스 생성
- Add New Server 를 눌러서 서버를 생성해봅시다.
- 서버 생성 화면
- port와 password는 postgreSQL 을 설치할 때 적었던 것과 동일하게 써야 합니다. port는 건드리지 않았다면 5432 일 것입니다.
- 그리고 그 외 host name이나 username 등은 typeORM 설치 후 설정을 할 때 필요한 것들이니 잊지 않도록 합니다!
- 서버가 생성되었으면 서버 내에 데이터베이스를 생성합니다.
- 위와 같은 화면이 나온다면 데이터베이스가 정상적으로 생성이 된 것입니다!
typeORM 세팅
- typeORM은 node.js 진영에서 사용하는 ORM 도구입니다. 자바의 JPA와 같은 역할을 하는 것이죠!
- nest.js에서 정의한 클래스를 관계형 데이터베이스와 연동시켜주어서 개발자가 일일이 테이블을 생성하거나 SQL 쿼리문을 작성하지 않아도 됩니다.
필요한 라이브러리 설치
npm install pg typeorm @nestjs/typeorm --save
- postgre(pg), typeorm 모듈과 nest.js에서 typeORM을 연동시키기 위한 모듈(@nestjs/typeorm) 까지 설치해줍니다!
typeORM 설정
- 설정 정보를 입력하는 방법은 여러가지 방법이 있습니다.
app.module.ts에 설정값 바로 넣기
// app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgre',
host: 'localhost',
port: 5432,
username: 'admin',
password: '1234',
database: 'test',
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
synchronize: true,
}),
],
})
export class AppModule {}
루트 디렉토리에 json 파일 생성
- 프로젝트의 루트 디렉토리에 json 파일을 생성하면 forRoot() 메소드가 인식을 할 수 있습니다.
// ormconfig.json
{
"type": "postgre",
"host": "localhost",
"port": 5432,
"username": "admin",
"password": "1234",
"database": "test",
"entities": [__dirname + '/../**/*.entity{.ts,.js}'],
"synchronize": true
}
// app.module.ts
@Module({
imports: [TypeOrmModule.forRoot()]
})
환경변수(.env) 이용하기
// .env
DB_USER=admin
DB_PASSWORD=1234
DB_PORT=5432
DB_HOST=localhost
DB_SCHEMA=test
ENTITY_PATH=__dirname + /../**/*.entity{.ts,.js}
// ormconfig.js
module.exports = {
type: 'postgre',
entities: [process.env.ENTITY_PATH],
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
host: process.env.DB_HOST,
database: process.env.DB_SCHEMA,
synchronize: true,
};
// app.module.ts
@Module({
imports: [TypeOrmModule.forRoot()]
})
configService 를 이용하는 방법
npm i --save @nestjs/config
- configService를 이용하기 위해서 필요한 패키지를 설치해줍니다.
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from '@nestjs/typeorm';
@Injectable()
export class MyConfigService implements TypeOrmOptionsFactory {
constructor(private configService: ConfigService) {}
createTypeOrmOptions(): TypeOrmModuleOptions {
return {
type: 'postgre',
username: this.configService.get<string>('DB_USER'),
password: this.configService.get<string>('DB_PASSWORD'),
port: +this.configService.get<number>('DB_PORT'),
host: this.configService.get<string>('DB_HOST'),
database: this.configService.get<string>('DB_SCHEMA'),
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
};
}
}
// /src/config/database/config.module.ts
import { Module } from '@nestjs/common';
import { MyConfigService } from './config.service';
@Module({
providers: [MyConfigService],
})
export class MyConfigModule {}
// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MyConfigModule } from './config/database/config.module';
import { MyConfigService } from './config/database/config.service';
import { UserModule } from './user/user.module';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
TypeOrmModule.forRootAsync({
imports: [MyConfigModule],
useClass: MyConfigService,
inject: [MyConfigService],
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
- 여기서 ConfigModule.forRoot({ isGlobal: true }) 는 모듈을 전역 모듈로 설정하겠다는 것입니다.
Entity 생성
- 이제 데이터베이스의 테이블이 될 엔티티를 생성해보겠습니다.
user.entity.ts
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
export enum UserRole {
ADMIN = 'admin',
MEMBER = 'member',
GHOST = 'ghost',
}
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column('varchar', { length: 15 })
username: string;
@Column('int')
age: number;
@Column({ type: 'enum', enum: UserRole, default: UserRole.GHOST })
role: UserRole;
}
- 여기서 @PrimaryGeneratedColumn() 은 자동으로 증가하는 primary key를 의미합니다. 스프링부트에서 @Id, @GeneratedValue(strategy = GenerationType.AUTO) 어노테이션을 붙여준 것과 같은 데코레이터라고 볼 수 있겠네요!
- 그 외에 테이블 컬럼에는 @Column 데코레이터를 사용해주면 되고 선택적으로 type을 비롯한 옵션들을 넣어줄 수 있습니다.
Repository 생성
- typeORM 0.3.0 버전부터는 기존에 사용되던 @EntityRepository 데코레이터가 deprecated 되었다고 합니다.
- EntityRepository를 대체할 수 있는 여러 방법들이 있었는데 그 중 custom decorator를 만들어서 사용하는 방법과 datasource의 createEntityManager() 메소드를 이용하는 방법을 정리해보았습니다.
custom decorator
custom repository decorator 생성
// db/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);
}
모듈 생성
// db/typeorm-ex.module
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,
};
}
}
- @CustomRepository 데코레이터가 적용될 repository를 받아줄 모듈입니다.
Reflect.getMetadata()
메서드로 메타데이터 키값인TYPEORM_EX_CUSTOM_REPOSITORY
에 해당되는 엔티티를 가져오고,- 메타데이터 키값에 해당하는 엔티티가 존재하는 경우 Factory를 이용하여 provider를 동적으로 생성하여 providers에 추가하는 역할을 합니다.
모듈 적용
@CustomRepository(User)
export class UserRepository extends Repository<User> {
...
}
모듈 설정
@Module({
imports: [
TypeOrmExModule.forCustomRepository([UserRepository]),
],
...
})
createEntityManager()
// user.repository.ts
import { Injectable } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class UserRepository extends Repository<User> {
constructor(datasource: DataSource) {
super(User, datasource.createEntityManager());
}
}
- 첫 번째 인자로 사용될 entity를 입력하고 두 번째 인자로 createEntityManager() 를 호출합니다.
// user.module.ts
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UserRepository } from './user.repository';
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UserController],
providers: [UserService, UserRepository],
})
export class UserModule {}
- 그리고 모듈에서 providers 안에 repository를 추가해줍니다!
데이터베이스 연동 확인
- npm start 를 통해 서버를 켜면 typeORM이 자동으로 CREATE 쿼리를 날려서 테이블을 생성하는 것을 볼 수 있습니다.
- pgAdmin 에서도 테이블과 컬럼들이 우리가 만든 Entity에 맞게 생성된 것을 확인할 수 있습니다!
반응형
'개발냥이 > Nest.js' 카테고리의 다른 글
[Nest.js] 라이프사이클(LifeCycle), 유틸리티 클래스(Utility class) (0) | 2024.01.15 |
---|---|
[Nest.js] 간단하게 CRUD 구현해보기! (1) | 2024.01.12 |
[Nest.js] 기본 구조 파악, Controller, Service 구현해보기 (1) | 2024.01.10 |
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 자바트리
- 백준
- 정렬
- BFS
- CS
- 이분탐색
- SQL
- 해시맵
- 알고리즘
- 형변환
- JavaScript
- SQLD
- 스프링부트
- dfs
- JPA
- DP
- Comparator
- java
- 자바dp
- 자바
- 스프링
- Algorithm
- 타입스크립트
- Spring
- 자바스크립트
- Nest
- 프로그래머스
- Queue
- 리액트
- 자바bfs
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함