Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.solve.domain.theme.controller

import com.solve.domain.theme.service.ThemeSearchService
import com.solve.global.common.dto.BaseResponse
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.data.domain.PageRequest
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@Tag(name = "테마 검색", description = "Theme Search")
@RestController
@RequestMapping("/themes/search")
class ThemeSearchController(
private val themeSearchService: ThemeSearchService
) {
@Operation(summary = "테마 검색")
@GetMapping
fun searchTheme(
@RequestParam(required = false, defaultValue = "") query: String,
@RequestParam(required = false, defaultValue = "0") page: Int,
@RequestParam(required = false, defaultValue = "10") size: Int
) = BaseResponse.of(themeSearchService.searchTheme(query, PageRequest.of(page, size)))
}
23 changes: 23 additions & 0 deletions src/main/kotlin/com/solve/domain/theme/mapper/ThemeMapper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.solve.domain.theme.mapper

import com.solve.domain.theme.domain.entity.Theme
import com.solve.domain.theme.dto.response.ThemeResponse
import org.springframework.stereotype.Component

@Component
class ThemeMapper {
fun toResponse(theme: Theme) = ThemeResponse(
id = theme.id!!,
name = theme.name,
description = theme.description,
thumbnail = theme.thumbnail,
background = theme.background,
backgroundBorder = theme.backgroundBorder,
container = theme.container,
containerBorder = theme.containerBorder,
main = theme.main,
price = theme.price,
isPurchasable = false,
has = false
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.solve.domain.theme.repository

import com.querydsl.core.types.dsl.BooleanExpression
import com.querydsl.jpa.impl.JPAQueryFactory
import com.solve.domain.theme.domain.entity.QTheme
import com.solve.domain.theme.domain.entity.Theme
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageImpl
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Repository
import org.springframework.transaction.annotation.Transactional

@Repository
class ThemeQueryRepository(
private val queryFactory: JPAQueryFactory
) {
private val theme = QTheme.theme

@Transactional(readOnly = true)
fun searchTheme(query: String, pageable: Pageable): Page<Theme> {
val contents = queryFactory
.selectFrom(theme)
.distinct()
.where(
searchKeywordContains(query)
)
.offset(pageable.offset)
.limit(pageable.pageSize.toLong())
.orderBy(theme._createdAt.desc(), theme.id.desc())
.fetch()

val total = queryFactory
.select(theme.count())
.from(theme)
.where(
searchKeywordContains(query)
)
.fetchOne() ?: 0L

return PageImpl(contents, pageable, total)
}

private fun searchKeywordContains(query: String): BooleanExpression? =
if (query.isBlank()) {
null
} else {
theme.name.containsIgnoreCase(query)
.or(theme.description.containsIgnoreCase(query))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.solve.domain.theme.service

import com.solve.domain.theme.dto.response.ThemeResponse
import com.solve.domain.theme.mapper.ThemeMapper
import com.solve.domain.theme.repository.ThemeQueryRepository
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class ThemeSearchService(
private val themeMapper: ThemeMapper,
private val themeQueryRepository: ThemeQueryRepository
) {
@Transactional(readOnly = true)
fun searchTheme(query: String, pageable: Pageable): Page<ThemeResponse> {
val themes = themeQueryRepository.searchTheme(query, pageable)

return themes.map { themeMapper.toResponse(it) }
}
}