저번의 생각을 토대로, 조금 더 최적화를 해보려고 했다.
일단 처음의 코드를 보자면,
private BooleanExpression usernameEq(String username, SearchType searchType){
if(username == null || username.isEmpty() || username.isBlank()) return null;
if(searchType.equals(CONTAINS)) return member.username.contains(username);
return member.username.eq(username);
}
private BooleanExpression nicknameEq(String nickname, SearchType searchType){
if(nickname == null || nickname.isEmpty() || nickname.isBlank()) return null;
if(searchType.equals(CONTAINS)) return member.nickname.contains(nickname);
return member.nickname.eq(nickname);
}
private BooleanExpression emailEq(String email, SearchType searchType){
if(email == null || email.isEmpty() || email.isBlank()) return null;
if(searchType.equals(CONTAINS)) return member.email.contains(email);
return member.email.eq(email);
}
이런식으로 만들어서 모든 메서드를 ','(and 연산)으로 추가했는데, 이렇게 되었을 때,
파라미터를 정확히 알지 못하는 상태에서는 아무것도 구하지 못할 것 이라는 문제가 있었다.
개인적으로, 한 멤버가 다른 멤버를 검색할 때에는, 정확한 정보를 몰라서 검색하는 것이라고 생각한다.
그러면, and연산보다는 or로 많더라도 데이터를 전부 보여주는게 좋지 않을까 라는 생각이 들었다.
private BooleanBuilder searchCondition(SearchMemberDto searchMemberDto, SearchType searchType){
BooleanBuilder builder = new BooleanBuilder();
if(StringUtils.hasText(searchMemberDto.getUsername())){
builder.or(queryUsername(searchMemberDto.getUsername(), searchType));
}
if(StringUtils.hasText(searchMemberDto.getNickname()))
builder.or(queryNickname(searchMemberDto.getNickname(), searchType));
if(StringUtils.hasText(searchMemberDto.getEmail()))
builder.or(queryEmail(searchMemberDto.getEmail(), searchType));
return builder;
}
private Predicate queryUsername(String username, SearchType searchType){
if(searchType.equals(EXACT))
return member.username.eq(username);
return member.username.contains(username);
}
private Predicate queryNickname(String nickname, SearchType searchType){
if(searchType.equals(EXACT))
return member.nickname.eq(nickname);
return member.nickname.contains(nickname);
}
private Predicate queryEmail(String email, SearchType searchType){
if(searchType.equals(EXACT))
return member.email.eq(email);
return member.email.contains(email);
}
이렇게 기능을 만들어서, 검색할 파라미터를 가지고, searchType을 토대로 쿼리를 다르게 만드는 코드를 만들어보았다.
이렇게 했을 때 문제를 생각해보면,
- Username
- 내용이 존재하는가?
- SearchType이 어떤가?
- SearchType에 맞는 쿼리문 반환
- SearchType이 어떤가?
- 내용이 존재하는가?
- Nickname
- 내용이 존재하는가?
- SearchType이 어떤가?
- SearchType에 맞는 쿼리문 반환
- SearchType이 어떤가?
- 내용이 존재하는가?
- Email
- 내용이 존재하는가?
- SearchType이 어떤가?
- SearchType에 맞는 쿼리문 반환
- SearchType이 어떤가?
- 내용이 존재하는가?
이게 반복되는 문제가 있다.
처음에 SearchType을 한번만 체크하고, 검색값을 가지고 바로 쿼리를 만들면서, 코드를 더 깔끔하게 쓸 수 있는 방법이 무엇일까를
조금 더 생각해보았다.
private BooleanBuilder searchCondition(SearchMemberDto searchMemberDto, SearchType searchType){
if(searchType.equals(EXACT)) return exactSearch(searchMemberDto);
return containsSearch(searchMemberDto);
}
private BooleanBuilder exactSearch(SearchMemberDto searchMemberDto) {
BooleanBuilder builder = new BooleanBuilder();
if(hasText(searchMemberDto.getUsername())) builder.or(member.username.eq(searchMemberDto.getNickname()));
if(hasText(searchMemberDto.getNickname())) builder.or(member.nickname.eq(searchMemberDto.getNickname()));
if(hasText(searchMemberDto.getEmail())) builder.or(member.email.eq(searchMemberDto.getEmail()));
return builder;
}
private BooleanBuilder containsSearch(SearchMemberDto searchMemberDto){
BooleanBuilder builder = new BooleanBuilder();
if(hasText(searchMemberDto.getUsername())) builder.or(member.username.contains(searchMemberDto.getNickname()));
if(hasText(searchMemberDto.getNickname())) builder.or(member.nickname.contains(searchMemberDto.getNickname()));
if(hasText(searchMemberDto.getEmail())) builder.or(member.email.contains(searchMemberDto.getEmail()));
return builder;
}
이렇게 되었을 때, 그 차이점을 보자면,
- SearchType에 따라 만드는 방식을 정한다.
- Username
- 내용이 존재하는가?
- 반환
- 내용이 존재하는가?
- Nickname
- 내용이 존재하는가?
- 반환
- 내용이 존재하는가?
- Email
- 내용이 존재하는가?
- 반환
- 내용이 존재하는가?
- Username
이렇게 보면, 내용상에 큰 차이는 없어 보일 수 있지만,
결국 하나의 결과까지 오는데, if문을 얼마나 타야할까? 를 생각해보면 이렇게 만든 이유를 알 수 있다.
쩌어 위에 코드는 쿼리문을 만드는데 까지, if문을 6번을 타게 된다.
하지만 방금 코드는 쿼리문을 만드는데 까지, if문을 4번을 타게 된다.
.
..
...
그렇다.
6은 4보다 크다!!!
이렇게 만든 후에, MemberRepositoryTest_Search_Contains를 제대로 동작시켜보았다.
이렇게 기존의 테스트는 잘 동작되는 것을 확인했다.
이제, 정말 or로 입력한 데이터와 동일한게 모두 나오는가를 체크해봐야겠다.
'스프링 공부 > 게시판 프로젝트 만들기' 카테고리의 다른 글
[스프링] 31. MemberController-회원가입 기능 구현하기, Null/Success 테스트 (0) | 2023.02.12 |
---|---|
[스프링] 30. MemberRepositoryTest_Search_Contains에서 검색조건이 서로 다른 객체를 향하는 거라면 잘될까 (0) | 2023.02.10 |
[스프링] 28. MemberService까지 만들고의 회고, 그리고 search를 마지막까지 다듬어보자!! (0) | 2023.02.09 |
[스프링] 27. MemberService.search의 기능을 조금 더 다양하게 만들어보기(페이징, like이용) (0) | 2023.02.09 |
[스프링] 26. MemberService : 로그인 로직 만들기 (0) | 2023.02.08 |