개발/library, framework

[NEST] custom repository

prpn97 2023. 8. 30. 07:32

서두

이전에 typeORM을 처음 익히면서 대부분의 포스팅이 nest관련된 것들이여서 express도 고작이였던 내게 버거웠던 기억이 난다. 그리고 그 당시에도 typeORM이 0.3이 나오면서 크게 달라져서 많은 사용자들이 난항을 겪었던 것들을 봤다. 

 

가장 큰 부분은, Custom Repository를 만드는 방식이다. 

이전에는 @EntityRepository() 에 변수로 repository를 넣어서 컨트롤러나 서비스 등에서 참조해서 사용했던 것 같은데, 아무튼 나는 애초에 이렇게도 써보지 않았기 때문에 중요한 것은, 이제 그럼 어떻게 해야 하는 것인가. 이다. 

 

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private readonly users: UserRepository,
  ) {}

처음에 이렇게 InjectRepository로 User entity를 주입했다.

그런데 이후 로직에서 typeORM의 find메서드로 간단하게 find({})하는 로직이였는데,

cannot read properties of undefined (reading 'find') 라는 에러를 확인했다. 

 해당 프로퍼티가 정의되지 않은 객체 또는 변수를 참조할 때, 객체나 변수의 값이 정의되지 않은 상태에서 프로퍼티를 참조하려 할 때 발생하는 에러다. find해서 가져왔는데 값이 없는게 아니다. 

 

보통 흔히 보이는 경우는 메서드가 적용되지 않는 상황일 때 보였던 것 같다. 

typeOrm의 어쩌면 기본 중의 기본 메서드고 find 자체는 잘 불러오고 있는데 왜 적용되지 않는다는 것인가?

 

 

해결 과정

이전에 typeORM을 처음 익힐 때  봤던.. 서두에서 언급한 이슈가 떠올랐다. 

그래서 먼저 @InjectRepository()로 repository를 바로 가져오면서 정상적으로 실행되지 않는다고 판단했고, custom repository를 만드는 방법에 대해 구글링했다. 여러 가지 찾아보며 테스트해보니 @EntityRepository()를 대신하여 @CustomRepository를 직접 만드는 방법에 대해 알게 되었다. 

 

 

그저 따라할 줄 정도 아는 상태에서 설명하기보다는, 참고한 포스팅을 업로드하려 한다. 이후 과정들이 이해되고 구조가 파악되면 개선해서 포스팅해보려 한다. 그리고 아래에는 포스트에 나오지 않는 여러 api를 한 repository 안에 담는 방법에 대해 소개하려 한다. 

 

https://hou27.tistory.com/entry/Custom-repository%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%A0%95%EC%9D%98-%EB%A0%88%ED%8F%AC%EC%A7%80%ED%86%A0%EB%A6%AC-typeORM

 

TypeORM - Custom repository(사용자 정의 레포지토리)

여기로! 현재 더 나은 방법을 포스팅해두었습니다. TypeORM-Custom-Repository-개선안 - hou27 TypeORM - Custom Repository 개선안 이전 내용 사실 이전에 TypeORM이 0.3.x 버전 이상으로 올라가면서 @EntityRepository(User

hou27.tistory.com

 

 

여러 api를 한 repository 안에 추가하기

이게 어려운 일도 아니고, 당연히 한 repository 안에 추가할 수 있는 것 아닌가? 생각할 수 있지만,

customRepository를 정의하면서 위 방법을 사용하게 되면 지정한 커스텀 메서드에 대해서만 사용할 수가 있는데,

type을 선언하는 방법이 포스트에 명확치 않아서 소개한다. 

export interface DiagnosisListRepository
  extends Repository<DiagnosisListEntity> {
  this: Repository<DiagnosisListEntity>;

  getDiagnosisList(): Promise<any>;
  getOneDiagnosisById(id: number): Promise<any>;
}
type CustomDiagnosisListRepository = Pick<
  DiagnosisListRepository,
  'getDiagnosisList' | 'getOneDiagnosisById'
>;

export const customDiagnosisListRepositoryMethods: CustomDiagnosisListRepository =
  {
    async getDiagnosisList() {
      const data = await this.find({});
      return data;
    },

    async getOneDiagnosisById(id) {
      const data = await this.findOne({ where: { id } });
      return data;
    },
  };

 

1. DiagnosisListRepository는 Repository<DiagnosisListEntity>를 확장한다. 이것은 TypeORM에서 제공하는 제네릭 Repository를 상속받아서 DiagnosisListEntity 엔터티와 상호 작용하는데 사용된다.

 

2. CustomDiagnosisListRepository는 DiagnosisListRepository에서 사용할 메서드를 선택적으로 가져와서 타입을 정의한다. 이렇게 함으로써 해당 repository의 사용자 지정 버전을 정의하고 특정 메서드만 사용할 수 있게 된다.

 

예를 들어, CustomDiagnosisListRepository를 사용하면 getDiagnosisList와 getOneDiagnosisById 메서드만 사용할 수 있고, 다른 메서드들은 사용할 수 없다. 이는 코드를 모듈화하고 특정 repository에 대한 의존성을 제어하기 위한 방법 중 하나다.

 

그리고 여러 api를 repository안에서 정의하려면, DiagnosisRepository 인터페이스에서 추가한 뒤 TypeScript에서 제공하는 Pick이라는 유틸리티 타입을 사용하여 DiagnosisListRepository에서 특정 메서드만 선택적으로 가져온다. 그래서 아래에 api를 추가하면서 사용할 api를 문자열로 Pick에 추가해주면 된다. 

728x90