본문 바로가기

JavaScript & TypeScript

[NestJS] 쿼리빌더를 사용한 코드 리팩토링 (feat.TypeORM)

쿼리빌더를 사용해서 코드 리팩토링 한 것을 알아보기 전에,

우선 어떤 작업인지 간단하게 설명하겠습니다.

 

현재 개발하고 있는 서비스는 학원을 관리하는 LMS 서비스로

수업을 조회하는 부분에서 필터링이 필요했습니다.

 

수업 상태를 기준으로 전체, 수업 예정/ 진행중, 수업 종료 3가지에 상태가 있고

수업 종류를 기준으로 전체, 정규 클래스, 원데이 클래스 3가지 종류가 있었습니다.

 

처음에는 switch case문을 중첩으로 사용하여 아래와 같이 짰는데요..

async findAll(pageRequest: ArtClassPageRequest, currentAcademy: Academy) {
    let getRes: ArtClass[];

    const [artClasses, count] = await this.artClassRepository.findAndCountByAcademy(currentAcademy, pageRequest);

    switch (artClassStatus) {
      // 모든 수업
      case ArtClassStatus.ALL: {
        switch (artClassType) {
          case ArtClassType.ALL: {
            getRes = await this.artClassRepository.find({
              where: {
                academy: currentAcademy,
              },
            });
            break;
          }
          case ArtClassType.REGULAR: {
            getRes = await this.artClassRepository.find({
              where: {
                academy: currentAcademy,
                type: ArtClassType.REGULAR,
              },
            });
            break;
          }
          case ArtClassType.ONE_DAY: {
            getRes = await this.artClassRepository.find({
              academy: currentAcademy,
              type: ArtClassType.ONE_DAY,
            });
            break;
          }
        }
        break;
      }

      // 예정이거나 진행중인 수업
      case ArtClassStatus.IN_PROGRESS: {
        switch (artClassType) {
          case ArtClassType.ALL: {
            getRes = await this.artClassRepository.find({
              where: {
                academy: currentAcademy,
                endDate: MoreThan(moment().format()),
              },
            });
            break;
          }
          case ArtClassType.REGULAR: {
            getRes = await this.artClassRepository.find({
              where: {
                academy: currentAcademy,
                type: ArtClassType.REGULAR,
                endDate: MoreThan(moment().format()),
              },
            });
            break;
          }
          case ArtClassType.ONE_DAY: {
            getRes = await this.artClassRepository.find({
              academy: currentAcademy,
              type: ArtClassType.ONE_DAY,
              endDate: MoreThan(moment().format()),
            });
            break;
          }
        }
        break;
      }

      // 종료된 수업
      case ArtClassStatus.FINISHED: {
        switch (artClassType) {
          case ArtClassType.ALL: {
            getRes = await this.artClassRepository.find({
              where: {
                academy: currentAcademy,
                endDate: LessThan(moment().format()),
              },
            });
            break;
          }
          case ArtClassType.REGULAR: {
            getRes = await this.artClassRepository.find({
              where: {
                academy: currentAcademy,
                type: ArtClassType.REGULAR,
                endDate: LessThan(moment().format()),
              },
            });
            break;
          }
          case ArtClassType.ONE_DAY: {
            getRes = await this.artClassRepository.find({
              academy: currentAcademy,
              type: ArtClassType.ONE_DAY,
              endDate: LessThan(moment().format()),
            });
            break;
          }
        }

        break;
      }
    }

    return getRes;
  }

위에 보이시는 것과 같이 수업 상태를 switch case문을 사용하여 바깥에서 감싸고,

수업 종류에 해당하는 분기 처리를 위해 switch case문을 한번 더 사용한 것을 볼 수 있습니다.

 

이것이 너무 비효율적이고, 코드도 길어서 쿼리빌더를 이용해서 리팩토링 해보았는데요.

1. 쿼리빌더 생성

2. 수업 상태(예정/진행, 종료)에 따라 쿼리 빌더 값의 where절에 들어갈 조건을 적용

3. 수업 종류(정규, 원데이)에 따라 쿼리 빌더에 andWhere절의 조건을 동적으로 할당해서 리팩토링 해보았습니다.

async findAndCountByAcademy(academy: Academy, pageRequest: ArtClassPageRequest) {
    const queryBuilder = createQueryBuilder(ArtClass, 'artClass')
    .leftJoinAndSelect('artClass.teachers', 'teacher')
    .leftJoinAndSelect('artClass.artClassTimes', 'artClassTime');

    switch(pageRequest.status) {
      case ArtClassStatus.IN_PROGRESS:
        queryBuilder.where('artClass.end_date >= :now_date', { now_date: moment().format()});
        break;
      case ArtClassStatus.FINISHED:
        queryBuilder.where('artClass.end_date < :now_date', { now_date: moment().format()});
        break;
    }
    

    if(pageRequest.type){
      queryBuilder.andWhere(`artClass.type= '${pageRequest.type}'`);
    }

    if(pageRequest.pagingMode) {
      queryBuilder.take(pageRequest.limit).skip(pageRequest.offset);
    }

    return queryBuilder.getManyAndCount();
  }

 

완벽한 방법은 아니지만, 한결 간결해진 코드를 볼 수 있습니다.

 

좋은 방법이 있다면 댓글로 달아주시면 감사하겠습니다!