Skip to content

Commit

Permalink
�feat: 방 검색 기능 구현 (#121)
Browse files Browse the repository at this point in the history
* feat: 검색 Native Query 작성

* feat: 방 검색 서비스 기능 구현

* test: 방 검색 서비스 테스트

* feat: 방 검색 컨트롤러 구현

* test: 방 컨트롤러 통합 테스트 구현

* refactor: 파라미터 타입 통일화

* refactor: controller 타입 수정
  • Loading branch information
Shin-Jae-Yoon authored Nov 20, 2023
1 parent cf6070f commit fb060f9
Show file tree
Hide file tree
Showing 8 changed files with 361 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.moabam.api.domain.room.Routine;
import com.moabam.api.domain.room.repository.CertificationsSearchRepository;
import com.moabam.api.domain.room.repository.ParticipantSearchRepository;
import com.moabam.api.domain.room.repository.RoomRepository;
import com.moabam.api.domain.room.repository.RoomSearchRepository;
import com.moabam.api.domain.room.repository.RoutineSearchRepository;
import com.moabam.api.dto.room.CertificationImageResponse;
Expand All @@ -54,6 +55,7 @@ public class RoomSearchService {
private final ParticipantSearchRepository participantSearchRepository;
private final RoutineSearchRepository routineSearchRepository;
private final RoomSearchRepository roomSearchRepository;
private final RoomRepository roomRepository;
private final MemberService memberService;
private final RoomCertificationService roomCertificationService;
private final NotificationService notificationService;
Expand Down Expand Up @@ -116,7 +118,38 @@ public RoomsHistoryResponse getJoinHistory(Long memberId) {
public SearchAllRoomsResponse searchAllRooms(@Nullable RoomType roomType, @Nullable Long roomId) {
List<SearchAllRoomResponse> searchAllRoomResponses = new ArrayList<>();
List<Room> rooms = new ArrayList<>(roomSearchRepository.findAllWithNoOffset(roomType, roomId));
boolean hasNext = isHasNext(searchAllRoomResponses, rooms);

return RoomMapper.toSearchAllRoomsResponse(hasNext, searchAllRoomResponses);
}

public SearchAllRoomsResponse search(String keyword, @Nullable RoomType roomType, @Nullable Long roomId) {
List<SearchAllRoomResponse> searchAllRoomResponses = new ArrayList<>();
List<Room> rooms = new ArrayList<>();

if (roomId == null && roomType == null) {
rooms = new ArrayList<>(roomRepository.searchByKeyword(keyword));
}

if (roomId == null && roomType != null) {
rooms = new ArrayList<>(roomRepository.searchByKeywordAndRoomType(keyword, roomType.name()));
}

if (roomId != null && roomType == null) {
rooms = new ArrayList<>(roomRepository.searchByKeywordAndRoomId(keyword, roomId));
}

if (roomId != null && roomType != null) {
rooms = new ArrayList<>(
roomRepository.searchByKeywordAndRoomIdAndRoomType(keyword, roomType.name(), roomId));
}

boolean hasNext = isHasNext(searchAllRoomResponses, rooms);

return RoomMapper.toSearchAllRoomsResponse(hasNext, searchAllRoomResponses);
}

private boolean isHasNext(List<SearchAllRoomResponse> searchAllRoomResponses, List<Room> rooms) {
boolean hasNext = false;

if (rooms.size() > ROOM_FIXED_SEARCH_SIZE) {
Expand All @@ -138,8 +171,7 @@ public SearchAllRoomsResponse searchAllRooms(@Nullable RoomType roomType, @Nulla
RoomMapper.toSearchAllRoomResponse(room, RoutineMapper.toRoutineResponses(filteredRoutines),
isPassword));
}

return RoomMapper.toSearchAllRoomsResponse(hasNext, searchAllRoomResponses);
return hasNext;
}

private List<RoutineResponse> getRoutineResponses(Long roomId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ public static RoomDetailsResponse toRoomDetailsResponse(Long memberId, Room room
.managerNickName(managerNickname)
.roomImage(room.getRoomImage())
.level(room.getLevel())
.roomType(room.getRoomType().name())
.roomType(room.getRoomType())
.certifyTime(room.getCertifyTime())
.currentUserCount(room.getCurrentUserCount())
.maxUserCount(room.getMaxUserCount())
.announcement(room.getAnnouncement())
.completePercentage(completePercentage)
.certifiedDates(certifiedDates)
.routine(routineResponses)
.routines(routineResponses)
.todayCertificateRank(todayCertificateRankResponses)
.build();
}
Expand Down Expand Up @@ -103,7 +103,7 @@ public static SearchAllRoomResponse toSearchAllRoomResponse(Room room, List<Rout
.certifyTime(room.getCertifyTime())
.currentUserCount(room.getCurrentUserCount())
.maxUserCount(room.getMaxUserCount())
.routine(routineResponses)
.routines(routineResponses)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,46 @@
package com.moabam.api.domain.room.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.moabam.api.domain.room.Room;

public interface RoomRepository extends JpaRepository<Room, Long> {

@Query(value = "select distinct rm.* from room rm left join routine rt on rm.id = rt.room_id "
+ "where rm.title like %:keyword% "
+ "or rm.manager_nickname like %:keyword% "
+ "or rt.content like %:keyword% "
+ "order by rm.id desc limit 11", nativeQuery = true)
List<Room> searchByKeyword(@Param(value = "keyword") String keyword);

@Query(value = "select distinct rm.* from room rm left join routine rt on rm.id = rt.room_id "
+ "where (rm.title like %:keyword% "
+ "or rm.manager_nickname like %:keyword% "
+ "or rt.content like %:keyword%) "
+ "and rm.room_type = :roomType "
+ "order by rm.id desc limit 11", nativeQuery = true)
List<Room> searchByKeywordAndRoomType(@Param(value = "keyword") String keyword,
@Param(value = "roomType") String roomType);

@Query(value = "select distinct rm.* from room rm left join routine rt on rm.id = rt.room_id "
+ "where (rm.title like %:keyword% "
+ "or rm.manager_nickname like %:keyword% "
+ "or rt.content like %:keyword%) "
+ "and rm.id < :roomId "
+ "order by rm.id desc limit 11", nativeQuery = true)
List<Room> searchByKeywordAndRoomId(@Param(value = "keyword") String keyword, @Param(value = "roomId") Long roomId);

@Query(value = "select distinct rm.* from room rm left join routine rt on rm.id = rt.room_id "
+ "where rm.title like %:keyword% "
+ "or rm.manager_nickname like %:keyword% "
+ "or rt.content like %:keyword% "
+ "and rm.room_type = :roomType "
+ "and rm.id < :roomId "
+ "order by rm.id desc limit 11", nativeQuery = true)
List<Room> searchByKeywordAndRoomIdAndRoomType(@Param(value = "keyword") String keyword,
@Param(value = "roomType") String roomType, @Param(value = "roomId") Long roomId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.time.LocalDate;
import java.util.List;

import com.moabam.api.domain.room.RoomType;

import lombok.Builder;

@Builder
Expand All @@ -13,14 +15,14 @@ public record RoomDetailsResponse(
String managerNickName,
String roomImage,
int level,
String roomType,
RoomType roomType,
int certifyTime,
int currentUserCount,
int maxUserCount,
String announcement,
double completePercentage,
List<LocalDate> certifiedDates,
List<RoutineResponse> routine,
List<RoutineResponse> routines,
List<TodayCertificateRankResponse> todayCertificateRank
) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public record SearchAllRoomResponse(
int certifyTime,
int currentUserCount,
int maxUserCount,
List<RoutineResponse> routine
List<RoutineResponse> routines
) {

}
11 changes: 10 additions & 1 deletion src/main/java/com/moabam/api/presentation/RoomController.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,18 @@ public RoomsHistoryResponse getJoinHistory(@CurrentMember AuthorizationMember au

@GetMapping
@ResponseStatus(HttpStatus.OK)
public SearchAllRoomsResponse searchAllRooms(@RequestParam(value = "type", required = false) RoomType roomType,
public SearchAllRoomsResponse searchAllRooms(@RequestParam(value = "roomType", required = false) RoomType roomType,
@RequestParam(value = "roomId", required = false) Long roomId) {

return roomSearchService.searchAllRooms(roomType, roomId);
}

@GetMapping("/search")
@ResponseStatus(HttpStatus.OK)
public SearchAllRoomsResponse search(@RequestParam(value = "keyword") String keyword,
@RequestParam(value = "roomType", required = false) RoomType roomType,
@RequestParam(value = "roomId", required = false) Long roomId) {

return roomSearchService.search(keyword, roomType, roomId);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.moabam.api.application.room;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.anyList;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.spy;
import static org.mockito.BDDMockito.when;

import java.time.LocalDate;
import java.time.LocalDateTime;
Expand All @@ -21,6 +24,7 @@
import com.moabam.api.domain.room.Routine;
import com.moabam.api.domain.room.repository.CertificationsSearchRepository;
import com.moabam.api.domain.room.repository.ParticipantSearchRepository;
import com.moabam.api.domain.room.repository.RoomRepository;
import com.moabam.api.domain.room.repository.RoomSearchRepository;
import com.moabam.api.domain.room.repository.RoutineSearchRepository;
import com.moabam.api.dto.room.MyRoomsResponse;
Expand Down Expand Up @@ -52,6 +56,9 @@ class RoomSearchServiceTest {
@Mock
private RoomCertificationService certificationService;

@Mock
private RoomRepository roomRepository;

@DisplayName("유저가 참여중인 방 목록 조회 성공")
@Test
void get_my_rooms_success() {
Expand Down Expand Up @@ -304,4 +311,101 @@ void search_last_page_all_morning_night_rooms_success() {
assertThat(searchAllRoomsResponse.rooms().get(0).id()).isEqualTo(11L);
assertThat(searchAllRoomsResponse.rooms().get(3).id()).isEqualTo(14L);
}

@DisplayName("전체 방 제목, 방장 이름, 루틴 내용으로 검색 성공 - 최초 조회")
@Test
void search_room_by_title_manager_nickname_routine_success() {
// given
Room room1 = spy(RoomFixture.room("아침 - 첫 번째 방", RoomType.MORNING, 10, "1234"));
Room room2 = spy(RoomFixture.room("아침 - 두 번째 방", RoomType.MORNING, 9));
Room room3 = spy(RoomFixture.room("밤 - 세 번째 방", RoomType.NIGHT, 22));
Room room4 = spy(RoomFixture.room("아침 - 네 번째 방", RoomType.MORNING, 7));
Room room5 = spy(RoomFixture.room("밤 - 다섯 번째 방", RoomType.NIGHT, 23, "5869"));
Room room6 = spy(RoomFixture.room("아침 - 여섯 번째 방", RoomType.MORNING, 8));
Room room7 = spy(RoomFixture.room("밤 - 일곱 번째 방", RoomType.NIGHT, 20));
Room room8 = spy(RoomFixture.room("밤 - 여덟 번째 방", RoomType.NIGHT, 1, "5236"));
Room room9 = spy(RoomFixture.room("아침 - 아홉 번째 방", RoomType.MORNING, 4));
Room room10 = spy(RoomFixture.room("밤 - 열 번째 방", RoomType.NIGHT, 1, "97979"));
Room room11 = spy(RoomFixture.room("밤 - 열하나 번째 방", RoomType.NIGHT, 22));
Room room12 = spy(RoomFixture.room("아침 - 열둘 번째 방", RoomType.MORNING, 10));
Room room13 = spy(RoomFixture.room("밤 - 열셋 번째 방", RoomType.NIGHT, 2));
Room room14 = spy(RoomFixture.room("밤 - 열넷 번째 방", RoomType.NIGHT, 21));

given(room4.getId()).willReturn(4L);
given(room5.getId()).willReturn(5L);
given(room6.getId()).willReturn(6L);
given(room7.getId()).willReturn(7L);
given(room8.getId()).willReturn(8L);
given(room9.getId()).willReturn(9L);
given(room10.getId()).willReturn(10L);
given(room11.getId()).willReturn(11L);
given(room12.getId()).willReturn(12L);
given(room13.getId()).willReturn(13L);
given(room14.getId()).willReturn(14L);

List<Room> rooms = List.of(room4, room5, room6, room7, room8, room9, room10, room11, room12, room13, room14);

Routine routine9 = spy(RoomFixture.routine(room5, "방5의 루틴1"));
Routine routine10 = spy(RoomFixture.routine(room5, "방5의 루틴2"));

Routine routine11 = spy(RoomFixture.routine(room6, "방6의 루틴1"));
Routine routine12 = spy(RoomFixture.routine(room6, "방6의 루틴2"));

Routine routine13 = spy(RoomFixture.routine(room7, "방7의 루틴1"));
Routine routine14 = spy(RoomFixture.routine(room7, "방7의 루틴2"));

Routine routine15 = spy(RoomFixture.routine(room8, "방8의 루틴1"));
Routine routine16 = spy(RoomFixture.routine(room8, "방8의 루틴2"));

Routine routine17 = spy(RoomFixture.routine(room9, "방9의 루틴1"));
Routine routine18 = spy(RoomFixture.routine(room9, "방9의 루틴2"));

Routine routine19 = spy(RoomFixture.routine(room10, "방10의 루틴1"));
Routine routine20 = spy(RoomFixture.routine(room10, "방10의 루틴2"));

Routine routine21 = spy(RoomFixture.routine(room11, "방11의 루틴1"));
Routine routine22 = spy(RoomFixture.routine(room11, "방11의 루틴2"));

Routine routine23 = spy(RoomFixture.routine(room12, "방12의 루틴1"));
Routine routine24 = spy(RoomFixture.routine(room12, "방12의 루틴2"));

Routine routine25 = spy(RoomFixture.routine(room13, "방13의 루틴1"));
Routine routine26 = spy(RoomFixture.routine(room13, "방13의 루틴2"));

Routine routine27 = spy(RoomFixture.routine(room14, "방14의 루틴1"));
Routine routine28 = spy(RoomFixture.routine(room14, "방14의 루틴2"));

given(routine9.getId()).willReturn(9L);
given(routine10.getId()).willReturn(10L);
given(routine11.getId()).willReturn(11L);
given(routine12.getId()).willReturn(12L);
given(routine13.getId()).willReturn(13L);
given(routine14.getId()).willReturn(14L);
given(routine15.getId()).willReturn(15L);
given(routine16.getId()).willReturn(16L);
given(routine17.getId()).willReturn(17L);
given(routine18.getId()).willReturn(18L);
given(routine19.getId()).willReturn(19L);
given(routine20.getId()).willReturn(20L);
given(routine21.getId()).willReturn(21L);
given(routine22.getId()).willReturn(22L);
given(routine23.getId()).willReturn(23L);
given(routine24.getId()).willReturn(24L);
given(routine25.getId()).willReturn(25L);
given(routine26.getId()).willReturn(26L);

List<Routine> routines = List.of(routine9, routine10, routine11, routine12, routine13, routine14, routine15,
routine16, routine17, routine18, routine19, routine20, routine21, routine22, routine23, routine24,
routine25, routine26, routine27, routine28);

given(roomRepository.searchByKeyword("번째")).willReturn(rooms);
given(routineSearchRepository.findAllByRoomIds(anyList())).willReturn(routines);

// when
SearchAllRoomsResponse searchAllRoomsResponse = roomSearchService.search("번째", null, null);

// then
assertThat(searchAllRoomsResponse.hasNext()).isTrue();
assertThat(searchAllRoomsResponse.rooms()).hasSize(10);
}
}
Loading

0 comments on commit fb060f9

Please sign in to comment.