generated from pricelees/issue-pr-template
feat: 인기 테마 조회 시 theme에서 JOIN으로 가져오도록 수정
This commit is contained in:
parent
c847ae2fe6
commit
e552636aec
@ -9,11 +9,13 @@ import org.springframework.transaction.annotation.Transactional
|
||||
import roomescape.admin.business.AdminService
|
||||
import roomescape.common.config.next
|
||||
import roomescape.common.dto.AuditInfo
|
||||
import roomescape.common.util.DateUtils
|
||||
import roomescape.theme.exception.ThemeErrorCode
|
||||
import roomescape.theme.exception.ThemeException
|
||||
import roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
import roomescape.theme.infrastructure.persistence.ThemeRepository
|
||||
import roomescape.theme.web.*
|
||||
import java.time.LocalDate
|
||||
|
||||
private val log: KLogger = KotlinLogging.logger {}
|
||||
|
||||
@ -43,13 +45,18 @@ class ThemeService(
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun findAllInfosByIds(request: ThemeIdListRequest): ThemeInfoListResponse {
|
||||
log.info { "[ThemeService.findThemesByIds] 예약 페이지에서의 테마 목록 조회 시작: themeIds=${request.themeIds}" }
|
||||
val result: List<ThemeEntity> = themeRepository.findAllByIdIn(request.themeIds)
|
||||
fun findMostReservedThemeLastWeek(count: Int): ThemeInfoListResponse {
|
||||
log.info { "[ThemeService.findMostReservedThemeLastWeek] 인기 테마 조회 시작: count=$count" }
|
||||
|
||||
return result.toInfoListResponse().also {
|
||||
log.info { "[ThemeService.findThemesByIds] ${it.themes.size} / ${request.themeIds.size} 개 테마 조회 완료" }
|
||||
val previousWeekSunday = DateUtils.getSundayOfPreviousWeek(LocalDate.now())
|
||||
val previousWeekSaturday = previousWeekSunday.plusDays(6)
|
||||
|
||||
return themeRepository.findMostReservedThemeByDateAndCount(previousWeekSunday, previousWeekSaturday, count)
|
||||
.toListResponse()
|
||||
.also {
|
||||
log.info { "[ThemeService.findMostReservedThemeLastWeek] ${it.themes.size} / $count 개의 인기 테마 조회 완료" }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ========================================
|
||||
|
||||
@ -5,8 +5,10 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses
|
||||
import jakarta.validation.Valid
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import roomescape.admin.infrastructure.persistence.AdminType
|
||||
import roomescape.admin.infrastructure.persistence.Privilege
|
||||
import roomescape.auth.web.support.AdminOnly
|
||||
@ -50,13 +52,13 @@ interface AdminThemeAPI {
|
||||
}
|
||||
|
||||
interface PublicThemeAPI {
|
||||
@Public
|
||||
@Operation(summary = "입력된 모든 ID에 대한 테마 정보 조회")
|
||||
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
|
||||
fun findThemeInfosByIds(request: ThemeIdListRequest): ResponseEntity<CommonApiResponse<ThemeInfoListResponse>>
|
||||
|
||||
@Public
|
||||
@Operation(summary = "입력된 테마 ID에 대한 정보 조회")
|
||||
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
|
||||
fun findThemeInfoById(@PathVariable id: Long): ResponseEntity<CommonApiResponse<ThemeInfoResponse>>
|
||||
|
||||
@Public
|
||||
@Operation(summary = "지난 주에 가장 많이 예약된 count 개의 테마 조회")
|
||||
@GetMapping("/most-reserved")
|
||||
fun findMostReservedThemeLastWeek(@RequestParam count: Int): ResponseEntity<CommonApiResponse<ThemeInfoListResponse>>
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@ package roomescape.theme.infrastructure.persistence
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.data.jpa.repository.Query
|
||||
import roomescape.theme.business.domain.ThemeInfo
|
||||
import java.time.LocalDate
|
||||
|
||||
interface ThemeRepository : JpaRepository<ThemeEntity, Long> {
|
||||
|
||||
@ -10,5 +12,32 @@ interface ThemeRepository : JpaRepository<ThemeEntity, Long> {
|
||||
|
||||
fun existsByName(name: String): Boolean
|
||||
|
||||
fun findAllByIdIn(themeIds: List<Long>): List<ThemeEntity>
|
||||
@Query(
|
||||
value = """
|
||||
SELECT
|
||||
t.id, t.name, t.description, t.difficulty, t.thumbnail_url, t.price,
|
||||
t.min_participants, t.max_participants,
|
||||
t.available_minutes, t.expected_minutes_from, t.expected_minutes_to
|
||||
FROM
|
||||
theme t
|
||||
JOIN (
|
||||
SELECT
|
||||
s.theme_id, count(*) as reservation_count
|
||||
FROM
|
||||
schedule s
|
||||
JOIN
|
||||
reservation r ON s.id = r.schedule_id AND r.status = 'CONFIRMED'
|
||||
WHERE
|
||||
s.status = 'RESERVED'
|
||||
AND (s.date BETWEEN :startFrom AND :endAt)
|
||||
GROUP BY
|
||||
s.theme_id
|
||||
ORDER BY
|
||||
reservation_count desc
|
||||
LIMIT :count
|
||||
) ranked_themes ON t.id = ranked_themes.theme_id
|
||||
""",
|
||||
nativeQuery = true
|
||||
)
|
||||
fun findMostReservedThemeByDateAndCount(startFrom: LocalDate, endAt: LocalDate, count: Int): List<ThemeInfo>
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package roomescape.theme.web
|
||||
|
||||
import jakarta.validation.Valid
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import roomescape.common.dto.response.CommonApiResponse
|
||||
@ -12,15 +11,6 @@ import roomescape.theme.docs.PublicThemeAPI
|
||||
class ThemeController(
|
||||
private val themeService: ThemeService,
|
||||
) : PublicThemeAPI {
|
||||
@PostMapping("/batch")
|
||||
override fun findThemeInfosByIds(
|
||||
@Valid @RequestBody request: ThemeIdListRequest
|
||||
): ResponseEntity<CommonApiResponse<ThemeInfoListResponse>> {
|
||||
val response = themeService.findAllInfosByIds(request)
|
||||
|
||||
return ResponseEntity.ok(CommonApiResponse(response))
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
override fun findThemeInfoById(
|
||||
@PathVariable id: Long
|
||||
@ -29,4 +19,13 @@ class ThemeController(
|
||||
|
||||
return ResponseEntity.ok(CommonApiResponse(response))
|
||||
}
|
||||
|
||||
@GetMapping("/most-reserved")
|
||||
override fun findMostReservedThemeLastWeek(
|
||||
@RequestParam count: Int
|
||||
): ResponseEntity<CommonApiResponse<ThemeInfoListResponse>> {
|
||||
val response = themeService.findMostReservedThemeLastWeek(count)
|
||||
|
||||
return ResponseEntity.ok(CommonApiResponse(response))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package roomescape.theme.web
|
||||
|
||||
import roomescape.theme.infrastructure.persistence.Difficulty
|
||||
import roomescape.theme.business.domain.ThemeInfo
|
||||
import roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
|
||||
data class ThemeIdListRequest(
|
||||
@ -12,7 +12,7 @@ data class ThemeInfoResponse(
|
||||
val name: String,
|
||||
val thumbnailUrl: String,
|
||||
val description: String,
|
||||
val difficulty: Difficulty,
|
||||
val difficulty: String,
|
||||
val price: Int,
|
||||
val minParticipants: Short,
|
||||
val maxParticipants: Short,
|
||||
@ -21,7 +21,7 @@ data class ThemeInfoResponse(
|
||||
val expectedMinutesTo: Short
|
||||
)
|
||||
|
||||
fun ThemeEntity.toInfoResponse() = ThemeInfoResponse(
|
||||
fun ThemeInfo.toInfoResponse() = ThemeInfoResponse(
|
||||
id = this.id,
|
||||
name = this.name,
|
||||
thumbnailUrl = this.thumbnailUrl,
|
||||
@ -35,10 +35,24 @@ fun ThemeEntity.toInfoResponse() = ThemeInfoResponse(
|
||||
expectedMinutesTo = this.expectedMinutesTo
|
||||
)
|
||||
|
||||
fun ThemeEntity.toInfoResponse() = ThemeInfoResponse(
|
||||
id = this.id,
|
||||
name = this.name,
|
||||
thumbnailUrl = this.thumbnailUrl,
|
||||
description = this.description,
|
||||
difficulty = this.difficulty.name,
|
||||
price = this.price,
|
||||
minParticipants = this.minParticipants,
|
||||
maxParticipants = this.maxParticipants,
|
||||
availableMinutes = this.availableMinutes,
|
||||
expectedMinutesFrom = this.expectedMinutesFrom,
|
||||
expectedMinutesTo = this.expectedMinutesTo
|
||||
)
|
||||
|
||||
data class ThemeInfoListResponse(
|
||||
val themes: List<ThemeInfoResponse>
|
||||
)
|
||||
|
||||
fun List<ThemeEntity>.toInfoListResponse() = ThemeInfoListResponse(
|
||||
fun List<ThemeInfo>.toListResponse() = ThemeInfoListResponse(
|
||||
themes = this.map { it.toInfoResponse() }
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user