generated from pricelees/issue-pr-template
[#44] 매장 기능 도입 #45
@ -46,29 +46,14 @@ class RegionService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
fun findDongBySidoAndSigungu(sidoCode: String, sigunguCode: String): DongListResponse {
|
fun findRegionCode(sidoCode: String, sigunguCode: String): RegionCodeResponse {
|
||||||
log.info { "[RegionService.findDongBySidoAndSigungu] 행정동 조회 시작: sidoCode=${sidoCode} / sigunguCode=${sigunguCode}" }
|
log.info { "[RegionService.findRegionCode] 지역 코드 조회 시작: sidoCode=${sidoCode} / sigunguCode=${sigunguCode}" }
|
||||||
val result: List<Pair<String, String>> = regionRepository.findAllDongBySidoAndSigungu(sidoCode, sigunguCode)
|
|
||||||
|
|
||||||
if (result.isEmpty()) {
|
return regionRepository.findRegionCode(sidoCode, sigunguCode)?.let {
|
||||||
log.warn { "[RegionService.findDongBySidoAndSigungu] 행정동 조회 실패: sidoCode=${sidoCode} / sigunguCode=${sigunguCode}" }
|
log.info { "[RegionService.findRegionCode] 지역 코드 조회 완료: code=${it} sidoCode=${sidoCode} / sigunguCode=${sigunguCode}" }
|
||||||
throw RegionException(RegionErrorCode.DONG_CODE_NOT_FOUND)
|
|
||||||
}
|
|
||||||
|
|
||||||
return DongListResponse(result.map { DongResponse(code = it.first, name = it.second) }).also {
|
|
||||||
log.info { "[RegionService.findDongBySidoAndSigungu] sidoCode=${sidoCode}, sigunguCode=${sigunguCode}인 ${it.dongList.size}개의 행정동 조회 완료" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
|
||||||
fun findRegionCode(sidoCode: String, sigunguCode: String, dongCode: String): RegionCodeResponse {
|
|
||||||
log.info { "[RegionService.findRegionCode] 지역 코드 조회 시작: sidoCode=${sidoCode} / sigunguCode=${sigunguCode} / dongCode=${dongCode}" }
|
|
||||||
|
|
||||||
return regionRepository.findRegionCode(sidoCode, sigunguCode, dongCode)?.let {
|
|
||||||
log.info { "[RegionService.findRegionCode] 지역 코드 조회 완료: code=${it} sidoCode=${sidoCode} / sigunguCode=${sigunguCode} / dongCode=${dongCode}" }
|
|
||||||
RegionCodeResponse(it)
|
RegionCodeResponse(it)
|
||||||
} ?: run {
|
} ?: run {
|
||||||
log.warn { "[RegionService.findRegionCode] 지역 코드 조회 실패: sidoCode=${sidoCode} / sigunguCode=${sigunguCode} / dongCode=${dongCode}" }
|
log.warn { "[RegionService.findRegionCode] 지역 코드 조회 실패: sidoCode=${sidoCode} / sigunguCode=${sigunguCode}" }
|
||||||
throw RegionException(RegionErrorCode.REGION_CODE_NOT_FOUND)
|
throw RegionException(RegionErrorCode.REGION_CODE_NOT_FOUND)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ interface RegionAPI {
|
|||||||
fun findRegionCode(
|
fun findRegionCode(
|
||||||
@RequestParam(name = "sidoCode", required = true) sidoCode: String,
|
@RequestParam(name = "sidoCode", required = true) sidoCode: String,
|
||||||
@RequestParam(name = "sigunguCode", required = true) sigunguCode: String,
|
@RequestParam(name = "sigunguCode", required = true) sigunguCode: String,
|
||||||
@RequestParam(name = "dongCode", required = true) dongCode: String,
|
|
||||||
): ResponseEntity<CommonApiResponse<RegionCodeResponse>>
|
): ResponseEntity<CommonApiResponse<RegionCodeResponse>>
|
||||||
|
|
||||||
@Public
|
@Public
|
||||||
@ -34,12 +33,4 @@ interface RegionAPI {
|
|||||||
fun findAllSigunguBySido(
|
fun findAllSigunguBySido(
|
||||||
@RequestParam(required = true) sidoCode: String
|
@RequestParam(required = true) sidoCode: String
|
||||||
): ResponseEntity<CommonApiResponse<SigunguListResponse>>
|
): ResponseEntity<CommonApiResponse<SigunguListResponse>>
|
||||||
|
|
||||||
@Public
|
|
||||||
@Operation(summary = "모든 행정동 목록 조회")
|
|
||||||
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
|
|
||||||
fun findAllDongBySigungu(
|
|
||||||
@RequestParam(name = "sidoCode", required = true) sidoCode: String,
|
|
||||||
@RequestParam(name = "sigunguCode", required = true) sigunguCode: String
|
|
||||||
): ResponseEntity<CommonApiResponse<DongListResponse>>
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,16 +3,15 @@ package roomescape.region.infrastructure.persistence
|
|||||||
import jakarta.persistence.Entity
|
import jakarta.persistence.Entity
|
||||||
import jakarta.persistence.Id
|
import jakarta.persistence.Id
|
||||||
import jakarta.persistence.Table
|
import jakarta.persistence.Table
|
||||||
|
import jakarta.persistence.UniqueConstraint
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "region")
|
@Table(name = "region", uniqueConstraints = [UniqueConstraint(columnNames = ["sidoCode", "sigunguCode"])])
|
||||||
class RegionEntity(
|
class RegionEntity(
|
||||||
@Id
|
@Id
|
||||||
val code: String,
|
val code: String,
|
||||||
val sidoCode: String,
|
val sidoCode: String,
|
||||||
val sigunguCode: String,
|
val sigunguCode: String,
|
||||||
val dongCode: String,
|
|
||||||
val sidoName: String,
|
val sidoName: String,
|
||||||
val sigunguName: String,
|
val sigunguName: String,
|
||||||
val dongName: String,
|
|
||||||
)
|
)
|
||||||
|
|||||||
@ -34,22 +34,6 @@ interface RegionRepository : JpaRepository<RegionEntity, String> {
|
|||||||
@Param("sidoCode") sidoCode: String
|
@Param("sidoCode") sidoCode: String
|
||||||
): List<Pair<String, String>>
|
): List<Pair<String, String>>
|
||||||
|
|
||||||
@Query("""
|
|
||||||
SELECT
|
|
||||||
new kotlin.Pair(r.dongCode, r.dongName)
|
|
||||||
FROM
|
|
||||||
RegionEntity r
|
|
||||||
WHERE
|
|
||||||
r.sidoCode = :sidoCode
|
|
||||||
AND r.sigunguCode = :sigunguCode
|
|
||||||
ORDER BY
|
|
||||||
r.dongName
|
|
||||||
""")
|
|
||||||
fun findAllDongBySidoAndSigungu(
|
|
||||||
@Param("sidoCode") sidoCode: String,
|
|
||||||
@Param("sigunguCode") sigunguCode: String
|
|
||||||
): List<Pair<String, String>>
|
|
||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT
|
SELECT
|
||||||
r.code
|
r.code
|
||||||
@ -58,11 +42,9 @@ interface RegionRepository : JpaRepository<RegionEntity, String> {
|
|||||||
WHERE
|
WHERE
|
||||||
r.sidoCode = :sidoCode
|
r.sidoCode = :sidoCode
|
||||||
AND r.sigunguCode = :sigunguCode
|
AND r.sigunguCode = :sigunguCode
|
||||||
AND r.dongCode = :dongCode
|
|
||||||
""")
|
""")
|
||||||
fun findRegionCode(
|
fun findRegionCode(
|
||||||
@Param("sidoCode") sidoCode: String,
|
@Param("sidoCode") sidoCode: String,
|
||||||
@Param("sigunguCode") sigunguCode: String,
|
@Param("sigunguCode") sigunguCode: String,
|
||||||
@Param("dongCode") dongCode: String,
|
|
||||||
): String?
|
): String?
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,9 +18,8 @@ class RegionController(
|
|||||||
override fun findRegionCode(
|
override fun findRegionCode(
|
||||||
@RequestParam(name = "sidoCode", required = true) sidoCode: String,
|
@RequestParam(name = "sidoCode", required = true) sidoCode: String,
|
||||||
@RequestParam(name = "sigunguCode", required = true) sigunguCode: String,
|
@RequestParam(name = "sigunguCode", required = true) sigunguCode: String,
|
||||||
@RequestParam(name = "dongCode", required = true) dongCode: String,
|
|
||||||
): ResponseEntity<CommonApiResponse<RegionCodeResponse>> {
|
): ResponseEntity<CommonApiResponse<RegionCodeResponse>> {
|
||||||
val response = regionService.findRegionCode(sidoCode, sigunguCode, dongCode)
|
val response = regionService.findRegionCode(sidoCode, sigunguCode)
|
||||||
|
|
||||||
return ResponseEntity.ok(CommonApiResponse(response))
|
return ResponseEntity.ok(CommonApiResponse(response))
|
||||||
}
|
}
|
||||||
@ -40,14 +39,4 @@ class RegionController(
|
|||||||
|
|
||||||
return ResponseEntity.ok(CommonApiResponse(response))
|
return ResponseEntity.ok(CommonApiResponse(response))
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/dong")
|
|
||||||
override fun findAllDongBySigungu(
|
|
||||||
@RequestParam(name = "sidoCode", required = true) sidoCode: String,
|
|
||||||
@RequestParam(name = "sigunguCode", required = true) sigunguCode: String
|
|
||||||
): ResponseEntity<CommonApiResponse<DongListResponse>> {
|
|
||||||
val response = regionService.findDongBySidoAndSigungu(sidoCode, sigunguCode)
|
|
||||||
|
|
||||||
return ResponseEntity.ok(CommonApiResponse(response))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -2,10 +2,39 @@ create table if not exists region (
|
|||||||
code varchar(10) primary key,
|
code varchar(10) primary key,
|
||||||
sido_code varchar(2) not null,
|
sido_code varchar(2) not null,
|
||||||
sigungu_code varchar(3) not null,
|
sigungu_code varchar(3) not null,
|
||||||
dong_code varchar(5) not null ,
|
|
||||||
sido_name varchar(20) not null,
|
sido_name varchar(20) not null,
|
||||||
sigungu_name varchar(20) not null,
|
sigungu_name varchar(20) not null,
|
||||||
dong_name varchar(20) not null
|
|
||||||
|
constraint uk_region__sido_sigungu_code unique (sido_code, sigungu_code)
|
||||||
|
);
|
||||||
|
|
||||||
|
create table if not exists store(
|
||||||
|
id bigint primary key,
|
||||||
|
name varchar(20) not null,
|
||||||
|
address varchar(100) not null,
|
||||||
|
business_reg_num varchar(10) not null,
|
||||||
|
region_code varchar(10) not null,
|
||||||
|
|
||||||
|
created_at timestamp not null,
|
||||||
|
updated_at timestamp not null,
|
||||||
|
|
||||||
|
constraint uk_store__business_reg_num unique (business_reg_num),
|
||||||
|
constraint fk_store__sido_code foreign key (region_code) references region (code)
|
||||||
|
);
|
||||||
|
|
||||||
|
create table if not exists room(
|
||||||
|
id bigint primary key ,
|
||||||
|
name varchar(20) not null,
|
||||||
|
store_id bigint not null,
|
||||||
|
max_capacity smallint not null,
|
||||||
|
status varchar(20) not null,
|
||||||
|
|
||||||
|
created_at timestamp not null,
|
||||||
|
created_by bigint not null,
|
||||||
|
updated_at timestamp not null,
|
||||||
|
updated_by bigint not null,
|
||||||
|
|
||||||
|
constraint fk_room__store_id foreign key (store_id) references store (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
create table if not exists users(
|
create table if not exists users(
|
||||||
|
|||||||
@ -37,26 +37,14 @@ class RegionApiFailTest(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("행정동") {
|
|
||||||
every {
|
|
||||||
regionRepository.findAllDongBySidoAndSigungu(any(), any())
|
|
||||||
} returns emptyList()
|
|
||||||
|
|
||||||
runExceptionTest(
|
|
||||||
method = HttpMethod.GET,
|
|
||||||
endpoint = "/regions/dong?sidoCode=11&sigunguCode=110",
|
|
||||||
expectedErrorCode = RegionErrorCode.DONG_CODE_NOT_FOUND,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
test("지역 코드") {
|
test("지역 코드") {
|
||||||
every {
|
every {
|
||||||
regionRepository.findRegionCode(any(), any(), any())
|
regionRepository.findRegionCode(any(), any())
|
||||||
} returns null
|
} returns null
|
||||||
|
|
||||||
runExceptionTest(
|
runExceptionTest(
|
||||||
method = HttpMethod.GET,
|
method = HttpMethod.GET,
|
||||||
endpoint = "/regions/code?sidoCode=11&sigunguCode=110&dongCode=10100",
|
endpoint = "/regions/code?sidoCode=11&sigunguCode=110",
|
||||||
expectedErrorCode = RegionErrorCode.REGION_CODE_NOT_FOUND,
|
expectedErrorCode = RegionErrorCode.REGION_CODE_NOT_FOUND,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import roomescape.supports.runTest
|
|||||||
|
|
||||||
class RegionApiSuccessTest: FunSpecSpringbootTest() {
|
class RegionApiSuccessTest: FunSpecSpringbootTest() {
|
||||||
init {
|
init {
|
||||||
context("시/도 -> 시/군/구 -> 행정동 -> 지역 코드 순으로 조회한다.") {
|
context("시/도 -> 시/군/구 -> 지역 코드 순으로 조회한다.") {
|
||||||
test("정상 응답") {
|
test("정상 응답") {
|
||||||
val sidoCode: String = runTest(
|
val sidoCode: String = runTest(
|
||||||
on = {
|
on = {
|
||||||
@ -33,25 +33,16 @@ class RegionApiSuccessTest: FunSpecSpringbootTest() {
|
|||||||
}
|
}
|
||||||
).extract().path("data.sigunguList[0].code")
|
).extract().path("data.sigunguList[0].code")
|
||||||
|
|
||||||
val dongCode: String = runTest(
|
|
||||||
on = {
|
|
||||||
get("/regions/dong?sidoCode=$sidoCode&sigunguCode=$sigunguCode")
|
|
||||||
},
|
|
||||||
expect = {
|
|
||||||
statusCode(HttpStatus.OK.value())
|
|
||||||
}
|
|
||||||
).extract().path("data.dongList[0].code")
|
|
||||||
|
|
||||||
val regionCode: String = runTest(
|
val regionCode: String = runTest(
|
||||||
on = {
|
on = {
|
||||||
get("/regions/code?sidoCode=$sidoCode&sigunguCode=$sigunguCode&dongCode=${dongCode}")
|
get("/regions/code?sidoCode=$sidoCode&sigunguCode=$sigunguCode")
|
||||||
},
|
},
|
||||||
expect = {
|
expect = {
|
||||||
statusCode(HttpStatus.OK.value())
|
statusCode(HttpStatus.OK.value())
|
||||||
}
|
}
|
||||||
).extract().path("data.code")
|
).extract().path("data.code")
|
||||||
|
|
||||||
regionCode shouldBe "$sidoCode$sigunguCode$dongCode"
|
regionCode shouldBe "$sidoCode$sigunguCode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,7 +52,7 @@ object UserFixture {
|
|||||||
email: String = "sample@example.com",
|
email: String = "sample@example.com",
|
||||||
password: String = "a".repeat(MIN_PASSWORD_LENGTH),
|
password: String = "a".repeat(MIN_PASSWORD_LENGTH),
|
||||||
phone: String = "01012345678",
|
phone: String = "01012345678",
|
||||||
regionCode: String = "1111010100",
|
regionCode: String = "1111000000",
|
||||||
status: UserStatus = UserStatus.ACTIVE
|
status: UserStatus = UserStatus.ACTIVE
|
||||||
): UserEntity = UserEntity(
|
): UserEntity = UserEntity(
|
||||||
id = id,
|
id = id,
|
||||||
@ -69,7 +69,7 @@ object UserFixture {
|
|||||||
email = "sample@example.com",
|
email = "sample@example.com",
|
||||||
password = "a".repeat(MIN_PASSWORD_LENGTH),
|
password = "a".repeat(MIN_PASSWORD_LENGTH),
|
||||||
phone = "01012345678",
|
phone = "01012345678",
|
||||||
regionCode = "1111010100"
|
regionCode = "1111000000"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user