diff --git a/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CustomCelebrityRestaurantRepository.kt b/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CustomCelebrityRestaurantRepository.kt index 92ccd9d..c4f0649 100644 --- a/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CustomCelebrityRestaurantRepository.kt +++ b/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CustomCelebrityRestaurantRepository.kt @@ -1,6 +1,5 @@ package com.celuveat.celeb.adapter.out.persistence.entity -import com.celuveat.restaurant.adapter.`in`.rest.request.ReadCelebrityVisitedRestaurantSortCondition import com.celuveat.restaurant.adapter.out.persistence.entity.RestaurantJpaEntity import org.springframework.data.domain.Pageable import org.springframework.data.domain.Slice @@ -9,6 +8,5 @@ interface CustomCelebrityRestaurantRepository { fun findRestaurantsByCelebrityId( celebrityId: Long, pageable: Pageable, - sort: ReadCelebrityVisitedRestaurantSortCondition, ): Slice } diff --git a/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CustomCelebrityRestaurantRepositoryImpl.kt b/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CustomCelebrityRestaurantRepositoryImpl.kt index 803496a..77b4de9 100644 --- a/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CustomCelebrityRestaurantRepositoryImpl.kt +++ b/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CustomCelebrityRestaurantRepositoryImpl.kt @@ -1,6 +1,5 @@ package com.celuveat.celeb.adapter.out.persistence.entity -import com.celuveat.restaurant.adapter.`in`.rest.request.ReadCelebrityVisitedRestaurantSortCondition import com.celuveat.restaurant.adapter.out.persistence.entity.RestaurantJpaEntity import com.linecorp.kotlinjdsl.support.spring.data.jpa.repository.KotlinJdslJpqlExecutor import org.springframework.data.domain.Pageable @@ -15,27 +14,24 @@ class CustomCelebrityRestaurantRepositoryImpl( override fun findRestaurantsByCelebrityId( celebrityId: Long, pageable: Pageable, - sort: ReadCelebrityVisitedRestaurantSortCondition, ): Slice { val findSlice = executor.findSlice(pageable) { select( - entity(CelebrityRestaurantJpaEntity::class), + entity(RestaurantJpaEntity::class), ).from( entity(CelebrityRestaurantJpaEntity::class), - fetchJoin(CelebrityRestaurantJpaEntity::restaurant), + fetchJoin(RestaurantJpaEntity::class).on( + path(CelebrityRestaurantJpaEntity::restaurant)(RestaurantJpaEntity::id).eq( + path(RestaurantJpaEntity::id) + ), + ), ).whereAnd( path(CelebrityRestaurantJpaEntity::celebrity) .path(CelebrityJpaEntity::id) .eq(celebrityId), - ).orderBy( - when (sort) { - ReadCelebrityVisitedRestaurantSortCondition.CREATED_AT -> path(RestaurantJpaEntity::createdAt).desc() - ReadCelebrityVisitedRestaurantSortCondition.REVIEW -> path(RestaurantJpaEntity::reviewCount).desc() - ReadCelebrityVisitedRestaurantSortCondition.LIKE -> path(RestaurantJpaEntity::likeCount).desc() - }, ) } - val restaurants = findSlice.content.filterNotNull().map { it.restaurant } + val restaurants = findSlice.content.filterNotNull() return SliceImpl( restaurants, findSlice.pageable, diff --git a/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/RestaurantPersistenceAdapter.kt b/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/RestaurantPersistenceAdapter.kt index 5c16236..208256d 100644 --- a/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/RestaurantPersistenceAdapter.kt +++ b/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/RestaurantPersistenceAdapter.kt @@ -5,6 +5,9 @@ import com.celuveat.common.annotation.Adapter import com.celuveat.common.application.port.`in`.result.SliceResult import com.celuveat.common.utils.geometry.SquarePolygon import com.celuveat.restaurant.adapter.`in`.rest.request.ReadCelebrityVisitedRestaurantSortCondition +import com.celuveat.restaurant.adapter.`in`.rest.request.ReadCelebrityVisitedRestaurantSortCondition.CREATED_AT +import com.celuveat.restaurant.adapter.`in`.rest.request.ReadCelebrityVisitedRestaurantSortCondition.LIKE +import com.celuveat.restaurant.adapter.`in`.rest.request.ReadCelebrityVisitedRestaurantSortCondition.REVIEW import com.celuveat.restaurant.adapter.out.persistence.entity.InterestedRestaurantJpaRepository import com.celuveat.restaurant.adapter.out.persistence.entity.RestaurantFilter import com.celuveat.restaurant.adapter.out.persistence.entity.RestaurantImageJpaRepository @@ -13,10 +16,10 @@ import com.celuveat.restaurant.adapter.out.persistence.entity.RestaurantPersiste import com.celuveat.restaurant.application.port.out.ReadRestaurantPort import com.celuveat.restaurant.application.port.out.SaveRestaurantPort import com.celuveat.restaurant.domain.Restaurant -import org.springframework.data.domain.PageRequest -import org.springframework.data.domain.Sort import java.time.LocalDate import java.time.LocalTime +import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Sort @Adapter class RestaurantPersistenceAdapter( @@ -32,11 +35,10 @@ class RestaurantPersistenceAdapter( size: Int, sort: ReadCelebrityVisitedRestaurantSortCondition, ): SliceResult { - val pageRequest = PageRequest.of(page, size, LATEST_SORTER) + val pageRequest = PageRequest.of(page, size, getVisitedRestaurantSort(sort)) val restaurantSlice = celebrityRestaurantJpaRepository.findRestaurantsByCelebrityId( celebrityId, pageRequest, - sort, ) val imagesByRestaurants = restaurantImageJpaRepository.findByRestaurantIn(restaurantSlice.content) .groupBy { it.restaurant.id } @@ -52,6 +54,13 @@ class RestaurantPersistenceAdapter( ) } + private fun getVisitedRestaurantSort(sortCondition: ReadCelebrityVisitedRestaurantSortCondition) = + when (sortCondition) { + CREATED_AT -> Sort.by("createdAt").descending().and(Sort.by("id").descending()) + REVIEW -> Sort.by("reviewCount").descending().and(Sort.by("id").descending()) + LIKE -> Sort.by("likeCount").descending().and(Sort.by("id").descending()) + } + override fun countRestaurantByCelebrity(celebrityId: Long): Int { return celebrityRestaurantJpaRepository.countRestaurantsByCelebrityId(celebrityId).toInt() } @@ -210,7 +219,7 @@ class RestaurantPersistenceAdapter( } companion object { - val LATEST_SORTER = Sort.by("createdAt").descending() + val LATEST_SORTER = Sort.by("id").descending() } override fun save(restaurant: Restaurant) { diff --git a/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/CustomRestaurantRepositoryImpl.kt b/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/CustomRestaurantRepositoryImpl.kt index 20711ee..efb810a 100644 --- a/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/CustomRestaurantRepositoryImpl.kt +++ b/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/CustomRestaurantRepositoryImpl.kt @@ -27,10 +27,11 @@ class CustomRestaurantRepositoryImpl( select( entity(RestaurantJpaEntity::class), ).from( - entity(RestaurantJpaEntity::class), - leftJoin(CelebrityRestaurantJpaEntity::class).on( - path(CelebrityRestaurantJpaEntity::restaurant)(RestaurantJpaEntity::id) - .eq(path(RestaurantJpaEntity::id)), + entity(CelebrityRestaurantJpaEntity::class), + fetchJoin(RestaurantJpaEntity::class).on( + path(CelebrityRestaurantJpaEntity::restaurant)(RestaurantJpaEntity::id).eq( + path(RestaurantJpaEntity::id) + ), ), ).whereAnd( filter.category?.let { path(RestaurantJpaEntity::category).eq(it) }, diff --git a/src/test/kotlin/com/celuveat/restaurant/adapter/out/persistence/RestaurantPersistenceAdapterTest.kt b/src/test/kotlin/com/celuveat/restaurant/adapter/out/persistence/RestaurantPersistenceAdapterTest.kt index 6fd42af..91ccf75 100644 --- a/src/test/kotlin/com/celuveat/restaurant/adapter/out/persistence/RestaurantPersistenceAdapterTest.kt +++ b/src/test/kotlin/com/celuveat/restaurant/adapter/out/persistence/RestaurantPersistenceAdapterTest.kt @@ -79,6 +79,56 @@ class RestaurantPersistenceAdapterTest( visitedRestaurants.hasNext shouldBe true } + test("셀럽이 방문한 음식점 조회 시 페이지에 따른 중복 데이터가 존재하지 않는다.") { + // given + val savedRestaurants = + restaurantJpaRepository.saveAll(sut.giveMeBuilder().sampleList(20)) + val savedCelebrity = celebrityJpaRepository.save(sut.giveMeOne()) + celebrityRestaurantJpaRepository.saveAll( + savedRestaurants.map { + CelebrityRestaurantJpaEntity( + celebrity = savedCelebrity, + restaurant = it, + ) + }, + ) + + restaurantImageJpaRepository.saveAll( + savedRestaurants.map { + sut.giveMeBuilder() + .set(RestaurantImageJpaEntity::id, 0) + .set(RestaurantImageJpaEntity::restaurant, it) + .set(RestaurantImageJpaEntity::isThumbnail, true, 1) + .sampleList(3) + }.flatten(), + ) + + // when + listOf( + restaurantPersistenceAdapter.readVisitedRestaurantByCelebrity( + celebrityId = savedCelebrity.id, + page = 0, + size = 2, + sort = CREATED_AT, + ).contents + restaurantPersistenceAdapter.readVisitedRestaurantByCelebrity( + celebrityId = savedCelebrity.id, + page = 1, + size = 2, + sort = CREATED_AT, + ).contents + restaurantPersistenceAdapter.readVisitedRestaurantByCelebrity( + celebrityId = savedCelebrity.id, + page = 2, + size = 2, + sort = CREATED_AT, + ).contents + restaurantPersistenceAdapter.readVisitedRestaurantByCelebrity( + celebrityId = savedCelebrity.id, + page = 3, + size = 2, + sort = CREATED_AT, + ).contents + ).flatten().distinctBy { it.id }.size shouldBe 8 + } + test("셀럽이 많이 다녀간 순서로 음식점을 조회한다.") { // given val savedRestaurants = restaurantJpaRepository.saveAll(sut.giveMeBuilder().sampleList(2)) @@ -133,12 +183,23 @@ class RestaurantPersistenceAdapterTest( test("조건에 따라 음식점을 페이징 검색한다.") { // given - restaurantJpaRepository.saveAll( + val savedRestaurants = restaurantJpaRepository.saveAll( sut.giveMeBuilder() .setExp(RestaurantJpaEntity::category, "한식", 2) .setExp(RestaurantJpaEntity::roadAddress, "서울", 1) .sampleList(5), ) + savedRestaurants.map { + celebrityRestaurantJpaRepository.save( + sut.giveMeBuilder() + .set(CelebrityRestaurantJpaEntity::restaurant, it) + .set( + CelebrityRestaurantJpaEntity::celebrity, + celebrityJpaRepository.save(sut.giveMeOne()) + ) + .sample() + ) + } // when val restaurants = restaurantPersistenceAdapter.readRestaurantsByCondition( @@ -178,13 +239,25 @@ class RestaurantPersistenceAdapterTest( test("존재하지 않는 조건은 생략하고 검색한다.") { // given - restaurantJpaRepository.saveAll( + val savedRestaurants = restaurantJpaRepository.saveAll( sut.giveMeBuilder() .setExp(RestaurantJpaEntity::category, "한식", 1) .setExp(RestaurantJpaEntity::roadAddress, "서울", 2) - .sampleList(4), + .sampleList(5), ) + savedRestaurants.map { + celebrityRestaurantJpaRepository.save( + sut.giveMeBuilder() + .set(CelebrityRestaurantJpaEntity::restaurant, it) + .set( + CelebrityRestaurantJpaEntity::celebrity, + celebrityJpaRepository.save(sut.giveMeOne()) + ) + .sample() + ) + } + // when val restaurants = restaurantPersistenceAdapter.readRestaurantsByCondition( category = null,