diff --git a/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/CelebrityPersistenceAdapter.kt b/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/CelebrityPersistenceAdapter.kt index 05b25e0..da36866 100644 --- a/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/CelebrityPersistenceAdapter.kt +++ b/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/CelebrityPersistenceAdapter.kt @@ -72,4 +72,9 @@ class CelebrityPersistenceAdapter( ) } } + + override fun readByName(name: String): List { + val celebrities = celebrityJpaRepository.readByNameContains(name) + return celebrities.map { celebrityPersistenceMapper.toDomainWithoutYoutubeContent(it) } + } } diff --git a/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CelebrityJpaRepository.kt b/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CelebrityJpaRepository.kt index e336843..ce955c7 100644 --- a/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CelebrityJpaRepository.kt +++ b/src/main/kotlin/com/celuveat/celeb/adapter/out/persistence/entity/CelebrityJpaRepository.kt @@ -20,4 +20,7 @@ interface CelebrityJpaRepository : JpaRepository { """, ) fun findAllBySubscriberCountDescTop10(): Set + + @Query(value = "SELECT c FROM CelebrityJpaEntity c WHERE c.name LIKE %:name%") + fun readByNameContains(name: String): List } diff --git a/src/main/kotlin/com/celuveat/celeb/application/port/out/ReadCelebritiesPort.kt b/src/main/kotlin/com/celuveat/celeb/application/port/out/ReadCelebritiesPort.kt index f7964e4..a6c7cf5 100644 --- a/src/main/kotlin/com/celuveat/celeb/application/port/out/ReadCelebritiesPort.kt +++ b/src/main/kotlin/com/celuveat/celeb/application/port/out/ReadCelebritiesPort.kt @@ -12,4 +12,6 @@ interface ReadCelebritiesPort { fun readById(celebrityId: Long): Celebrity fun readByYoutubeContentIds(youtubeContentIds: List): List + + fun readByName(name: String): List } diff --git a/src/main/kotlin/com/celuveat/region/adapter/out/persistence/RegionPersistenceAdapter.kt b/src/main/kotlin/com/celuveat/region/adapter/out/persistence/RegionPersistenceAdapter.kt new file mode 100644 index 0000000..6d81fc4 --- /dev/null +++ b/src/main/kotlin/com/celuveat/region/adapter/out/persistence/RegionPersistenceAdapter.kt @@ -0,0 +1,18 @@ +package com.celuveat.region.adapter.out.persistence + +import com.celuveat.common.annotation.Adapter +import com.celuveat.region.adapter.out.persistence.entity.RegionJpaRepository +import com.celuveat.region.adapter.out.persistence.entity.RegionPersistenceMapper +import com.celuveat.region.application.port.out.ReadRegionPort +import com.celuveat.region.domain.Region + +@Adapter +class RegionPersistenceAdapter( + private val regionJpaRepository: RegionJpaRepository, + private val regionPersistenceMapper: RegionPersistenceMapper, +) : ReadRegionPort { + override fun readByName(name: String): List { + val regions = regionJpaRepository.readByNameContains(name) + return regions.map { regionPersistenceMapper.toDomain(it) } + } +} diff --git a/src/main/kotlin/com/celuveat/region/adapter/out/persistence/entity/RegionJpaEntity.kt b/src/main/kotlin/com/celuveat/region/adapter/out/persistence/entity/RegionJpaEntity.kt new file mode 100644 index 0000000..d530d58 --- /dev/null +++ b/src/main/kotlin/com/celuveat/region/adapter/out/persistence/entity/RegionJpaEntity.kt @@ -0,0 +1,24 @@ +package com.celuveat.region.adapter.out.persistence.entity + +import com.celuveat.common.adapter.out.persistence.entity.RootEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.Table + +@Table(name = "region") +@Entity +class RegionJpaEntity( + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long = 0, + @Column(nullable = false) + val name: String, + val latitude: Double, + val longitude: Double, +) : RootEntity() { + override fun id(): Long { + return this.id + } +} diff --git a/src/main/kotlin/com/celuveat/region/adapter/out/persistence/entity/RegionJpaRepository.kt b/src/main/kotlin/com/celuveat/region/adapter/out/persistence/entity/RegionJpaRepository.kt new file mode 100644 index 0000000..8425067 --- /dev/null +++ b/src/main/kotlin/com/celuveat/region/adapter/out/persistence/entity/RegionJpaRepository.kt @@ -0,0 +1,9 @@ +package com.celuveat.region.adapter.out.persistence.entity + +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query + +interface RegionJpaRepository : JpaRepository { + @Query(value = "SELECT r FROM RegionJpaEntity r WHERE r.name LIKE %:name%") + fun readByNameContains(name: String): List +} diff --git a/src/main/kotlin/com/celuveat/region/adapter/out/persistence/entity/RegionPersistenceMapper.kt b/src/main/kotlin/com/celuveat/region/adapter/out/persistence/entity/RegionPersistenceMapper.kt new file mode 100644 index 0000000..e193999 --- /dev/null +++ b/src/main/kotlin/com/celuveat/region/adapter/out/persistence/entity/RegionPersistenceMapper.kt @@ -0,0 +1,20 @@ +package com.celuveat.region.adapter.out.persistence.entity + +import com.celuveat.common.annotation.Mapper +import com.celuveat.region.domain.Region + +@Mapper +class RegionPersistenceMapper { + fun toDomain(region: RegionJpaEntity): Region { + return Region(id = region.id, name = region.name, latitude = region.latitude, longitude = region.longitude) + } + + fun toEntity(region: Region): RegionJpaEntity { + return RegionJpaEntity( + id = region.id, + name = region.name, + latitude = region.latitude, + longitude = region.longitude, + ) + } +} diff --git a/src/main/kotlin/com/celuveat/region/application/port/out/ReadRegionPort.kt b/src/main/kotlin/com/celuveat/region/application/port/out/ReadRegionPort.kt new file mode 100644 index 0000000..1bc9dae --- /dev/null +++ b/src/main/kotlin/com/celuveat/region/application/port/out/ReadRegionPort.kt @@ -0,0 +1,7 @@ +package com.celuveat.region.application.port.out + +import com.celuveat.region.domain.Region + +interface ReadRegionPort { + fun readByName(name: String): List +} diff --git a/src/main/kotlin/com/celuveat/region/domain/Region.kt b/src/main/kotlin/com/celuveat/region/domain/Region.kt new file mode 100644 index 0000000..fc69644 --- /dev/null +++ b/src/main/kotlin/com/celuveat/region/domain/Region.kt @@ -0,0 +1,8 @@ +package com.celuveat.region.domain + +data class Region( + val id: Long = 0, + val name: String, + val latitude: Double = 0.0, + val longitude: Double = 0.0, +) diff --git a/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/InterestedRestaurantPersistenceAdapter.kt b/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/InterestedRestaurantPersistenceAdapter.kt index d3f56a8..f81b70c 100644 --- a/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/InterestedRestaurantPersistenceAdapter.kt +++ b/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/InterestedRestaurantPersistenceAdapter.kt @@ -8,7 +8,6 @@ import com.celuveat.restaurant.adapter.out.persistence.entity.InterestedRestaura import com.celuveat.restaurant.adapter.out.persistence.entity.InterestedRestaurantPersistenceMapper import com.celuveat.restaurant.adapter.out.persistence.entity.RestaurantImageJpaRepository import com.celuveat.restaurant.adapter.out.persistence.entity.RestaurantJpaRepository -import com.celuveat.restaurant.adapter.out.persistence.entity.RestaurantPersistenceMapper import com.celuveat.restaurant.application.port.out.DeleteInterestedRestaurantPort import com.celuveat.restaurant.application.port.out.ReadInterestedRestaurantPort import com.celuveat.restaurant.application.port.out.SaveInterestedRestaurantPort @@ -25,7 +24,6 @@ class InterestedRestaurantPersistenceAdapter( private val interestedRestaurantPersistenceMapper: InterestedRestaurantPersistenceMapper, private val restaurantJpaRepository: RestaurantJpaRepository, private val memberJpaRepository: MemberJpaRepository, - private val restaurantPersistenceMapper: RestaurantPersistenceMapper, ) : ReadInterestedRestaurantPort, SaveInterestedRestaurantPort, DeleteInterestedRestaurantPort { @Transactional(readOnly = true) override fun readInterestedRestaurants( 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 3121847..d19a776 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 @@ -11,10 +11,10 @@ import com.celuveat.restaurant.adapter.out.persistence.entity.RestaurantJpaRepos import com.celuveat.restaurant.adapter.out.persistence.entity.RestaurantPersistenceMapper import com.celuveat.restaurant.application.port.out.ReadRestaurantPort import com.celuveat.restaurant.domain.Restaurant -import java.time.LocalDate -import java.time.LocalTime import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Sort +import java.time.LocalDate +import java.time.LocalTime @Adapter class RestaurantPersistenceAdapter( @@ -132,7 +132,7 @@ class RestaurantPersistenceAdapter( override fun readTop10InterestedRestaurantsInDate( startOfDate: LocalDate, - endOfDate: LocalDate + endOfDate: LocalDate, ): List { val restaurants = interestedRestaurantJpaRepository.findTop10InterestedRestaurantInDate( startOfDate = startOfDate.atStartOfDay(), @@ -148,6 +148,11 @@ class RestaurantPersistenceAdapter( } } + override fun readByName(name: String): List { + val restaurants = restaurantJpaRepository.readByNameContains(name) + return restaurants.map { restaurantPersistenceMapper.toDomainWithoutImage(it) } + } + companion object { val LATEST_SORTER = Sort.by("createdAt").descending() } diff --git a/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/InterestedRestaurantJpaRepository.kt b/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/InterestedRestaurantJpaRepository.kt index f031f15..0254e55 100644 --- a/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/InterestedRestaurantJpaRepository.kt +++ b/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/InterestedRestaurantJpaRepository.kt @@ -1,11 +1,11 @@ package com.celuveat.restaurant.adapter.out.persistence.entity -import java.time.LocalDateTime import org.springframework.data.domain.Pageable import org.springframework.data.domain.Slice import org.springframework.data.jpa.repository.EntityGraph import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query +import java.time.LocalDateTime interface InterestedRestaurantJpaRepository : JpaRepository { @EntityGraph(attributePaths = ["restaurant"]) diff --git a/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/RestaurantJpaRepository.kt b/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/RestaurantJpaRepository.kt index 37d92e3..81d5f52 100644 --- a/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/RestaurantJpaRepository.kt +++ b/src/main/kotlin/com/celuveat/restaurant/adapter/out/persistence/entity/RestaurantJpaRepository.kt @@ -35,4 +35,7 @@ interface RestaurantJpaRepository : JpaRepository, Cu longitude: Double, distanceKilometer: Double = 2.0, ): List + + @Query(value = "SELECT r FROM RestaurantJpaEntity r WHERE r.name LIKE %:name%") + fun readByNameContains(name: String): List } diff --git a/src/main/kotlin/com/celuveat/restaurant/application/RestaurantQueryService.kt b/src/main/kotlin/com/celuveat/restaurant/application/RestaurantQueryService.kt index 9bdaef4..6434e1a 100644 --- a/src/main/kotlin/com/celuveat/restaurant/application/RestaurantQueryService.kt +++ b/src/main/kotlin/com/celuveat/restaurant/application/RestaurantQueryService.kt @@ -22,9 +22,9 @@ import com.celuveat.restaurant.application.port.`in`.result.RestaurantDetailResu import com.celuveat.restaurant.application.port.`in`.result.RestaurantPreviewResult import com.celuveat.restaurant.application.port.out.ReadInterestedRestaurantPort import com.celuveat.restaurant.application.port.out.ReadRestaurantPort +import org.springframework.stereotype.Service import java.time.DayOfWeek import java.time.temporal.TemporalAdjusters -import org.springframework.stereotype.Service @Service class RestaurantQueryService( diff --git a/src/main/kotlin/com/celuveat/restaurant/application/port/out/ReadRestaurantPort.kt b/src/main/kotlin/com/celuveat/restaurant/application/port/out/ReadRestaurantPort.kt index ddd78f0..ea96b36 100644 --- a/src/main/kotlin/com/celuveat/restaurant/application/port/out/ReadRestaurantPort.kt +++ b/src/main/kotlin/com/celuveat/restaurant/application/port/out/ReadRestaurantPort.kt @@ -37,4 +37,6 @@ interface ReadRestaurantPort { startOfDate: LocalDate, endOfDate: LocalDate, ): List + + fun readByName(name: String): List } diff --git a/src/main/kotlin/com/celuveat/search/adapter/in/rest/SearchApi.kt b/src/main/kotlin/com/celuveat/search/adapter/in/rest/SearchApi.kt new file mode 100644 index 0000000..3265b21 --- /dev/null +++ b/src/main/kotlin/com/celuveat/search/adapter/in/rest/SearchApi.kt @@ -0,0 +1,24 @@ +package com.celuveat.search.adapter.`in`.rest + +import com.celuveat.search.adapter.`in`.rest.response.IntegratedSearchResponse +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestParam + +@Tag(name = "검색 API") +interface SearchApi { + @Operation(summary = "지역, 셀럽, 음식점 통합 검색") + @GetMapping("/integrated") + fun integratedSearch( + @Parameter( + `in` = ParameterIn.QUERY, + description = "이름", + example = "감자", + required = true, + ) + @RequestParam(name = "name") name: String, + ): IntegratedSearchResponse +} diff --git a/src/main/kotlin/com/celuveat/search/adapter/in/rest/SearchController.kt b/src/main/kotlin/com/celuveat/search/adapter/in/rest/SearchController.kt new file mode 100644 index 0000000..d636906 --- /dev/null +++ b/src/main/kotlin/com/celuveat/search/adapter/in/rest/SearchController.kt @@ -0,0 +1,22 @@ +package com.celuveat.search.adapter.`in`.rest + +import com.celuveat.search.adapter.`in`.rest.response.IntegratedSearchResponse +import com.celuveat.search.application.port.`in`.IntegratedSearchUseCase +import com.celuveat.search.application.port.`in`.query.IntegratedSearchQuery +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 + +@RequestMapping("/search") +@RestController +class SearchController( + private val integratedSearchUseCase: IntegratedSearchUseCase, +) : SearchApi { + @GetMapping("/integrated") + override fun integratedSearch( + @RequestParam(name = "name") name: String, + ): IntegratedSearchResponse { + return IntegratedSearchResponse.from(integratedSearchUseCase.searchByName(IntegratedSearchQuery(name))) + } +} diff --git a/src/main/kotlin/com/celuveat/search/adapter/in/rest/response/IntegratedSearchResonse.kt b/src/main/kotlin/com/celuveat/search/adapter/in/rest/response/IntegratedSearchResonse.kt new file mode 100644 index 0000000..d876cbe --- /dev/null +++ b/src/main/kotlin/com/celuveat/search/adapter/in/rest/response/IntegratedSearchResonse.kt @@ -0,0 +1,52 @@ +package com.celuveat.search.adapter.`in`.rest.response + +import com.celuveat.search.application.port.`in`.result.IntegratedSearchResult +import com.celuveat.search.application.port.`in`.result.RegionResult +import io.swagger.v3.oas.annotations.media.Schema + +data class IntegratedSearchResponse( + val regionResults: List, + val restaurantResults: List, + val celebrityResults: List, +) { + companion object { + fun from(result: IntegratedSearchResult): IntegratedSearchResponse { + return IntegratedSearchResponse( + regionResults = result.regionResults.map { RegionResponse.from(it) }, + restaurantResults = result.restaurantResults.map { ResponseWithId(id = it.id, name = it.name) }, + celebrityResults = result.celebrityResults.map { ResponseWithId(id = it.id, name = it.name) }, + ) + } + } +} + +data class ResponseWithId( + val id: Long, + val name: String, +) + +data class RegionResponse( + val id: Long, + val name: String, + @Schema( + description = "위도", + example = "37.123456", + ) + val latitude: Double, + @Schema( + description = "경도", + example = "127.123456", + ) + val longitude: Double, +) { + companion object { + fun from(result: RegionResult): RegionResponse { + return RegionResponse( + id = result.id, + name = result.name, + latitude = result.latitude, + longitude = result.longitude, + ) + } + } +} diff --git a/src/main/kotlin/com/celuveat/search/application/SearchQueryService.kt b/src/main/kotlin/com/celuveat/search/application/SearchQueryService.kt new file mode 100644 index 0000000..ec09734 --- /dev/null +++ b/src/main/kotlin/com/celuveat/search/application/SearchQueryService.kt @@ -0,0 +1,23 @@ +package com.celuveat.search.application + +import com.celuveat.celeb.application.port.out.ReadCelebritiesPort +import com.celuveat.region.application.port.out.ReadRegionPort +import com.celuveat.restaurant.application.port.out.ReadRestaurantPort +import com.celuveat.search.application.port.`in`.IntegratedSearchUseCase +import com.celuveat.search.application.port.`in`.query.IntegratedSearchQuery +import com.celuveat.search.application.port.`in`.result.IntegratedSearchResult +import org.springframework.stereotype.Service + +@Service +class SearchQueryService( + private val readRegionPort: ReadRegionPort, + private val readRestaurantPort: ReadRestaurantPort, + private val readCelebritiesPort: ReadCelebritiesPort, +) : IntegratedSearchUseCase { + override fun searchByName(query: IntegratedSearchQuery): IntegratedSearchResult { + val regions = readRegionPort.readByName(query.name) + val restaurants = readRestaurantPort.readByName(query.name) + val celebrities = readCelebritiesPort.readByName(query.name) + return IntegratedSearchResult.of(regions = regions, restaurants = restaurants, celebrities = celebrities) + } +} diff --git a/src/main/kotlin/com/celuveat/search/application/port/in/IntegratedSearchUseCase.kt b/src/main/kotlin/com/celuveat/search/application/port/in/IntegratedSearchUseCase.kt new file mode 100644 index 0000000..d0a4bcf --- /dev/null +++ b/src/main/kotlin/com/celuveat/search/application/port/in/IntegratedSearchUseCase.kt @@ -0,0 +1,8 @@ +package com.celuveat.search.application.port.`in` + +import com.celuveat.search.application.port.`in`.query.IntegratedSearchQuery +import com.celuveat.search.application.port.`in`.result.IntegratedSearchResult + +interface IntegratedSearchUseCase { + fun searchByName(query: IntegratedSearchQuery): IntegratedSearchResult +} diff --git a/src/main/kotlin/com/celuveat/search/application/port/in/query/IntegratedSearchQuery.kt b/src/main/kotlin/com/celuveat/search/application/port/in/query/IntegratedSearchQuery.kt new file mode 100644 index 0000000..220e71f --- /dev/null +++ b/src/main/kotlin/com/celuveat/search/application/port/in/query/IntegratedSearchQuery.kt @@ -0,0 +1,5 @@ +package com.celuveat.search.application.port.`in`.query + +data class IntegratedSearchQuery( + val name: String, +) diff --git a/src/main/kotlin/com/celuveat/search/application/port/in/result/IntegratedSearchResult.kt b/src/main/kotlin/com/celuveat/search/application/port/in/result/IntegratedSearchResult.kt new file mode 100644 index 0000000..5febac8 --- /dev/null +++ b/src/main/kotlin/com/celuveat/search/application/port/in/result/IntegratedSearchResult.kt @@ -0,0 +1,57 @@ +package com.celuveat.search.application.port.`in`.result + +import com.celuveat.celeb.domain.Celebrity +import com.celuveat.region.domain.Region +import com.celuveat.restaurant.domain.Restaurant +import io.swagger.v3.oas.annotations.media.Schema + +data class IntegratedSearchResult( + val regionResults: List, + val restaurantResults: List, + val celebrityResults: List, +) { + companion object { + fun of( + regions: List, + restaurants: List, + celebrities: List, + ): IntegratedSearchResult { + return IntegratedSearchResult( + regionResults = regions.map { RegionResult.from(it) }, + restaurantResults = restaurants.map { ResultWithId(id = it.id, name = it.name) }, + celebrityResults = celebrities.map { ResultWithId(id = it.id, name = it.name) }, + ) + } + } +} + +data class ResultWithId( + val id: Long, + val name: String, +) + +data class RegionResult( + val id: Long, + val name: String, + @Schema( + description = "위도", + example = "37.123456", + ) + val latitude: Double, + @Schema( + description = "경도", + example = "127.123456", + ) + val longitude: Double, +) { + companion object { + fun from(result: Region): RegionResult { + return RegionResult( + id = result.id, + name = result.name, + latitude = result.latitude, + longitude = result.longitude, + ) + } + } +} diff --git a/src/test/kotlin/com/celuveat/celeb/adapter/out/persistence/CelebrityPersistenceAdapterTest.kt b/src/test/kotlin/com/celuveat/celeb/adapter/out/persistence/CelebrityPersistenceAdapterTest.kt index 5c1b4fc..dc419b5 100644 --- a/src/test/kotlin/com/celuveat/celeb/adapter/out/persistence/CelebrityPersistenceAdapterTest.kt +++ b/src/test/kotlin/com/celuveat/celeb/adapter/out/persistence/CelebrityPersistenceAdapterTest.kt @@ -17,6 +17,7 @@ import com.celuveat.support.sut import com.navercorp.fixturemonkey.kotlin.giveMeBuilder import com.navercorp.fixturemonkey.kotlin.giveMeOne import com.navercorp.fixturemonkey.kotlin.set +import com.navercorp.fixturemonkey.kotlin.setExp import io.kotest.assertions.assertSoftly import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.collections.shouldContainExactly @@ -238,6 +239,32 @@ class CelebrityPersistenceAdapterTest( celebrities.size shouldBe 1 celebrities[0].id shouldBe celebrity.id } + + test("이름으로 셀럽을 조회한다") { + // given + celebrityJpaRepository.saveAll( + listOf( + sut.giveMeBuilder() + .setExp(CelebrityJpaEntity::name, "말랑") + .sample(), + sut.giveMeBuilder() + .setExp(CelebrityJpaEntity::name, "말랭") + .sample(), + sut.giveMeBuilder() + .setExp(CelebrityJpaEntity::name, "로이스") + .sample(), + sut.giveMeBuilder() + .setExp(CelebrityJpaEntity::name, "로말스") + .sample(), + ), + ) + + // when + val celebrities = celebrityPersistenceAdapter.readByName("말") + + // then + celebrities.size shouldBe 3 + } }) private fun generateCelebrityYoutubeContent( diff --git a/src/test/kotlin/com/celuveat/region/adapter/out/persistence/RegionPersistenceAdapterTest.kt b/src/test/kotlin/com/celuveat/region/adapter/out/persistence/RegionPersistenceAdapterTest.kt new file mode 100644 index 0000000..76b34f4 --- /dev/null +++ b/src/test/kotlin/com/celuveat/region/adapter/out/persistence/RegionPersistenceAdapterTest.kt @@ -0,0 +1,46 @@ +package com.celuveat.region.adapter.out.persistence + +import com.celuveat.region.adapter.out.persistence.entity.RegionJpaEntity +import com.celuveat.region.adapter.out.persistence.entity.RegionJpaRepository +import com.celuveat.support.PersistenceAdapterTest +import com.celuveat.support.sut +import com.navercorp.fixturemonkey.kotlin.giveMeBuilder +import com.navercorp.fixturemonkey.kotlin.setExp +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe + +@PersistenceAdapterTest +class RegionPersistenceAdapterTest( + private val regionPersistenceAdapter: RegionPersistenceAdapter, + private val regionJpaRepository: RegionJpaRepository, +) : FunSpec({ + test("지역 이름으로 검색한다.") { + // given + regionJpaRepository.saveAll( + listOf( + sut.giveMeBuilder() + .setExp(RegionJpaEntity::name, "서울 도봉구") + .sample(), + sut.giveMeBuilder() + .setExp(RegionJpaEntity::name, "서울 노원구") + .sample(), + sut.giveMeBuilder() + .setExp(RegionJpaEntity::name, "경기 순천") + .sample(), + sut.giveMeBuilder() + .setExp(RegionJpaEntity::name, "전남 순천") + .sample(), + ), + ) + + // when + val result1 = regionPersistenceAdapter.readByName("서울") + val result2 = regionPersistenceAdapter.readByName("순천") + val result3 = regionPersistenceAdapter.readByName("도봉") + + // then + result1.size shouldBe 2 + result2.size shouldBe 2 + result3.size shouldBe 1 + } +}) diff --git a/src/test/kotlin/com/celuveat/restaurant/adapter/in/rest/RestaurantControllerTest.kt b/src/test/kotlin/com/celuveat/restaurant/adapter/in/rest/RestaurantControllerTest.kt index 5739d48..fa8a744 100644 --- a/src/test/kotlin/com/celuveat/restaurant/adapter/in/rest/RestaurantControllerTest.kt +++ b/src/test/kotlin/com/celuveat/restaurant/adapter/in/rest/RestaurantControllerTest.kt @@ -433,7 +433,7 @@ class RestaurantControllerTest( .sampleList(3) val response = results.map(RestaurantPreviewResponse::from) val query = ReadPopularRestaurantQuery(memberId = null) - + every { readPopularRestaurantsUseCase.readPopularRestaurants(query) } returns results mockMvc.get("/restaurants/popular") { 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 6b721bb..1ee5813 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 @@ -332,4 +332,34 @@ class RestaurantPersistenceAdapterTest( interestedRestaurants.size shouldBe 2 interestedRestaurants.map { it.id } shouldContainAll listOf(restaurantB.id, restaurantA.id) } + + test("이름으로 음식점을 조회한다.") { + // given + restaurantJpaRepository.saveAll( + listOf( + sut.giveMeBuilder() + .setExp(RestaurantJpaEntity::name, "말랑이의 감자탕") + .sample(), + sut.giveMeBuilder() + .setExp(RestaurantJpaEntity::name, "말랑이의감자탕") + .sample(), + sut.giveMeBuilder() + .setExp(RestaurantJpaEntity::name, "말랑이의 삼계탕") + .sample(), + sut.giveMeBuilder() + .setExp(RestaurantJpaEntity::name, "로이스의 감자탕") + .sample(), + ), + ) + + // when + val result1 = restaurantPersistenceAdapter.readByName("감자") + val result2 = restaurantPersistenceAdapter.readByName("말랑") + val result3 = restaurantPersistenceAdapter.readByName("의 감") + + // then + result1.size shouldBe 3 + result2.size shouldBe 3 + result3.size shouldBe 2 + } }) diff --git a/src/test/kotlin/com/celuveat/restaurant/application/RestaurantQueryServiceTest.kt b/src/test/kotlin/com/celuveat/restaurant/application/RestaurantQueryServiceTest.kt index cb49b28..6f5c8a0 100644 --- a/src/test/kotlin/com/celuveat/restaurant/application/RestaurantQueryServiceTest.kt +++ b/src/test/kotlin/com/celuveat/restaurant/application/RestaurantQueryServiceTest.kt @@ -469,7 +469,7 @@ class RestaurantQueryServiceTest : BehaviorSpec({ every { readInterestedRestaurantPort.readInterestedRestaurantsByIds( memberId, - restaurantIds + restaurantIds, ) } returns interestedRestaurants