diff --git a/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingFinder.kt b/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingFinder.kt index 8a4d795..d84c1c9 100644 --- a/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingFinder.kt +++ b/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingFinder.kt @@ -31,11 +31,11 @@ class BloomingFinder( suspend fun readRecentlyBloomingByCafeId(cafeId: Long): List = bloomingRepository.findRecentlyByCafeId(cafeId) - fun recentlyBloomingBySpotIds(spotIds: List): List = bloomingRepository.findRecentBySpotIds(spotIds) + suspend fun recentlyBloomingBySpotIds(spotIds: List): List = bloomingRepository.findRecentBySpotIds(spotIds) - fun recentlyBloomingByEventIds(eventIds: List): List = bloomingRepository.findRecentByEventIds(eventIds) + suspend fun recentlyBloomingByEventIds(eventIds: List): List = bloomingRepository.findRecentByEventIds(eventIds) - fun recentlyBloomingByCafeIds(cafeIds: List): List = bloomingRepository.findRecentByCafeIds(cafeIds) + suspend fun recentlyBloomingByCafeIds(cafeIds: List): List = bloomingRepository.findRecentByCafeIds(cafeIds) fun readTodayBloomingByUserId( userId: Long, diff --git a/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingRepository.kt b/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingRepository.kt index 3be0b09..9d3df94 100644 --- a/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingRepository.kt +++ b/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingRepository.kt @@ -31,11 +31,11 @@ interface BloomingRepository { suspend fun findRecentlyByCafeId(cafeId: Long): List - fun findRecentBySpotIds(spotIds: List): List + suspend fun findRecentBySpotIds(spotIds: List): List - fun findRecentByEventIds(eventIds: List): List + suspend fun findRecentByEventIds(eventIds: List): List - fun findRecentByCafeIds(cafeIds: List): List + suspend fun findRecentByCafeIds(cafeIds: List): List fun findTodayBloomingByUserId( userId: Long, diff --git a/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingService.kt b/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingService.kt index e271c08..07535b9 100644 --- a/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingService.kt +++ b/pida-core/core-domain/src/main/kotlin/com/pida/blooming/BloomingService.kt @@ -1,8 +1,5 @@ package com.pida.blooming -import com.fasterxml.jackson.core.type.TypeReference -import com.pida.support.cache.Cache -import com.pida.support.cache.CacheRepository import com.pida.support.error.ErrorException import com.pida.support.error.ErrorType import org.springframework.stereotype.Service @@ -12,15 +9,7 @@ class BloomingService( private val bloomingAppender: BloomingAppender, private val bloomingValidator: BloomingValidator, private val bloomingFinder: BloomingFinder, - private val cacheRepository: CacheRepository, ) { - companion object { - const val BLOOMING_SPOT_KEY = "blooming:spot" - const val BLOOMING_EVENT_KEY = "blooming:event" - const val BLOOMING_CAFE_KEY = "blooming:cafe" - const val BLOOMING_TTL = 30L - } - suspend fun add(newBlooming: NewBlooming): Blooming { val blooming = when (newBlooming) { @@ -38,9 +27,7 @@ class BloomingService( } bloomingValidator.addValidate(blooming) - val result = bloomingAppender.add(newBlooming) - evictBloomingCache(newBlooming) - return result + return bloomingAppender.add(newBlooming) } suspend fun recentlyBloomingBySpotId(spotId: Long): List = bloomingFinder.readRecentlyBloomingBySpotId(spotId) @@ -49,41 +36,14 @@ class BloomingService( suspend fun recentlyBloomingByCafeId(cafeId: Long): List = bloomingFinder.readRecentlyBloomingByCafeId(cafeId) - fun recentlyBloomingBySpotIds(spotIds: List): List = - spotIds.flatMap { spotId -> cachedRecentlyBloomingBySpotId(spotId) } - - fun recentlyBloomingByEventIds(eventIds: List): List = - eventIds.flatMap { eventId -> cachedRecentlyBloomingByEventId(eventId) } - - fun recentlyBloomingByCafeIds(cafeIds: List): List = - cafeIds.flatMap { cafeId -> cachedRecentlyBloomingByCafeId(cafeId) } + suspend fun recentlyBloomingBySpotIds(spotIds: List): List = + bloomingFinder.recentlyBloomingBySpotIds(spotIds.distinct()) - private fun cachedRecentlyBloomingBySpotId(spotId: Long): List = - Cache.cacheBlocking( - ttl = BLOOMING_TTL, - key = "$BLOOMING_SPOT_KEY:$spotId", - typeReference = object : TypeReference>() {}, - ) { - bloomingFinder.recentlyBloomingBySpotIds(listOf(spotId)) - } + suspend fun recentlyBloomingByEventIds(eventIds: List): List = + bloomingFinder.recentlyBloomingByEventIds(eventIds.distinct()) - private fun cachedRecentlyBloomingByEventId(eventId: Long): List = - Cache.cacheBlocking( - ttl = BLOOMING_TTL, - key = "$BLOOMING_EVENT_KEY:$eventId", - typeReference = object : TypeReference>() {}, - ) { - bloomingFinder.recentlyBloomingByEventIds(listOf(eventId)) - } - - private fun cachedRecentlyBloomingByCafeId(cafeId: Long): List = - Cache.cacheBlocking( - ttl = BLOOMING_TTL, - key = "$BLOOMING_CAFE_KEY:$cafeId", - typeReference = object : TypeReference>() {}, - ) { - bloomingFinder.recentlyBloomingByCafeIds(listOf(cafeId)) - } + suspend fun recentlyBloomingByCafeIds(cafeIds: List): List = + bloomingFinder.recentlyBloomingByCafeIds(cafeIds.distinct()) fun verifyTodayBlooming( userId: Long, @@ -104,12 +64,4 @@ class BloomingService( return bloomingValidator.todayBloomingValidate(blooming) } - - private fun evictBloomingCache(newBlooming: NewBlooming) { - when (newBlooming) { - is NewBlooming.FlowerSpot -> cacheRepository.delete("$BLOOMING_SPOT_KEY:${newBlooming.flowerSpotId}") - is NewBlooming.FlowerEvent -> cacheRepository.delete("$BLOOMING_EVENT_KEY:${newBlooming.flowerEventId}") - is NewBlooming.FlowerSpotCafe -> cacheRepository.delete("$BLOOMING_CAFE_KEY:${newBlooming.flowerSpotCafeId}") - } - } } diff --git a/pida-core/core-domain/src/test/kotlin/com/pida/blooming/BloomingServiceTest.kt b/pida-core/core-domain/src/test/kotlin/com/pida/blooming/BloomingServiceTest.kt index 38fa837..fc075ee 100644 --- a/pida-core/core-domain/src/test/kotlin/com/pida/blooming/BloomingServiceTest.kt +++ b/pida-core/core-domain/src/test/kotlin/com/pida/blooming/BloomingServiceTest.kt @@ -1,6 +1,5 @@ package com.pida.blooming -import com.pida.support.cache.CacheRepository import com.pida.support.error.ErrorException import com.pida.support.error.ErrorType import io.kotest.matchers.shouldBe @@ -17,8 +16,7 @@ class BloomingServiceTest { val bloomingAppender = mockk() val bloomingValidator = mockk() val bloomingFinder = mockk() - val cacheRepository = mockk(relaxed = true) - val service = BloomingService(bloomingAppender, bloomingValidator, bloomingFinder, cacheRepository) + val service = BloomingService(bloomingAppender, bloomingValidator, bloomingFinder) val blooming = Blooming( id = 1L, @@ -44,13 +42,93 @@ class BloomingServiceTest { verify { bloomingValidator.todayBloomingValidate(blooming) } } + @Test + fun `spot batch 조회는 중복 id를 제거한 뒤 한 번의 finder 호출로 위임한다`() { + val bloomingAppender = mockk() + val bloomingValidator = mockk() + val bloomingFinder = mockk() + val service = BloomingService(bloomingAppender, bloomingValidator, bloomingFinder) + val bloomings = + listOf( + Blooming( + id = 1L, + status = BloomingStatus.BLOOMED, + userId = 10L, + flowerSpotId = 30L, + flowerEventId = null, + flowerSpotCafeId = null, + createdAt = LocalDateTime.of(2026, 4, 1, 9, 0), + ), + ) + + every { bloomingFinder.recentlyBloomingBySpotIds(listOf(30L, 31L)) } returns bloomings + + val result = service.recentlyBloomingBySpotIds(listOf(30L, 31L, 30L)) + + result shouldBe bloomings + verify(exactly = 1) { bloomingFinder.recentlyBloomingBySpotIds(listOf(30L, 31L)) } + } + + @Test + fun `event batch 조회는 중복 id를 제거한 뒤 한 번의 finder 호출로 위임한다`() { + val bloomingAppender = mockk() + val bloomingValidator = mockk() + val bloomingFinder = mockk() + val service = BloomingService(bloomingAppender, bloomingValidator, bloomingFinder) + val bloomings = + listOf( + Blooming( + id = 2L, + status = BloomingStatus.LITTLE, + userId = 11L, + flowerSpotId = null, + flowerEventId = 40L, + flowerSpotCafeId = null, + createdAt = LocalDateTime.of(2026, 4, 1, 10, 0), + ), + ) + + every { bloomingFinder.recentlyBloomingByEventIds(listOf(40L, 41L)) } returns bloomings + + val result = service.recentlyBloomingByEventIds(listOf(40L, 41L, 40L)) + + result shouldBe bloomings + verify(exactly = 1) { bloomingFinder.recentlyBloomingByEventIds(listOf(40L, 41L)) } + } + + @Test + fun `cafe batch 조회는 중복 id를 제거한 뒤 한 번의 finder 호출로 위임한다`() { + val bloomingAppender = mockk() + val bloomingValidator = mockk() + val bloomingFinder = mockk() + val service = BloomingService(bloomingAppender, bloomingValidator, bloomingFinder) + val bloomings = + listOf( + Blooming( + id = 3L, + status = BloomingStatus.WITHERED, + userId = 12L, + flowerSpotId = null, + flowerEventId = null, + flowerSpotCafeId = 50L, + createdAt = LocalDateTime.of(2026, 4, 1, 11, 0), + ), + ) + + every { bloomingFinder.recentlyBloomingByCafeIds(listOf(50L, 51L)) } returns bloomings + + val result = service.recentlyBloomingByCafeIds(listOf(50L, 51L, 50L)) + + result shouldBe bloomings + verify(exactly = 1) { bloomingFinder.recentlyBloomingByCafeIds(listOf(50L, 51L)) } + } + @Test fun `flowerSpotId와 flowerEventId가 모두 없으면 INVALID_REQUEST를 던진다`() { val bloomingAppender = mockk() val bloomingValidator = mockk() val bloomingFinder = mockk() - val cacheRepository = mockk(relaxed = true) - val service = BloomingService(bloomingAppender, bloomingValidator, bloomingFinder, cacheRepository) + val service = BloomingService(bloomingAppender, bloomingValidator, bloomingFinder) val exception = assertThrows { @@ -67,8 +145,7 @@ class BloomingServiceTest { val bloomingAppender = mockk() val bloomingValidator = mockk() val bloomingFinder = mockk() - val cacheRepository = mockk(relaxed = true) - val service = BloomingService(bloomingAppender, bloomingValidator, bloomingFinder, cacheRepository) + val service = BloomingService(bloomingAppender, bloomingValidator, bloomingFinder) val exception = assertThrows { diff --git a/pida-storage/db-core/src/main/kotlin/com/pida/storage/db/core/blooming/BloomingCoreRepository.kt b/pida-storage/db-core/src/main/kotlin/com/pida/storage/db/core/blooming/BloomingCoreRepository.kt index 424f7e6..d9ca711 100644 --- a/pida-storage/db-core/src/main/kotlin/com/pida/storage/db/core/blooming/BloomingCoreRepository.kt +++ b/pida-storage/db-core/src/main/kotlin/com/pida/storage/db/core/blooming/BloomingCoreRepository.kt @@ -95,18 +95,18 @@ class BloomingCoreRepository( bloomingCustomRepository.recentlyByCafeId(cafeId).map { it.toBlooming() } } - override fun findRecentBySpotIds(spotIds: List): List = - Tx.readable { + override suspend fun findRecentBySpotIds(spotIds: List): List = + Tx.coReadable { bloomingCustomRepository.recentlyBySpotIds(spotIds).map { it.toBlooming() } } - override fun findRecentByEventIds(eventIds: List): List = - Tx.readable { + override suspend fun findRecentByEventIds(eventIds: List): List = + Tx.coReadable { bloomingCustomRepository.recentlyByEventIds(eventIds).map { it.toBlooming() } } - override fun findRecentByCafeIds(cafeIds: List): List = - Tx.readable { + override suspend fun findRecentByCafeIds(cafeIds: List): List = + Tx.coReadable { bloomingCustomRepository.recentlyByCafeIds(cafeIds).map { it.toBlooming() } }