From b3cf26119b6dcc18ef2929e7e4da22ecece661ed Mon Sep 17 00:00:00 2001 From: Klaus Date: Sat, 27 Jun 2026 10:56:05 +0900 Subject: [PATCH] =?UTF-8?q?fix(recommendation):=20native=20Boolean=20?= =?UTF-8?q?=EB=A7=A4=ED=95=91=EC=9D=84=20=EB=B3=B4=EC=A0=95=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...efaultHomeRecommendationQueryRepository.kt | 14 ++++-- ...ltHomeRecommendationQueryRepositoryTest.kt | 43 +++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt index 02ffd7e4..8b358c7e 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt @@ -475,9 +475,9 @@ class DefaultHomeRecommendationQueryRepository( title = row[4] as String, price = (row[5] as Number).toInt(), coverImage = row[6] as String?, - isPointAvailable = row[7] as Boolean, - isAdult = row[8] as Boolean, - isOriginalSeries = row[9] as Boolean + isPointAvailable = row[7].toNativeBoolean(), + isAdult = row[8].toNativeBoolean(), + isOriginalSeries = row[9].toNativeBoolean() ) } } @@ -1185,6 +1185,14 @@ class DefaultHomeRecommendationQueryRepository( return if (condition == null) this else and(condition) } + private fun Any?.toNativeBoolean(): Boolean { + return when (this) { + is Boolean -> this + is Number -> this.toInt() != 0 + else -> this as Boolean + } + } + private fun includeAdultCommunityCondition(includeAdultCommunities: Boolean): BooleanExpression? { return if (includeAdultCommunities) null else creatorCommunity.isAdult.isFalse } diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt index 095f900f..0f627358 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt @@ -44,11 +44,15 @@ import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomePopularCommunityR import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyString +import org.mockito.Mockito import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest import org.springframework.context.annotation.Import import java.time.LocalDateTime import javax.persistence.EntityManager +import javax.persistence.Query @DataJpaTest( properties = [ @@ -1183,6 +1187,45 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor( assertEquals(true, contents.single().isOriginalSeries) } + @Test + @DisplayName("첫 오디오 콘텐츠 native query의 숫자 Boolean 값을 매핑한다") + fun shouldMapNumericNativeBooleanFromFirstAudioContentRows() { + val mockEntityManager = Mockito.mock(EntityManager::class.java) + val mockQuery = Mockito.mock(Query::class.java) + val repository = DefaultHomeRecommendationQueryRepository( + JPAQueryFactory(mockEntityManager), + mockEntityManager + ) + Mockito.`when`(mockEntityManager.createNativeQuery(anyString())).thenReturn(mockQuery) + Mockito.`when`(mockQuery.setParameter(anyString(), any())).thenReturn(mockQuery) + Mockito.`when`(mockQuery.resultList).thenReturn( + listOf( + arrayOf( + 1L, + 2L, + "creator", + null, + "title", + 0, + null, + true, + false, + 1 + ) + ) + ) + + val contents = repository.findFirstAudioContents( + now = LocalDateTime.of(2026, 6, 27, 10, 0), + offset = 0L, + limit = 1, + memberId = null, + includeAdultContents = false + ) + + assertEquals(true, contents.single().isOriginalSeries) + } + @Test @DisplayName("첫 오디오 콘텐츠는 회원과 크리에이터의 양방향 차단 관계를 제외한다") fun shouldExcludeBidirectionalBlockedCreatorsFromFirstAudioContents() {