[#44] 매장 기능 도입 #45

Merged
pricelees merged 116 commits from feat/#44 into main 2025-09-20 03:15:06 +00:00
Showing only changes of commit f4d7b30452 - Show all commits

View File

@ -4,12 +4,19 @@ import io.kotest.core.spec.style.StringSpec
import org.apache.poi.xssf.usermodel.XSSFWorkbook import org.apache.poi.xssf.usermodel.XSSFWorkbook
import java.io.File import java.io.File
const val BASE_DIR = "data"
const val PARSED_REGION_POPULATION_FILE = "$BASE_DIR/region_population.txt"
const val REGION_SQL_FILE = "data/region.sql"
const val MIN_POPULATION_FOR_PER_STORE = 200_000
/**
* 행안부 202508 인구 동향 데이터 사용( /data/population.xlsx )
*/
class PopulationDataSqlParser() : StringSpec({ class PopulationDataSqlParser() : StringSpec({
val regionCodePattern = Regex("^[0-9]{10}$") val regionCodePattern = Regex("^[0-9]{10}$")
val minPopulation = 250_000
"인구 데이터를 이용하여 지역 정보 SQL 파일로 변환하고, 추가로 $minPopulation 이상의 시/군/구는 매장 데이터 생성을 위해 따로 분류한다." { "인구 데이터를 이용하여 지역 정보 SQL 파일로 변환하고, 추가로 $MIN_POPULATION_FOR_PER_STORE 이상의 시/군/구는 매장 데이터 생성을 위해 따로 분류한다." {
val populationXlsx = XSSFWorkbook(File("data/population.xlsx")) val populationXlsx = XSSFWorkbook(File("data/population.xlsx"))
val sheet = populationXlsx.getSheetAt(0) val sheet = populationXlsx.getSheetAt(0)
val allRegion = mutableListOf<List<String>>() val allRegion = mutableListOf<List<String>>()
@ -30,47 +37,46 @@ class PopulationDataSqlParser() : StringSpec({
} }
val regionName = row.getCell(1).stringCellValue val regionName = row.getCell(1).stringCellValue
if (!regionName.trim().contains(" ")) { if (!regionName.trim().contains(" ")) {
return@forEach return@forEach
} }
val parts = regionName.split(" ") val parts = regionName.split(" ")
if (parts.size < 2) {
return@forEach
}
val sidoName = parts[0].trim() val sidoName = parts[0].trim()
val sigunguName = parts[1].trim() val sigunguName = parts[1].trim()
val guName = if (parts.size > 2) parts[2].trim() else ""
val populationInt = population.toInt() val populationInt = population.toInt()
if (populationInt <= 0) { if (populationInt <= 0) {
return@forEach return@forEach
} }
if (populationInt > minPopulation) { if (populationInt >= MIN_POPULATION_FOR_PER_STORE) {
regionsMoreThanMinPopulation.add(listOf( regionsMoreThanMinPopulation.add(listOf(
regionCode, regionCode,
sidoCode, sidoCode,
sigunguCode, sigunguCode,
sidoName, sidoName,
sigunguName, sigunguName,
guName,
population population
) )
) )
} }
allRegion.add(listOf(regionCode, sidoCode, sigunguCode, sidoName, sigunguName)) allRegion.add(listOf(regionCode, sidoCode, sigunguCode, sidoName, sigunguName))
} }
regionsMoreThanMinPopulation.filter { regionsMoreThanMinPopulation.filter {
val sidoName = it[3]
val sigunguName = it[4] val sigunguName = it[4]
val sameSigungu = regionsMoreThanMinPopulation.filter { r -> r[4] == sigunguName } val sameSigungu = allRegion.filter { r -> r[3] == sidoName && r[4] == sigunguName }
!((sameSigungu.size > 1) && (it[5].isNullOrBlank())) !((sameSigungu.size > 1) && sameSigungu.minByOrNull { r -> r[2].toInt() }!![2] != it[2])
}.mapIndexed { idx, values -> }.mapIndexed { idx, values ->
val guName = if (values[5].isNullOrBlank()) "NULL" else "'${values[5]}'" "${values[0]}, ${values[1]}, ${values[2]}, ${values[3]}, ${values[4]}, ${values[5]}"
"${values[0]}, ${values[1]}, ${values[2]}, ${values[3]}, ${values[4]}, $guName, ${values[6]}"
}.joinToString(separator = "\n").also { }.joinToString(separator = "\n").also {
File("data/region_population.txt").writeText(it) File(PARSED_REGION_POPULATION_FILE).writeText(it)
} }
allRegion.distinctBy { it[1] to it[2] }.filter { allRegion.distinctBy { it[1] to it[2] }.filter {
@ -84,7 +90,7 @@ class PopulationDataSqlParser() : StringSpec({
) { region -> ) { region ->
"('${region[0]}', '${region[1]}', '${region[2]}', '${region[3]}', '${region[4]}')" "('${region[0]}', '${region[1]}', '${region[2]}', '${region[3]}', '${region[4]}')"
}.also { }.also {
File("data/region.sql").writeText("${it};") File(REGION_SQL_FILE).writeText("${it};")
} }
} }
}) })