타입스크립트 꽝꽝

[TypeScript] 인터페이스를 활용한 커스텀 Repository 만들기(w.typeorm)

bimppap 2022. 3. 9. 00:48

이전 게시물에서 커스텀 레포지토리를 활용한다고 했다.

 

typeorm에서 커스텀 레포지토리 문서를 제공하긴 하나 typeorm에 지나치게 의존하게 된다는 느낌이 들어 인터페이스를 활용해보기로 했다.

 

인터페이스 user.repository.ts

export interface UserRepository {

  findById(id: number): Promise<User | undefined>;

}
  • 인터페이스를 사용하게 된 이유?
    - 확장성. typeorm 구현체를 사용하게 될 경우, 다른 orm 라이브러리로 갈아타게 될 일이 생길 때 리팩토링 비용이 많이 들 것이다. 또한 typeorm에서만 통하는 문법이 있어 다른 개발자가 봤을 때 이해하기까지 시간이 더 걸릴 수 있다. 이에 공통으로 통용되는 방식을 차용해 접근성을 높이고, 다른 라이브러리로 갈아타기 쉽도록 인터페이스를 사용하게 되었다.

 

구현체 typeorm-user.repository.ts

@EntityRepository(User)
export class TypeormUserRepository
  extends BaseRepository<User>
  implements UserRepository
{
  async findById(id: number): Promise<User | undefined> {
    return await this.findOne({ id: id});
  }
}
  • @EntityRepository(T)
    - typeorm에서 제공하는 커스텀 레포지토리 데코레이터
  • BaseRepository<T>
    - typeorm-trasactional-cls-hooked 라이브러리를 쓸 경우 Repository<T> 대신 사용
    - 레포지토리를 사용하지 않는 경우 getRepository(T)로 대체할 수 있다.
  • findOne()
    - typeorm 레포 제공 메소드로, 조건을 만족하는 값을 하나 가져온다
    - 이런... typeorm에서만 통하는 메소드명 때문에 인터페이스로 확장하게 되었다

 

사용 예시

 

서비스 UserService

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(TypeormUserRepository)
    private readonly userRepository: UserRepository,
  ) {}
  
  @Transactional()
  async saveUser(user: User): Promise<User> {
    return this.menuRepository.save(user);
 }
  

  async findUser(id: number): Promise<User> {
    return await this.userRepository.findById(id);
  }
}

저기서 @InjectRepository를 빼고 모듈을 아래처럼 짜면 주입이 될 줄 알았는데...

잘 되지 않았다... 

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UserController],
  providers: [
    UserService,
    { provide: 'UserRepository', useClass: TypeormUserRepository },
  ],
})
export class UserModule {}

자바 스프링처럼 하고 싶었던 꿈은 물 건너로ㅠㅠ

결과적으로 모듈은 아래처럼 쓰였다.

 

user.module.ts

@Module({
  imports: [TypeOrmModule.forFeature([TypeormUserRepository])],
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

 

원하는 만큼 의존성을 걷어내진 못했지만 이 정도면 충분하다고 본다. 

사실 타입 스크립트 클린 아키텍쳐를 참고하면 가능할 것 같긴 하지만... 프로덕션도 아닌 과제에서 이렇게까지 할 필요가 있나 싶어서ㅎ

기회가 된다면 참고해서 다시 해보는 걸로...^ㅡ^

 

 

참고자료

 

https://clownhacker.tistory.com/250

 

NestJS Custom repository

개요  TypeORM의 Custom Repository를 이용해서 Active Recorder에 없는 method를 추가할 것이다. categories/repositories/category.repository.ts import { EntityRepository, Repository } from 'typeorm'; im..

clownhacker.tistory.com

https://stackoverflow.com/questions/63988821/nestjs-inject-custom-typeorm-repository-based-on-an-interface

 

NestJS inject custom TypeOrm repository based on an Interface

I'm currently working through the database integration docs for NestJS using TypeOrm. In these docs there are examples that show how to inject a custom database repository using the app.module from

stackoverflow.com