Repository 생성에 쓰인 @EntityRepository 데커레이터가 삭제되면서,
Repository 생성을 위한 CustomRepository을 공부한 기록이다.
개요
전체적인 Repository의 구조와 역할에 대해서는 지난 기록에서 다뤘다.
이번 기록에서는 커스텀 모듈, 데커레이터 생성에 대해 기록하려고 한다.
지난 기록에서 볼 수 있듯 Repository는 Repository Pattern을 구현하기 위해 생성한다.
Repository Pattern은 쉽게 말해, 서비스 파일에서의 비즈니스 로직에서 DB 관련 로직을 분리하는 패턴이다.
즉, Repository에서 반드시 이루어져야 하는 작업은 entity와 연결되는 작업이다.(꼭 기억하자!)
커스텀 데커레이션
먼저 Repository 클래스임을 선언해 줄 클래스 데커레이션을 생성해 보자.
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);
}
SetMetadata 메서드를 통해 key, value 쌍으로 문자열과 entity를 저장해 줌으로써,
해당 Repository의 메타데이터를 설정해 줬다.
Meta data
메타 데이터는 쉽게 말해 데이터의 데이터다.
데이터에 대한 설명을key, value 쌍으로 나타낸 데이터이다.
동적 모듈 생성
이제 가장 중요한 Repository를 entity와 연결해주는 작업이다.
이 작업을 동적 모듈을 통해 구현해 줄 것이다.
동적 모듈은 쉽게 말해 모듈이 provider가 구성되는 방식에 영향을 주는
동적으로 provider를 설정하는 모듈이다.
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,
};
}
}
위 모듈에서의 핵심은 repository 배열을 인자로 전달받고,
repository의 meta data에서 entity를 가져와 둘을 연결해주는 작업이다.
for (const repository of repositories) {
const entity = Reflect.getMetadata(
TYPEORM_EX_CUSTOM_REPOSITORY,
repository,
);
Reflect.getMetadata를 통해 런타임에 meta data를 가져옴으로써
동적 모듈을 구현할 수 있게 했다.
meta data에서 repository를 통해 setMetadata의 value였던 entity를 가져온다.
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,
);
},
});
}
getDataSourceToken을 통해 Data Source 타입을 가져온다.
해당 타입을 통해 위에 보이는 getRepository 메서드를 사용할 수 있는데
이 메서드가 반환하는 값이 바로
entity와 연결된 repository
참고
마무리
얕게 이해한 정도라 부족한 점이 많습니다.
잘못된 정보 등의 피드백은 환영입니다.
감사합니다.
'Backend > NestJS' 카테고리의 다른 글
[NestJS]JWT(2) Guards, Passport에 대한 이해 (0) | 2023.01.07 |
---|---|
[NestJS] JWT(1) 기본 개념, 구현 (0) | 2023.01.07 |
[NestJS] TypeORM, Entity, Repository 구조(NestJS PostgresSQL 적용) (1) | 2023.01.03 |
[NestJS] NestJS 유효성 파이프 적용 이해하기(ValidationPipe) (0) | 2023.01.01 |
[NestJS] User API 만들기(3) (파이프 Pipe 유효성 검사) (0) | 2022.12.30 |