diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/all/domain/MainContentAllQueryPolicy.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/all/domain/MainContentAllQueryPolicy.kt new file mode 100644 index 00000000..a04f4435 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/all/domain/MainContentAllQueryPolicy.kt @@ -0,0 +1,47 @@ +package kr.co.vividnext.sodalive.v2.content.all.domain + +import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDaysOfWeek +import kr.co.vividnext.sodalive.v2.common.domain.ContentSort + +class MainContentAllQueryPolicy { + fun resolveType(type: String?): MainContentAllType { + return type.toEnumOrNull() ?: MainContentAllType.AUDIO + } + + fun resolveSort(sort: String?): ContentSort { + val resolved = sort.toEnumOrNull() ?: ContentSort.LATEST + return if (resolved == ContentSort.OWNED) ContentSort.LATEST else resolved + } + + fun resolveDayOfWeek(type: MainContentAllType, dayOfWeek: String?): SeriesPublishedDaysOfWeek? { + if (type != MainContentAllType.SERIES) return null + return dayOfWeek.toEnumOrNull() + } + + fun createPage(page: Int?, size: Int?): MainContentPage { + return MainContentPage( + page = page?.coerceAtLeast(0) ?: DEFAULT_PAGE, + size = size?.coerceIn(MIN_SIZE, MAX_SIZE) ?: DEFAULT_SIZE + ) + } + + fun limitItems(items: List, page: MainContentPage): List { + return items.take(page.size) + } + + fun hasNext(items: List<*>, page: MainContentPage): Boolean { + return items.size > page.size + } + + private inline fun > String?.toEnumOrNull(): T? { + if (this == null) return null + return enumValues().firstOrNull { it.name == this } + } + + companion object { + private const val DEFAULT_PAGE = 0 + private const val DEFAULT_SIZE = 20 + private const val MIN_SIZE = 20 + private const val MAX_SIZE = 50 + } +} diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/content/all/domain/MainContentAllQueryPolicyTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/content/all/domain/MainContentAllQueryPolicyTest.kt new file mode 100644 index 00000000..26b13c53 --- /dev/null +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/content/all/domain/MainContentAllQueryPolicyTest.kt @@ -0,0 +1,48 @@ +package kr.co.vividnext.sodalive.v2.content.all.domain + +import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDaysOfWeek +import kr.co.vividnext.sodalive.v2.common.domain.ContentSort +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +class MainContentAllQueryPolicyTest { + private val policy = MainContentAllQueryPolicy() + + @Test + @DisplayName("전체 탭 요청 기본값과 fallback을 보정한다") + fun shouldResolveDefaultsAndFallbacks() { + assertEquals(MainContentAllType.AUDIO, policy.resolveType(null)) + assertEquals(MainContentAllType.AUDIO, policy.resolveType("UNKNOWN")) + assertEquals(ContentSort.LATEST, policy.resolveSort(null)) + assertEquals(ContentSort.LATEST, policy.resolveSort("UNKNOWN")) + assertEquals(ContentSort.LATEST, policy.resolveSort("OWNED")) + assertEquals(ContentSort.POPULAR, policy.resolveSort("POPULAR")) + assertEquals(MainContentPage(page = 0, size = 20), policy.createPage(page = null, size = null)) + assertEquals(MainContentPage(page = 0, size = 20), policy.createPage(page = -1, size = 1)) + assertEquals(MainContentPage(page = 2, size = 50), policy.createPage(page = 2, size = 100)) + } + + @Test + @DisplayName("요일 조건은 SERIES 타입에만 적용한다") + fun shouldResolveDayOfWeekOnlyForSeriesType() { + assertEquals(SeriesPublishedDaysOfWeek.MON, policy.resolveDayOfWeek(MainContentAllType.SERIES, "MON")) + assertEquals(SeriesPublishedDaysOfWeek.RANDOM, policy.resolveDayOfWeek(MainContentAllType.SERIES, "RANDOM")) + assertNull(policy.resolveDayOfWeek(MainContentAllType.SERIES, "INVALID")) + assertNull(policy.resolveDayOfWeek(MainContentAllType.ORIGINAL, "MON")) + assertNull(policy.resolveDayOfWeek(MainContentAllType.AUDIO, "MON")) + } + + @Test + @DisplayName("limit + 1 조회 결과에서 응답 목록과 hasNext를 계산한다") + fun shouldLimitItemsAndResolveHasNext() { + val items = listOf(1, 2, 3) + + assertEquals(listOf(1, 2), policy.limitItems(items, MainContentPage(page = 0, size = 2))) + assertTrue(policy.hasNext(items, MainContentPage(page = 0, size = 2))) + assertFalse(policy.hasNext(listOf(1, 2), MainContentPage(page = 0, size = 2))) + } +}