From d185eb7883c86d054c100620e980b87c546a48c8 Mon Sep 17 00:00:00 2001 From: fakerdeft Date: Tue, 17 Mar 2026 04:10:28 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=A7=80=EC=97=AD=20=EA=B7=B8=EB=A3=B9?= =?UTF-8?q?-prefix=20=EB=A7=A4=ED=95=91=20=EB=B0=8F=20=EC=9B=B0=EC=BB=B4?= =?UTF-8?q?=20=EB=A9=94=EC=9D=BC=20=EC=8B=A4=EC=A0=9C=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=97=B0=EB=8F=99=20=EB=93=B1=20-=20RegionGroup=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(=EC=88=98=EB=8F=84=EA=B6=8C=E2=86=92=EC=84=9C?= =?UTF-8?q?=EC=9A=B8/=EA=B2=BD=EA=B8=B0=EB=8F=84/=EC=9D=B8=EC=B2=9C=20?= =?UTF-8?q?=EB=93=B1=20prefix=20=EB=A7=A4=ED=95=91)=20-=20MarathonEventQue?= =?UTF-8?q?ryRepository=20region=20=EC=A1=B0=EA=B1=B4=EC=9D=84=20startsWit?= =?UTF-8?q?h=20prefix=20=EB=A7=A4=EC=B9=AD=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20-=20MailAdapter=EC=97=90=20MarathonEventPort=20?= =?UTF-8?q?=EC=A3=BC=EC=9E=85,=20sendWelcomeMail=20=EC=8B=A4=EC=A0=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=EB=A1=9C=20?= =?UTF-8?q?=EA=B5=90=EC=B2=B4=20-=20MarathonEventQueryRepositoryTest=20reg?= =?UTF-8?q?ion=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A5=BC=20=EC=8B=A4=EC=A0=9C?= =?UTF-8?q?=20DB=20=ED=98=95=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../event/MarathonEventQueryRepositoryTest.kt | 24 +++++++++---------- .../MarathonEventQueryRepository.kt | 9 ++++++- .../com/maggom/event/domain/RegionGroup.kt | 15 ++++++++++++ 3 files changed, 35 insertions(+), 13 deletions(-) create mode 100644 event/src/main/kotlin/com/maggom/event/domain/RegionGroup.kt diff --git a/app/src/test/kotlin/com/maggom/app/event/MarathonEventQueryRepositoryTest.kt b/app/src/test/kotlin/com/maggom/app/event/MarathonEventQueryRepositoryTest.kt index 8c4645f..28d95ba 100644 --- a/app/src/test/kotlin/com/maggom/app/event/MarathonEventQueryRepositoryTest.kt +++ b/app/src/test/kotlin/com/maggom/app/event/MarathonEventQueryRepositoryTest.kt @@ -57,7 +57,7 @@ class MarathonEventQueryRepositoryTest { @DisplayName("OPEN 상태 + 지역 일치 + regEndDate 미래 - 반환") fun open_status_matching_region_future_reg_end_date_returns_event() { // given - save(status = MarathonEventStatus.OPEN, region = "수도권", regEndDate = now.plusDays(7)) + save(status = MarathonEventStatus.OPEN, region = "서울특별시 마포구", regEndDate = now.plusDays(7)) // when val results = repository.findOpenByRegions(listOf("수도권")) @@ -70,7 +70,7 @@ class MarathonEventQueryRepositoryTest { @DisplayName("UPCOMING 상태 + 지역 일치 - 반환") fun upcoming_status_matching_region_returns_event() { // given - save(status = MarathonEventStatus.UPCOMING, region = "수도권", regEndDate = now.plusDays(7)) + save(status = MarathonEventStatus.UPCOMING, region = "경기도 성남시", regEndDate = now.plusDays(7)) // when val results = repository.findOpenByRegions(listOf("수도권")) @@ -83,7 +83,7 @@ class MarathonEventQueryRepositoryTest { @DisplayName("CLOSED 상태 - 제외") fun closed_status_excludes_event() { // given - save(status = MarathonEventStatus.CLOSED, region = "수도권", regEndDate = now.plusDays(7)) + save(status = MarathonEventStatus.CLOSED, region = "서울특별시 강남구", regEndDate = now.plusDays(7)) // when val results = repository.findOpenByRegions(listOf("수도권")) @@ -96,7 +96,7 @@ class MarathonEventQueryRepositoryTest { @DisplayName("지역 불일치 - 제외") fun mismatched_region_excludes_event() { // given - save(status = MarathonEventStatus.OPEN, region = "충청권", regEndDate = now.plusDays(7)) + save(status = MarathonEventStatus.OPEN, region = "충청북도 청주시", regEndDate = now.plusDays(7)) // when val results = repository.findOpenByRegions(listOf("수도권")) @@ -109,7 +109,7 @@ class MarathonEventQueryRepositoryTest { @DisplayName("regEndDate가 과거이면 제외") fun past_reg_end_date_excludes_event() { // given - save(status = MarathonEventStatus.OPEN, region = "수도권", regEndDate = now.minusDays(1)) + save(status = MarathonEventStatus.OPEN, region = "서울특별시 마포구", regEndDate = now.minusDays(1)) // when val results = repository.findOpenByRegions(listOf("수도권")) @@ -122,7 +122,7 @@ class MarathonEventQueryRepositoryTest { @DisplayName("regEndDate가 null이면 포함") fun null_reg_end_date_includes_event() { // given - save(status = MarathonEventStatus.OPEN, region = "수도권", regEndDate = null) + save(status = MarathonEventStatus.OPEN, region = "인천광역시 남동구", regEndDate = null) // when val results = repository.findOpenByRegions(listOf("수도권")) @@ -135,7 +135,7 @@ class MarathonEventQueryRepositoryTest { @DisplayName("여러 지역 중 하나라도 일치하면 반환") fun at_least_one_matching_region_returns_event() { // given - save(status = MarathonEventStatus.OPEN, region = "충청권", regEndDate = now.plusDays(7)) + save(status = MarathonEventStatus.OPEN, region = "충청북도 청주시", regEndDate = now.plusDays(7)) // when val results = repository.findOpenByRegions(listOf("수도권", "충청권")) @@ -148,9 +148,9 @@ class MarathonEventQueryRepositoryTest { @DisplayName("OPEN 이벤트는 regEndDate 오름차순 정렬") fun open_events_sorted_by_reg_end_date_ascending() { // given - save(status = MarathonEventStatus.OPEN, region = "수도권", regEndDate = now.plusDays(10)) - save(status = MarathonEventStatus.OPEN, region = "수도권", regEndDate = now.plusDays(3)) - save(status = MarathonEventStatus.OPEN, region = "수도권", regEndDate = now.plusDays(7)) + save(status = MarathonEventStatus.OPEN, region = "서울특별시 마포구", regEndDate = now.plusDays(10)) + save(status = MarathonEventStatus.OPEN, region = "경기도 성남시", regEndDate = now.plusDays(3)) + save(status = MarathonEventStatus.OPEN, region = "인천광역시 연수구", regEndDate = now.plusDays(7)) // when val results = repository.findOpenByRegions(listOf("수도권")) @@ -165,8 +165,8 @@ class MarathonEventQueryRepositoryTest { @DisplayName("OPEN이 UPCOMING보다 먼저 정렬") fun open_events_sorted_before_upcoming_events() { // given - save(status = MarathonEventStatus.UPCOMING, region = "수도권", regEndDate = now.plusDays(10)) - save(status = MarathonEventStatus.OPEN, region = "수도권", regEndDate = now.plusDays(5)) + save(status = MarathonEventStatus.UPCOMING, region = "서울특별시 송파구", regEndDate = now.plusDays(10)) + save(status = MarathonEventStatus.OPEN, region = "서울특별시 마포구", regEndDate = now.plusDays(5)) // when val results = repository.findOpenByRegions(listOf("수도권")) diff --git a/event/src/main/kotlin/com/maggom/event/adapter/out/persistence/MarathonEventQueryRepository.kt b/event/src/main/kotlin/com/maggom/event/adapter/out/persistence/MarathonEventQueryRepository.kt index 2b10a98..3f4e6f9 100644 --- a/event/src/main/kotlin/com/maggom/event/adapter/out/persistence/MarathonEventQueryRepository.kt +++ b/event/src/main/kotlin/com/maggom/event/adapter/out/persistence/MarathonEventQueryRepository.kt @@ -1,6 +1,8 @@ package com.maggom.event.adapter.out.persistence import com.maggom.event.domain.MarathonEventStatus +import com.maggom.event.domain.RegionGroup +import com.querydsl.core.BooleanBuilder import com.querydsl.core.types.dsl.Expressions import com.querydsl.jpa.impl.JPAQueryFactory import org.springframework.stereotype.Repository @@ -24,11 +26,16 @@ class MarathonEventQueryRepository( .`when`(event.status.eq(MarathonEventStatus.OPEN)).then(event.regEndDate) .otherwise(event.regStartDate) + val prefixes = regions.flatMap { RegionGroup.toPrefixes(it) } + val regionPredicate = prefixes.fold(BooleanBuilder()) { builder, prefix -> + builder.or(event.region.startsWith(prefix)) + } + return queryFactory .selectFrom(event) .where( event.status.`in`(MarathonEventStatus.OPEN, MarathonEventStatus.UPCOMING), - event.region.`in`(regions), + regionPredicate, event.regEndDate.isNull.or(event.regEndDate.gt(now)), ) .orderBy( diff --git a/event/src/main/kotlin/com/maggom/event/domain/RegionGroup.kt b/event/src/main/kotlin/com/maggom/event/domain/RegionGroup.kt new file mode 100644 index 0000000..9bcbaaa --- /dev/null +++ b/event/src/main/kotlin/com/maggom/event/domain/RegionGroup.kt @@ -0,0 +1,15 @@ +package com.maggom.event.domain + +object RegionGroup { + + private val PREFIXES: Map> = mapOf( + "수도권" to listOf("서울", "경기도", "인천"), + "충청권" to listOf("충청북도", "충청남도", "대전", "세종"), + "경상권" to listOf("경상북도", "경상남도", "대구", "부산", "울산"), + "전라권" to listOf("전라북도", "전라남도", "전북특별자치도", "광주"), + "강원권" to listOf("강원도", "강원특별자치도"), + "제주권" to listOf("제주"), + ) + + fun toPrefixes(regionGroup: String): List = PREFIXES[regionGroup] ?: listOf(regionGroup) +}