From cbcc8bb71d03fa57c61f0b256d61db6bd2cb969b Mon Sep 17 00:00:00 2001 From: amaran-th Date: Thu, 5 Oct 2023 15:55:33 +0900 Subject: [PATCH 1/8] =?UTF-8?q?test:=20=ED=96=89=EC=82=AC=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=8A=A4=ED=8E=99=EC=9D=84=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=ED=99=94=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=97=90=20=EC=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #324 --- .../src/documentTest/java/com/emmsale/EventApiTest.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java index 5d919b0ce..521bca41a 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java @@ -127,6 +127,9 @@ void findEvents() throws Exception { RequestDocumentation.parameterWithName("tags").description("필터링하려는 태그(option)").optional(), RequestDocumentation.parameterWithName("statuses") .description("필터링하려는 상태(UPCOMING, IN_PROGRESS, ENDED)(option)") + .optional(), + RequestDocumentation.parameterWithName("keyword") + .description("검색하려는 키워드") .optional() ); @@ -156,11 +159,6 @@ void findEvents() throws Exception { ); final List eventResponses = List.of( - new EventResponse(1L, "인프콘 2023", LocalDateTime.parse("2023-06-03T12:00:00"), - LocalDateTime.parse("2023-09-03T12:00:00"), - List.of("백엔드", "프론트엔드", "안드로이드", "IOS", "AI"), "IN_PROGRESS", "ENDED", - "https://biz.pusan.ac.kr/dext5editordata/2022/08/20220810_160546511_10103.jpg", - 3, -30, EventMode.ONLINE.getValue(), PaymentType.PAID.getValue()), new EventResponse(5L, "웹 컨퍼런스", LocalDateTime.parse("2023-07-03T12:00:00"), LocalDateTime.parse("2023-08-03T12:00:00"), List.of("백엔드", "프론트엔드"), "IN_PROGRESS", "IN_PROGRESS", @@ -184,6 +182,7 @@ void findEvents() throws Exception { .param("start_date", "2023-07-01") .param("end_date", "2023-07-31") .param("statuses", "UPCOMING,IN_PROGRESS") + .param("keyword", "컨퍼") ) .andExpect(status().isOk()) .andDo(MockMvcRestDocumentation.document("find-events", requestParameters, responseFields)); From 6201a1b99b2aa6ea5c682aed0e9122a4f37ce95a Mon Sep 17 00:00:00 2001 From: amaran-th Date: Thu, 5 Oct 2023 16:36:03 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #324 --- .../java/com/emmsale/EventApiTest.java | 2 +- .../java/com/emmsale/event/api/EventApi.java | 6 ++-- .../event/application/EventService.java | 28 +++++++++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java b/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java index 521bca41a..141febbb9 100644 --- a/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java +++ b/backend/emm-sale/src/documentTest/java/com/emmsale/EventApiTest.java @@ -174,7 +174,7 @@ void findEvents() throws Exception { Mockito.when(eventService.findEvents(any(EventType.class), any(LocalDate.class), eq("2023-07-01"), eq("2023-07-31"), - eq(null), any())).thenReturn(eventResponses); + eq(null), any(), eq("컨퍼"))).thenReturn(eventResponses); // when & then mockMvc.perform(get("/events") diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java b/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java index c95630d3e..196481f24 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/api/EventApi.java @@ -43,9 +43,11 @@ public ResponseEntity> findEvents( @RequestParam(name = "start_date", required = false) final String startDate, @RequestParam(name = "end_date", required = false) final String endDate, @RequestParam(required = false) final List tags, - @RequestParam(required = false) final List statuses) { + @RequestParam(required = false) final List statuses, + @RequestParam(required = false) final String keyword) { return ResponseEntity.ok( - eventService.findEvents(category, LocalDate.now(), startDate, endDate, tags, statuses)); + eventService.findEvents(category, LocalDate.now(), startDate, endDate, tags, statuses, + keyword)); } @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java index 9c224395d..03981a92b 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java @@ -73,7 +73,7 @@ public EventDetailResponse findEvent(final Long id, final LocalDate today) { @Transactional(readOnly = true) public List findEvents(final EventType category, final LocalDate nowDate, final String startDate, final String endDate, - final List tagNames, final List statuses) { + final List tagNames, final List statuses, final String keyword) { Specification spec = Specification.where(filterByCategory(category)); if (isExistTagNames(tagNames)) { @@ -87,7 +87,7 @@ public List findEvents(final EventType category, validateEndDateAfterDateStart(startDateTime, endDateTime); spec = spec.and(EventSpecification.filterByPeriod(startDateTime, endDateTime)); } - final List events = eventRepository.findAll(spec); + final List events = filterBySearchKeyword(keyword, spec); final EnumMap> eventsForEventStatus = groupByEventStatus(nowDate, events); @@ -138,6 +138,30 @@ private void validateEndDateAfterDateStart(final LocalDateTime startDate, } } + private List filterBySearchKeyword(final String keyword, final Specification spec) { + List events = eventRepository.findAll(spec); + if (isExistKeyword(keyword)) { + final String[] keywords = keyword.split(" "); + events = events.stream() + .filter(event -> isEventNameContainTokenIn(event, keywords)) + .collect(toList()); + } + return events; + } + + private boolean isExistKeyword(final String keyword) { + return keyword != null && !keyword.trim().isEmpty(); + } + + private boolean isEventNameContainTokenIn(final Event event, final String[] keywords) { + for (String token : keywords) { + if (event.getName().contains(token)) { + return true; + } + } + return false; + } + private EnumMap> groupByEventStatus(final LocalDate nowDate, final List events) { return events.stream() From 1981b469092afbc7ce482b59671c4e7341ff2be2 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Thu, 5 Oct 2023 16:38:31 +0900 Subject: [PATCH 3/8] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EC=8B=9C=20=EB=B3=B5=EC=88=98=20=ED=86=A0=ED=81=B0?= =?UTF-8?q?=EC=9D=B4=20=EB=93=A4=EC=96=B4=EC=98=AC=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=20=EC=B2=98=EB=A6=AC=20=EB=B0=A9=EC=8B=9D?= =?UTF-8?q?=EC=9D=84=20or=EC=97=90=EC=84=9C=20and=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #324 --- .../java/com/emmsale/event/application/EventService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java index 03981a92b..c120ad4ce 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java @@ -155,11 +155,11 @@ private boolean isExistKeyword(final String keyword) { private boolean isEventNameContainTokenIn(final Event event, final String[] keywords) { for (String token : keywords) { - if (event.getName().contains(token)) { - return true; + if (!event.getName().contains(token)) { + return false; } } - return false; + return true; } private EnumMap> groupByEventStatus(final LocalDate nowDate, From f763276301fcdff2157f47dc2af022cc4e0b582d Mon Sep 17 00:00:00 2001 From: amaran-th Date: Thu, 5 Oct 2023 16:47:06 +0900 Subject: [PATCH 4/8] =?UTF-8?q?feat:=20=EA=B2=80=EC=83=89=20=ED=82=A4?= =?UTF-8?q?=EC=9B=8C=EB=93=9C=EC=9D=98=20=ED=86=A0=ED=81=B0=EC=9D=84=20?= =?UTF-8?q?=EC=AA=BC=EA=B0=9C=EA=B8=B0=20=EC=A0=84=EC=97=90=20trim()=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #324 --- .../main/java/com/emmsale/event/application/EventService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java index c120ad4ce..ad7f9e079 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java @@ -141,7 +141,7 @@ private void validateEndDateAfterDateStart(final LocalDateTime startDate, private List filterBySearchKeyword(final String keyword, final Specification spec) { List events = eventRepository.findAll(spec); if (isExistKeyword(keyword)) { - final String[] keywords = keyword.split(" "); + final String[] keywords = keyword.trim().split(" "); events = events.stream() .filter(event -> isEventNameContainTokenIn(event, keywords)) .collect(toList()); From af9062f95efc4c2b61a6594c2df4d8483c1cd12e Mon Sep 17 00:00:00 2001 From: amaran-th Date: Thu, 5 Oct 2023 17:01:46 +0900 Subject: [PATCH 5/8] =?UTF-8?q?test:=20=EA=B2=80=EC=83=89=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B2=80=EC=A6=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #324 --- .../event/application/EventServiceTest.java | 148 ++++++++++++++---- 1 file changed, 120 insertions(+), 28 deletions(-) diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java index 3de8d1caa..0230c02da 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java @@ -196,7 +196,7 @@ void findEvents_CONFERENCE() { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - null, null, null, null); + null, null, null, null, null); // then assertThat(actualEvents) @@ -213,7 +213,7 @@ void findEvents_COMPETITION() { // when final List actualEvents = eventService.findEvents(EventType.COMPETITION, TODAY, - null, null, null, null); + null, null, null, null, null); // then assertThat(actualEvents) @@ -230,7 +230,7 @@ void findEvents_2023_7() { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-07-01", "2023-07-31", null, null); + "2023-07-01", "2023-07-31", null, null, null); // then assertThat(actualEvents) @@ -247,7 +247,7 @@ void findEvents_2023_8() { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-08-01", "2023-08-31", null, null); + "2023-08-01", "2023-08-31", null, null, null); // then assertThat(actualEvents) @@ -264,7 +264,7 @@ void findEvents_2023_6() { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-06-01", "2023-06-30", null, null); + "2023-06-01", "2023-06-30", null, null, null); // then assertThat(actualEvents) @@ -281,7 +281,7 @@ void findEvents_after_2023_7_17() { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-07-17", null, null, null); + "2023-07-17", null, null, null, null); // then assertThat(actualEvents) @@ -298,7 +298,7 @@ void findEvents_before_2023_7_31() { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - null, "2023-07-31", null, null); + null, "2023-07-31", null, null, null); // then assertThat(actualEvents) @@ -316,8 +316,7 @@ void findEvents_empty(final List statusName) { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-12-01", "2023-12-31", null, - statusName); + "2023-12-01", "2023-12-31", null, statusName, null); // then assertThat(actualEvents).isEmpty(); @@ -328,7 +327,7 @@ void findEvents_empty(final List statusName) { void findEvents_2023_12() { // given, when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-12-01", "2023-12-31", null, null); + "2023-12-01", "2023-12-31", null, null, null); // then assertThat(actualEvents).isEmpty(); @@ -340,8 +339,7 @@ void findEvents_2023_12() { void findEvents_empty_tag_filter() { // given, when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-12-01", "2023-12-31", List.of("안드로이드"), - null); + "2023-12-01", "2023-12-31", List.of("안드로이드"), null, null); // then assertThat(actualEvents).isEmpty(); @@ -352,8 +350,7 @@ void findEvents_empty_tag_filter() { void findEvents_empty_status_filter() { // given, when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-12-01", "2023-12-31", null, - List.of(IN_PROGRESS)); + "2023-12-01", "2023-12-31", null, List.of(IN_PROGRESS), null); // then assertThat(actualEvents).isEmpty(); @@ -365,7 +362,7 @@ void findEvents_empty_status_filter() { void findEvents_start_date_fail(final String startDate) { // given, when final ThrowingCallable actual = () -> eventService.findEvents(EventType.CONFERENCE, TODAY, - startDate, "2023-07-31", null, null); + startDate, "2023-07-31", null, null, null); // then assertThatThrownBy(actual) @@ -379,7 +376,7 @@ void findEvents_start_date_fail(final String startDate) { void findEvents_end_date_fail(final String endDate) { // given, when final ThrowingCallable actual = () -> eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-07-01", endDate, null, null); + "2023-07-01", endDate, null, null, null); // then assertThatThrownBy(actual) @@ -392,7 +389,7 @@ void findEvents_end_date_fail(final String endDate) { void findEvents_start_after_end_fail() { // given, when final ThrowingCallable actual = () -> eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-07-16", "2023-07-15", null, null); + "2023-07-16", "2023-07-15", null, null, null); // then assertThatThrownBy(actual) @@ -408,8 +405,7 @@ void findEvents_tag_filter() { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - null, null, List.of("안드로이드"), - null); + null, null, List.of("안드로이드"), null, null); // then assertThat(actualEvents) @@ -426,8 +422,7 @@ void findEvents_tags_filter() { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - null, null, List.of("안드로이드", "백엔드"), - null); + null, null, List.of("안드로이드", "백엔드"), null, null); // then assertThat(actualEvents) @@ -441,7 +436,7 @@ void findEvents_tags_filter() { void findEvents_tag_filter_fail() { // given, when final ThrowingCallable actual = () -> eventService.findEvents(EventType.CONFERENCE, TODAY, - null, null, List.of("개발"), null); + null, null, List.of("개발"), null, null); // then assertThatThrownBy(actual) @@ -457,8 +452,7 @@ void findEvents_status_filter() { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - null, null, null, - List.of(IN_PROGRESS)); + null, null, null, List.of(IN_PROGRESS), null); // then assertThat(actualEvents) @@ -475,8 +469,7 @@ void findEvents_statuses_filter() { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - null, null, null, - List.of(EventStatus.UPCOMING, IN_PROGRESS)); + null, null, null, List.of(EventStatus.UPCOMING, IN_PROGRESS), null); // then assertThat(actualEvents) @@ -493,8 +486,7 @@ void findEvents_period_tags_filter() { // when final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-09-01", "2023-09-30", List.of("안드로이드", "백엔드"), - List.of(EventStatus.UPCOMING)); + "2023-09-01", "2023-09-30", List.of("안드로이드", "백엔드"), List.of(EventStatus.UPCOMING), null); // then assertThat(actualEvents) @@ -502,6 +494,106 @@ void findEvents_period_tags_filter() { .comparingOnlyFields("name", "status", "applyStatus") .isEqualTo(expectedEvents); } + + @Nested + @DisplayName("특정 키워드로 행사를 검색할 수 있다.") + class SearchEvent { + + @ParameterizedTest + @ValueSource(strings = {"", " ", " ", "\r", "\n", "\t"}) + @DisplayName("2023년 7월 21일에 컨퍼런스 행사를 조회할 때, 검색어가 공백인 경우 해당 카테고리에 해당하는 모든 행사 목록을 조회할 수 있다.") + void findEvents_blank_search(final String keyword) { + // given + final List expectedEvents = List.of(인프콘_2023, 웹_컨퍼런스, AI_컨퍼런스, 모바일_컨퍼런스, + 안드로이드_컨퍼런스); + + // when + final List actualEvents = eventService.findEvents(EventType.CONFERENCE, + TODAY, + null, null, null, null, keyword); + + // then + assertThat(actualEvents) + .usingRecursiveComparison() + .comparingOnlyFields("name", "status", "applyStatus") + .isEqualTo(expectedEvents); + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", "컨퍼", "인프콘"}) + @DisplayName("2023년 7월 21일에 컨퍼런스 행사를 조회할 때, 목록이 비어있을 때 어떤 키워드가 들어오든 빈 행사 목록을 반환한다.") + void findEvents_empty_events_search(final String keyword) { + // given + eventRepository.deleteAll(); + final List expectedEvents = List.of(); + + // when + final List actualEvents = eventService.findEvents(EventType.CONFERENCE, + TODAY, null, null, null, null, keyword); + + // then + assertThat(actualEvents) + .usingRecursiveComparison() + .comparingOnlyFields("name", "status", "applyStatus") + .isEqualTo(expectedEvents); + } + + @Test + @DisplayName("2023년 7월 21일에 컨퍼런스 행사를 조회할 때, 검색 키워드가 들어오면 이름에 해당 검색 키워드를 포함하고 있는 행사 목록을 조회할 수 있다.") + void findEvents_search() { + // given + final String keyword = " 컨퍼런스"; + final List expectedEvents = List.of(웹_컨퍼런스, AI_컨퍼런스, 모바일_컨퍼런스, + 안드로이드_컨퍼런스); + + // when + final List actualEvents = eventService.findEvents(EventType.CONFERENCE, + TODAY, null, null, null, null, keyword); + + // then + assertThat(actualEvents) + .usingRecursiveComparison() + .comparingOnlyFields("name", "status", "applyStatus") + .isEqualTo(expectedEvents); + } + + @Test + @DisplayName("2023년 7월 21일에 컨퍼런스 행사를 조회할 때, 검색 키워드가 여러 토큰으로 들어오면 해당 토큰을 이름에 모두 포함하고 있는 행사 목록을 조회할 수 있다.") + void findEvents_multiple_tokens_search() { + // given + final String keyword = " 모 컨퍼"; + final List expectedEvents = List.of(모바일_컨퍼런스); + + // when + final List actualEvents = eventService.findEvents(EventType.CONFERENCE, + TODAY, null, null, null, null, keyword); + + // then + assertThat(actualEvents) + .usingRecursiveComparison() + .comparingOnlyFields("name", "status", "applyStatus") + .isEqualTo(expectedEvents); + } + + @Test + @DisplayName("'진행 중' 상태이고 특정 키워드를 포함하고 있는 행사 목록을 조회할 수 있다.") + void findEvents_status_filter_and_search() { + // given + final String keyword = "프콘 "; + final List expectedEvents = List.of(인프콘_2023); + + // when + final List actualEvents = eventService.findEvents(EventType.CONFERENCE, + TODAY, + null, null, null, List.of(IN_PROGRESS), keyword); + + // then + assertThat(actualEvents) + .usingRecursiveComparison() + .comparingOnlyFields("name", "status", "applyStatus") + .isEqualTo(expectedEvents); + } + } } @Nested From b3d994453dc69e999bbe37355477b4308b60b10e Mon Sep 17 00:00:00 2001 From: amaran-th Date: Thu, 5 Oct 2023 18:08:13 +0900 Subject: [PATCH 6/8] =?UTF-8?q?refactor:=20=ED=82=A4=EC=9B=8C=EB=93=9C=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=EC=9D=84=20=EB=8F=99=EC=A0=81=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=EB=A1=9C=20=EC=B2=98=EB=A6=AC=ED=95=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #324 --- .../event/application/EventService.java | 58 ++++++++++--------- .../domain/repository/EventSpecification.java | 13 +++++ 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java index ad7f9e079..2ea4b465f 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java @@ -1,6 +1,8 @@ package com.emmsale.event.application; import static com.emmsale.event.domain.repository.EventSpecification.filterByCategory; +import static com.emmsale.event.domain.repository.EventSpecification.filterByNameContainsSearchKeywords; +import static com.emmsale.event.domain.repository.EventSpecification.filterByPeriod; import static com.emmsale.event.domain.repository.EventSpecification.filterByTags; import static com.emmsale.event.exception.EventExceptionType.NOT_FOUND_EVENT; import static com.emmsale.tag.exception.TagExceptionType.NOT_FOUND_TAG; @@ -15,7 +17,6 @@ import com.emmsale.event.domain.EventStatus; import com.emmsale.event.domain.EventType; import com.emmsale.event.domain.repository.EventRepository; -import com.emmsale.event.domain.repository.EventSpecification; import com.emmsale.event.domain.repository.EventTagRepository; import com.emmsale.event.exception.EventException; import com.emmsale.event.exception.EventExceptionType; @@ -76,24 +77,27 @@ public List findEvents(final EventType category, final List tagNames, final List statuses, final String keyword) { Specification spec = Specification.where(filterByCategory(category)); - if (isExistTagNames(tagNames)) { - validateTags(tagNames); - spec = spec.and(filterByTags(tagNames)); - } + spec = filterByTagIfExist(tagNames, spec); + spec = filterByDateIfExist(startDate, endDate, spec); + spec = filterByKeywordIfExist(keyword, spec); + + List events = eventRepository.findAll(spec); - if (isExistFilterDate(startDate, endDate)) { - final LocalDateTime startDateTime = validateStartDate(startDate); - final LocalDateTime endDateTime = validateEndDate(endDate); - validateEndDateAfterDateStart(startDateTime, endDateTime); - spec = spec.and(EventSpecification.filterByPeriod(startDateTime, endDateTime)); - } - final List events = filterBySearchKeyword(keyword, spec); final EnumMap> eventsForEventStatus = groupByEventStatus(nowDate, events); return filterByStatuses(nowDate, statuses, eventsForEventStatus); } + private Specification filterByTagIfExist(final List tagNames, + Specification spec) { + if (isExistTagNames(tagNames)) { + validateTags(tagNames); + spec = spec.and(filterByTags(tagNames)); + } + return spec; + } + private boolean isExistTagNames(final List tagNames) { return tagNames != null; } @@ -105,6 +109,17 @@ private void validateTags(final List tagNames) { } } + private Specification filterByDateIfExist(final String startDate, final String endDate, + Specification spec) { + if (isExistFilterDate(startDate, endDate)) { + final LocalDateTime startDateTime = validateStartDate(startDate); + final LocalDateTime endDateTime = validateEndDate(endDate); + validateEndDateAfterDateStart(startDateTime, endDateTime); + spec = spec.and(filterByPeriod(startDateTime, endDateTime)); + } + return spec; + } + private boolean isExistFilterDate(final String startDate, final String endDate) { return startDate != null || endDate != null; } @@ -138,30 +153,19 @@ private void validateEndDateAfterDateStart(final LocalDateTime startDate, } } - private List filterBySearchKeyword(final String keyword, final Specification spec) { - List events = eventRepository.findAll(spec); + private Specification filterByKeywordIfExist(final String keyword, + Specification spec) { if (isExistKeyword(keyword)) { final String[] keywords = keyword.trim().split(" "); - events = events.stream() - .filter(event -> isEventNameContainTokenIn(event, keywords)) - .collect(toList()); + spec = spec.and(filterByNameContainsSearchKeywords(keywords)); } - return events; + return spec; } private boolean isExistKeyword(final String keyword) { return keyword != null && !keyword.trim().isEmpty(); } - private boolean isEventNameContainTokenIn(final Event event, final String[] keywords) { - for (String token : keywords) { - if (!event.getName().contains(token)) { - return false; - } - } - return true; - } - private EnumMap> groupByEventStatus(final LocalDate nowDate, final List events) { return events.stream() diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/domain/repository/EventSpecification.java b/backend/emm-sale/src/main/java/com/emmsale/event/domain/repository/EventSpecification.java index 890044a08..6985c6ed9 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/domain/repository/EventSpecification.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/domain/repository/EventSpecification.java @@ -7,6 +7,7 @@ import java.util.List; import javax.persistence.criteria.Join; import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.Predicate; import org.springframework.data.jpa.domain.Specification; public class EventSpecification { @@ -38,4 +39,16 @@ public static Specification filterByPeriod(final LocalDateTime startDate, startDate)) ); } + + public static Specification filterByNameContainsSearchKeywords(final String[] keywords) { + return (root, query, criteriaBuilder) -> { + Predicate[] predicates = new Predicate[keywords.length]; + + for (int i = 0; i < keywords.length; i++) { + predicates[i] = criteriaBuilder.like(root.get("name"), "%" + keywords[i] + "%"); + } + + return criteriaBuilder.and(predicates); + }; + } } From 2eb6d2d87828cc6a81e80ee43fa155b81d033e29 Mon Sep 17 00:00:00 2001 From: amaran-th Date: Sat, 7 Oct 2023 17:40:39 +0900 Subject: [PATCH 7/8] =?UTF-8?q?refactor:=20keyword.trim().isEmpty()?= =?UTF-8?q?=EB=A5=BC=20isBlank()=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #324 --- .../main/java/com/emmsale/event/application/EventService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java index 2ea4b465f..abeadfa13 100644 --- a/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java +++ b/backend/emm-sale/src/main/java/com/emmsale/event/application/EventService.java @@ -163,7 +163,7 @@ private Specification filterByKeywordIfExist(final String keyword, } private boolean isExistKeyword(final String keyword) { - return keyword != null && !keyword.trim().isEmpty(); + return keyword != null && !keyword.isBlank(); } private EnumMap> groupByEventStatus(final LocalDate nowDate, From ca21d99179471c1ac53d589781448a85f15e9cec Mon Sep 17 00:00:00 2001 From: amaran-th Date: Sat, 7 Oct 2023 17:55:00 +0900 Subject: [PATCH 8/8] =?UTF-8?q?test:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #324 --- .../event/application/EventServiceTest.java | 58 ------------------- 1 file changed, 58 deletions(-) diff --git a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java index 0230c02da..0987005e7 100644 --- a/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java +++ b/backend/emm-sale/src/test/java/com/emmsale/event/application/EventServiceTest.java @@ -61,7 +61,6 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; @@ -307,21 +306,6 @@ void findEvents_before_2023_7_31() { .isEqualTo(expectedEvents); } - @ParameterizedTest - @NullSource - @DisplayName("등록된 행사가 없고 status 옵션이 없을 경우 빈 목록을 반환한다.") - void findEvents_empty(final List statusName) { - // given - eventRepository.deleteAll(); - - // when - final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-12-01", "2023-12-31", null, statusName, null); - - // then - assertThat(actualEvents).isEmpty(); - } - @Test @DisplayName("아무 행사도 없는 2023년 12월 행사를 조회하면, 빈 목록을 반환한다.") void findEvents_2023_12() { @@ -333,29 +317,6 @@ void findEvents_2023_12() { assertThat(actualEvents).isEmpty(); } - - @Test - @DisplayName("아무 행사도 없는 2023년 12월의 행사를 tag로 필터링하면, 빈 목록을 반환한다.") - void findEvents_empty_tag_filter() { - // given, when - final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-12-01", "2023-12-31", List.of("안드로이드"), null, null); - - // then - assertThat(actualEvents).isEmpty(); - } - - @Test - @DisplayName("아무 행사도 없는 2023년 12월의 행사를 status로 필터링하면, 빈 목록을 반환한다.") - void findEvents_empty_status_filter() { - // given, when - final List actualEvents = eventService.findEvents(EventType.CONFERENCE, TODAY, - "2023-12-01", "2023-12-31", null, List.of(IN_PROGRESS), null); - - // then - assertThat(actualEvents).isEmpty(); - } - @ParameterizedTest @ValueSource(strings = {"abcde", "00-0-0", "-1-1-1-1", "2023-02-30"}) @DisplayName("유효하지 않은 값이 시작일 정보로 들어오면 예외를 반환한다.") @@ -519,25 +480,6 @@ void findEvents_blank_search(final String keyword) { .isEqualTo(expectedEvents); } - @ParameterizedTest - @ValueSource(strings = {"", " ", "컨퍼", "인프콘"}) - @DisplayName("2023년 7월 21일에 컨퍼런스 행사를 조회할 때, 목록이 비어있을 때 어떤 키워드가 들어오든 빈 행사 목록을 반환한다.") - void findEvents_empty_events_search(final String keyword) { - // given - eventRepository.deleteAll(); - final List expectedEvents = List.of(); - - // when - final List actualEvents = eventService.findEvents(EventType.CONFERENCE, - TODAY, null, null, null, null, keyword); - - // then - assertThat(actualEvents) - .usingRecursiveComparison() - .comparingOnlyFields("name", "status", "applyStatus") - .isEqualTo(expectedEvents); - } - @Test @DisplayName("2023년 7월 21일에 컨퍼런스 행사를 조회할 때, 검색 키워드가 들어오면 이름에 해당 검색 키워드를 포함하고 있는 행사 목록을 조회할 수 있다.") void findEvents_search() {