42Helper 오픈소스 프로젝트 (1) - 시간 중복 로직 추가
첫 번째 오픈소스 프로젝트는 42Helper입니다. 42Helper의 자세한 설명은 링크에서 확인해볼 수 있습니다.
제가 프로젝트에 기여한 첫 번째 부분인 시간 중복 로직에 관하여 설명드리겠습니다.
처음엔 이 부분을 Service로직으로 넣을지 아니면 Jpql로 직접 짤 것인지에 관해서 고민하였습니다.
두 가지 방법은 각각의 장점을 가지고 있습니다.
Jpql로 작성하는 경우에는 재활용성은 조금 떨어지고 쿼리문이 복잡하지만 서버 메모리의 부하를 줄여줄 수 있습니다.
User와 Team 테이블은 서로 참조하고 있지 않습니다.
왜냐하면 다대다 관계가 될 수 있기 때문에 중간에 Member를 중간에 둬서 일대다, 다대일 관계를 형성하였습니다.
그래서 Jpql로 짜면 쿼리문을 최소로 줄이고 한 번에 데이터들을 가져올 수 있습니다.
그러나 단점은 재활용성이 떨어진다는 단점이 있습니다. 중복 로직의 경우에는 많은 곳에서 다시 사용할 수 있기 때문입니다.
Serivce로 넣을 경우 위에서 말한 단점을 보완 할 수 있습니다.
그러나 많은 쿼리문이 나가야 된다는 단점이 있습니다.
User가 Team을 조회하고 싶은 경우에는 Member를 조회하고 그 Member들의 Team을 조회해야하기 때문입니다.
그래서 결과적으로는 처음에 Service로직을 이용했다가 Jpql이 깔끔하고 또 다른 곳에 로직을 복사해서 붙여쓰면 되기 때문에
Jpql로 작성하기로 했습니다. TeamService와 TeamRepository의 부분을 수정하였습니다.
<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편도 곧 올리겠습니다.
긴 글 읽어주셔서 감사합니다.