Skip to content

Commit

Permalink
[feat] : 전체 Gallery 조회 기능 추가 (#381)
Browse files Browse the repository at this point in the history
  • Loading branch information
devxb authored Mar 3, 2024
1 parent 3b0c8c6 commit f3cb875
Show file tree
Hide file tree
Showing 9 changed files with 233 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CREATE INDEX gallery_idx_bookmark ON gallery(bookmarked_count)
CREATE INDEX gallery_idx_update_order ON gallery(update_order)
CREATE UNIQUE INDEX gallery_idx_survey_id ON gallery(survey_id)
CREATE INDEX gallery_idx_job ON gallery(job)
CREATE INDEX gallery_idx_created_at ON gallery(created_at)
CREATE INDEX gallery_idx_updated_at ON gallery(updated_at)
34 changes: 34 additions & 0 deletions gallery/src/main/kotlin/me/nalab/gallery/app/GalleryGetApp.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package me.nalab.gallery.app

import me.nalab.gallery.domain.Gallery
import me.nalab.gallery.domain.GalleryService
import me.nalab.gallery.domain.response.GalleriesDto
import me.nalab.gallery.domain.response.GalleryDto
import me.nalab.survey.application.port.`in`.web.findfeedback.FeedbackFindUseCase
import me.nalab.survey.application.port.`in`.web.survey.find.SurveyFindUseCase
import me.nalab.survey.application.port.`in`.web.target.find.TargetFindUseCase
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import org.springframework.data.domain.Sort
import org.springframework.stereotype.Service

@Service
Expand All @@ -23,4 +29,32 @@ class GalleryGetApp(

return toGalleryDto(gallery, target, survey, feedbacks)
}

fun getGalleries(job: String, page: Int, count: Int, orderType: String): GalleriesDto {
val pageable = getPage(page, count, orderType)
val galleries = galleryService.getGalleries(job, pageable)

val galleryDtos = toGalleryDtos(galleries)

return GalleriesDto(galleries.totalPages, galleryDtos)
}

private fun toGalleryDtos(galleries: Page<Gallery>): List<GalleryDto> {
return galleries.asSequence()
.map { gallery ->
val target = targetFindUseCase.findTarget(gallery.getTargetId())
val survey = surveyFindUseCase.getSurveyByTargetId(gallery.getTargetId())
val feedbacks = feedbackFindUseCase.findAllFeedbackDtoBySurveyId(survey.id)

toGalleryDto(gallery, target, survey, feedbacks)
}.toList()
}

private fun getPage(page: Int, count: Int, orderType: String): Pageable {
return when (orderType.lowercase()) {
"update" -> PageRequest.of(page, count, Sort.by("updateOrder").descending())
"job" -> PageRequest.of(page, count, Sort.by("survey.bookmarkedCount").descending())
else -> throw IllegalArgumentException("orderType 은 update와 bookmark중 하나여야 합니다. 현재 orderType \"$orderType\"")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import me.nalab.gallery.app.GalleryGetApp
import me.nalab.gallery.app.GalleryPreviewApp
import me.nalab.gallery.app.GalleryRegisterApp
import me.nalab.gallery.controller.request.GalleryRegisterRequest
import me.nalab.gallery.domain.response.GalleriesDto
import me.nalab.gallery.domain.response.GalleryDto
import me.nalab.gallery.domain.response.GalleryPreviewDto
import org.springframework.http.HttpStatus
Expand Down Expand Up @@ -36,4 +37,15 @@ class GalleryController(
fun getGallery(@RequestAttribute("logined") targetId: Long): GalleryDto =
galleryGetApp.getGalleryByTargetId(targetId)

@GetMapping
@ResponseStatus(HttpStatus.OK)
fun getGalleries(
@RequestParam(name = "job", defaultValue = "all") job: String,
@RequestParam(name = "page", defaultValue = "0") page: Int,
@RequestParam(name = "count", defaultValue = "5") count: Int,
@RequestParam(name = "order-type", defaultValue = "update") orderType: String
): GalleriesDto {
return galleryGetApp.getGalleries(job, page, count, orderType)
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package me.nalab.gallery.domain

import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Lock
import org.springframework.data.jpa.repository.Query
Expand All @@ -11,4 +13,8 @@ interface GalleryRepository : JpaRepository<Gallery, Long> {
@Lock(LockModeType.OPTIMISTIC)
@Query("select g from Gallery as g where g.target.targetId = :targetId")
fun findByTargetIdOrNull(@Param("targetId") targetId: Long): Gallery?

@Query("select g from Gallery g where g.target.job in :job")
fun findGalleries(@Param("job") job: List<Job>, pageable: Pageable): Page<Gallery>

}
11 changes: 11 additions & 0 deletions gallery/src/main/kotlin/me/nalab/gallery/domain/GalleryService.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package me.nalab.gallery.domain

import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

Expand Down Expand Up @@ -27,4 +29,13 @@ class GalleryService(
fun increaseBookmarkCount(targetId: Long) {
galleryRepository.findByTargetIdOrNull(targetId)?.increaseBookmarkedCount()
}

fun getGalleries(job: String, pageable: Pageable): Page<Gallery> {
val jobs = when (job) {
"all" -> Job.entries.toList()
else -> listOf(Job.valueOf(job.uppercase()))
}

return galleryRepository.findGalleries(jobs, pageable)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package me.nalab.gallery.domain.response

data class GalleriesDto(
val totalPage: Int,
val galleries: List<GalleryDto>
)
11 changes: 6 additions & 5 deletions gallery/src/test/kotlin/me/nalab/gallery/app/SurveyFixture.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package me.nalab.gallery.app

import me.nalab.core.time.TimeUtil
import me.nalab.survey.application.common.feedback.dto.*
import me.nalab.survey.application.common.survey.dto.*
import java.time.Instant
Expand All @@ -23,7 +24,7 @@ fun surveyDto(
choiceFormQuestionDto(),
shortFormQuestionDto()
),
time: Instant = Instant.now(),
time: Instant = TimeUtil.toInstant(),
): SurveyDto {
return SurveyDto.builder()
.id(id)
Expand All @@ -36,7 +37,7 @@ fun surveyDto(

fun choiceFormQuestionDto(
id: Long = 0L,
time: Instant = Instant.now(),
time: Instant = TimeUtil.toInstant(),
type: ChoiceFormQuestionDtoType = ChoiceFormQuestionDtoType.TENDENCY,
choices: List<ChoiceDto> = listOf(choiceDto()),
maxSelectableCount: Int = 5,
Expand Down Expand Up @@ -67,7 +68,7 @@ fun choiceDto(

fun shortFormQuestionDto(
id: Long = 0L,
time: Instant = Instant.now(),
time: Instant = TimeUtil.toInstant(),
type: ShortFormQuestionDtoType = ShortFormQuestionDtoType.CUSTOM,
title: String = "제가 고쳐야할점을 알려주세요.",
order: Int = 1,
Expand All @@ -85,7 +86,7 @@ fun shortFormQuestionDto(
fun feedbackDto(
id: Long = 0L,
surveyId: Long = 0L,
time: Instant = Instant.now(),
time: Instant = TimeUtil.toInstant(),
formQuestionFeedbackDtos: List<FormQuestionFeedbackDtoable> = listOf(
choiceFormQuestionFeedbackDto(),
shortFormQuestionFeedbackDto()
Expand Down Expand Up @@ -136,7 +137,7 @@ fun shortFormQuestionFeedbackDto(

fun bookmarkDto(
isBookmarked: Boolean = false,
time: Instant = Instant.now(),
time: Instant = TimeUtil.toInstant(),
): BookmarkDto {
return BookmarkDto.builder()
.isBookmarked(isBookmarked)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package me.nalab.gallery.domain

import me.nalab.core.time.TimeUtil
import java.time.Instant

fun gallery(
Expand All @@ -8,7 +9,7 @@ fun gallery(
job: Job = Job.OTHERS,
surveyId: Long = 0L,
bookmarkedCount: Int = 0,
updateOrder: Instant = Instant.now(),
updateOrder: Instant = TimeUtil.toInstant(),
): Gallery = Gallery(
id = id,
targetId = targetId,
Expand Down
152 changes: 150 additions & 2 deletions gallery/src/test/kotlin/me/nalab/gallery/domain/GalleryServiceTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@ package me.nalab.gallery.domain
import io.kotest.assertions.throwables.shouldThrowMessage
import io.kotest.core.annotation.DisplayName
import io.kotest.core.spec.style.DescribeSpec
import io.kotest.matchers.equality.FieldsEqualityCheckConfig
import io.kotest.matchers.equality.shouldBeEqualToComparingFields
import io.kotest.matchers.equality.shouldBeEqualUsingFields
import io.kotest.matchers.equals.shouldBeEqual
import me.nalab.core.time.TimeUtil
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Sort
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import org.springframework.test.context.ContextConfiguration
import java.time.temporal.ChronoUnit
import kotlin.reflect.full.memberProperties

@DataJpaTest
@EnableJpaRepositories
Expand All @@ -16,13 +24,24 @@ import org.springframework.test.context.ContextConfiguration
@ContextConfiguration(classes = [GalleryService::class])
internal class GalleryServiceTest(
private val galleryService: GalleryService,
private val galleryRepository: GalleryRepository,
) : DescribeSpec({

beforeSpec {
galleryService.registerGallery(gallery(id = EXIST_GALLERY_ID, targetId = EXIST_TARGET_ID, surveyId = EXIST_SURVEY_ID))
afterEach {
galleryRepository.deleteAll()
}

describe("registerGallery 메소드는") {
beforeEach {
galleryService.registerGallery(
gallery(
id = EXIST_GALLERY_ID,
targetId = EXIST_TARGET_ID,
surveyId = EXIST_SURVEY_ID
)
)
}

context("Gallery에 등록되지 않은 target의 Gallery를 입력받으면,") {
val gallery = gallery(targetId = NOT_EXIST_TARGET_ID)

Expand All @@ -43,12 +62,141 @@ internal class GalleryServiceTest(
}
}
}

describe("getGalleries 메소드는") {
beforeEach {
galleryService.registerGallery(oldDesignerGallery)
galleryService.registerGallery(midDeveloperGallery)
galleryService.registerGallery(latestPmGallery)
}

context("job으로 all과 update순으로 정렬된 Pageable을 입력받으면,") {
val expected = listOf(latestPmGallery, midDeveloperGallery, oldDesignerGallery)

it("update순으로 정렬된 Gallery를 반환한다.") {
val result = galleryService.getGalleries("all", updatePage).content

result.shouldBeExactlyEqualToComparingFields(expected)
}
}

context("job으로 designer와 update순으로 정렬된 Pageable을 입력받으면,") {
val expected = listOf(oldDesignerGallery)

it("update순으로 정렬된 designer Gallery를 반환한다.") {
val result = galleryService.getGalleries("designer", updatePage).content

result.shouldBeExactlyEqualToComparingFields(expected)
}
}

context("job으로 pm과 update순으로 정렬된 Pageable을 입력받으면,") {
val expected = listOf(latestPmGallery)

it("update순으로 정렬된 pm Gallery를 반환한다.") {
val result = galleryService.getGalleries("pm", updatePage).content

result.shouldBeExactlyEqualToComparingFields(expected)
}
}

context("job으로 developer와 update순으로 정렬된 Pageable을 입력받으면,") {
val expected = listOf(midDeveloperGallery)

it("update순으로 정렬된 pm Gallery를 반환한다.") {
val result = galleryService.getGalleries("developer", updatePage).content

result.shouldBeExactlyEqualToComparingFields(expected)
}
}

context("job으로 all과 bookmark순으로 정렬된 Pageable을 받으면,") {
val expected = listOf(oldDesignerGallery, midDeveloperGallery, latestPmGallery)

it("bookmark순으로 정렬된 Gallery를 반환한다") {
val result = galleryService.getGalleries("all", bookmarkPage).content

result.shouldBeExactlyEqualToComparingFields(expected)
}
}

context("job으로 designer와 bookmark순으로 정렬된 Pageable을 입력받으면,") {
val expected = listOf(oldDesignerGallery)

it("update순으로 정렬된 designer Gallery를 반환한다.") {
val result = galleryService.getGalleries("designer", bookmarkPage).content

result.shouldBeExactlyEqualToComparingFields(expected)
}
}

context("job으로 pm과 bookmark순으로 정렬된 Pageable을 입력받으면,") {
val expected = listOf(latestPmGallery)

it("update순으로 정렬된 pm Gallery를 반환한다.") {
val result = galleryService.getGalleries("pm", bookmarkPage).content

result.shouldBeExactlyEqualToComparingFields(expected)
}
}

context("job으로 developer와 bookmark순으로 정렬된 Pageable을 입력받으면,") {
val expected = listOf(midDeveloperGallery)

it("update순으로 정렬된 pm Gallery를 반환한다.") {
val result = galleryService.getGalleries("developer", bookmarkPage).content

result.shouldBeExactlyEqualToComparingFields(expected)
}
}
}
}) {

companion object {
private const val NOT_EXIST_TARGET_ID = 1L
private const val EXIST_GALLERY_ID = 100L
private const val EXIST_TARGET_ID = 100L
private const val EXIST_SURVEY_ID = 100L

val updatePage: PageRequest = PageRequest.of(0, 5, Sort.by("updateOrder").descending())
val bookmarkPage: PageRequest =
PageRequest.of(0, 5, Sort.by("survey.bookmarkedCount").descending())

val oldDesignerGallery = gallery(
id = 1,
targetId = 101,
surveyId = 101,
job = Job.DESIGNER,
updateOrder = TimeUtil.toInstant().minus(1, ChronoUnit.DAYS),
bookmarkedCount = 3
)

val midDeveloperGallery = gallery(
id = 2,
targetId = 102,
surveyId = 102,
job = Job.DEVELOPER,
updateOrder = TimeUtil.toInstant(),
bookmarkedCount = 2
)

val latestPmGallery = gallery(
id = 3,
targetId = 103,
surveyId = 103,
job = Job.PM,
updateOrder = TimeUtil.toInstant().plus(1, ChronoUnit.DAYS),
bookmarkedCount = 1
)

private fun List<Gallery>.shouldBeExactlyEqualToComparingFields(galleries: List<Gallery>) {
this.size shouldBeEqual galleries.size
for (i in galleries.indices) {
this[i].shouldBeEqualToComparingFields(
galleries[i],
FieldsEqualityCheckConfig(propertiesToExclude = Gallery::class.memberProperties.filter { it.name == "createdAt" || it.name == "updatedAt" })
)
}
}
}
}

0 comments on commit f3cb875

Please sign in to comment.