오픈소스 프로젝트/42Helper

42Helper 오픈소스 프로젝트 (1) - 시간 중복 로직 추가

HOONY_612 2021. 10. 1. 17:19
반응형

첫 번째 오픈소스 프로젝트는 42Helper입니다. 42Helper의 자세한 설명은 링크에서 확인해볼 수 있습니다.

제가 프로젝트에 기여한 첫 번째 부분인 시간 중복 로직에 관하여 설명드리겠습니다.

 

처음엔 이 부분을 Service로직으로 넣을지 아니면 Jpql로 직접 짤 것인지에 관해서 고민하였습니다.

두 가지 방법은 각각의 장점을 가지고 있습니다.

 

Jpql로 작성하는 경우에는 재활용성은 조금 떨어지고 쿼리문이 복잡하지만 서버 메모리의 부하를 줄여줄 수 있습니다.

User와 Team 테이블은 서로 참조하고 있지 않습니다.

왜냐하면 다대다 관계가 될 수 있기 때문에 중간에 Member를 중간에 둬서 일대다, 다대일 관계를 형성하였습니다.

그래서 Jpql로 짜면 쿼리문을 최소로 줄이고 한 번에 데이터들을 가져올 수 있습니다.

그러나 단점은 재활용성이 떨어진다는 단점이 있습니다. 중복 로직의 경우에는 많은 곳에서 다시 사용할 수 있기 때문입니다.

 

Serivce로 넣을 경우 위에서 말한 단점을 보완 할 수 있습니다.

 그러나 많은 쿼리문이 나가야 된다는 단점이 있습니다. 

User가 Team을 조회하고 싶은 경우에는 Member를 조회하고 그 Member들의 Team을 조회해야하기 때문입니다.

 

그래서 결과적으로는 처음에 Service로직을 이용했다가 Jpql이 깔끔하고 또 다른 곳에 로직을 복사해서 붙여쓰면 되기 때문에

Jpql로 작성하기로 했습니다. TeamServiceTeamRepository의 부분을 수정하였습니다.

 

<TeamService>

        List<TeamStatus> statusList = new ArrayList<>();
        statusList.add(TeamStatus.REVOKE);
        statusList.add(TeamStatus.END);
        if (teamRepo.findTeamsByDuplicateDateTime(statusList, requestDto.getStartTime(), requestDto.getEndTime()).size() != 0)
            throw new IllegalArgumentException("Time Overlap");

<TeamService> 

    @Query("SELECT DISTINCT t FROM Team t " +
            "WHERE (t.status NOT IN (:statusList)) and " +
            "((t.period.startTime <= :startTime and t.period.endTime <= :endTime and t.period.endTime > :startTime) or" +
            "(t.period.startTime >= :startTime and t.period.endTime >= :endTime and t.period.startTime < :endTime) or" +
            "(t.period.startTime <= :startTime and t.period.endTime >= :endTime) or " +
            "(t.period.startTime >= :startTime and t.period.endTime <= :endTime))")
    List<Team> findTeamsByDuplicateDateTime(List<TeamStatus> statusList, LocalDateTime startTime, LocalDateTime endTime);

 

위의 코드를 설명하겠습니다. 

일단 처음에 TeamStatus문제입니다. TeamStatus는 총 7가지 상태를 가지고 있습니다.

그리고 그 중 REVOKE상태와 END는 팀을 생성했다가 삭제했거나 팀이 종료되었다는 상태입니다.

그래서 두 가지의 상태는 제외하고 체크를 해줘야합니다.

그래서 두 상태를 매개변수로 넘기기 보다는 List컬렉션을 만들어 넘겨줬습니다.

@Getter
@RequiredArgsConstructor
public enum TeamStatus {
    WAITING("STATUS_WAITING", "선택 대기중"),
    READY("STATUS_READY", "인원 모집중"),
    FULL("STATUS_FULL", "인원 모집 완료"),
    REVIEW("STATUS_REVIEW", "리뷰중"),
    END("STATUS_END", "종료"),
    TIMEOUT("STATUS_TIMEOUT", "만료"),
    REVOKE("REVOKE", "취소");

    private final String key;
    private final String name;
}

처음에 Jpql을 활용한 적이 없어 많이 어색했지만 이번을 계기로 잘 작성 할 수 있게되었습니다.

로직은 총 크게 4부분으로 나눠 작성하였습니다. 아래와 같이 4가지 부분을 로직으로 구현하였습니다.

만약 10/01일 6:00 ~ 18:00까지 프로젝트가 있을 경우에는 아래와 같이 시간이 겹치는 프로젝트는 생성 할 수 없습니다.

(t.period.startTime <= :startTime and t.period.endTime <= :endTime and t.period.endTime > :startTime)

(t.period.startTime <= :startTime and t.period.endTime >= :endTime)

(t.period.startTime >= :startTime and t.period.endTime >= :endTime and t.period.startTime < :endTime)

 

(t.period.startTime >= :startTime and t.period.endTime <= :endTime)

 

 

이렇게 시간 중복로직을 추가해 적용했습니다. 비록 테스트는 만들지 못하였지만 다음 기여에는 테스트까지 만들예정입니다.

이번 PR기여로 Jpql 로직 구현에 관한 공부를 심도있게 했습니다. 다음 2편도 곧 올리겠습니다.

긴 글 읽어주셔서 감사합니다.

반응형