Use JPA repo for local pincode resolution
All checks were successful
build-and-deploy / build-deploy (push) Successful in 40s
All checks were successful
build-and-deploy / build-deploy (push) Successful in 40s
This commit is contained in:
@@ -1,76 +0,0 @@
|
|||||||
package com.android.trisolarisserver.component.geo
|
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.springframework.jdbc.core.JdbcTemplate
|
|
||||||
import org.springframework.stereotype.Component
|
|
||||||
|
|
||||||
@Component
|
|
||||||
class LocalPincodeDirectoryClient(
|
|
||||||
private val jdbcTemplate: JdbcTemplate
|
|
||||||
) {
|
|
||||||
private val logger = LoggerFactory.getLogger(LocalPincodeDirectoryClient::class.java)
|
|
||||||
|
|
||||||
fun resolve(pinCode: String): PincodeLookupResult {
|
|
||||||
val normalizedPin = pinCode.trim()
|
|
||||||
if (!PIN_REGEX.matches(normalizedPin)) {
|
|
||||||
return PincodeLookupResult(
|
|
||||||
resolvedCityState = null,
|
|
||||||
rawResponse = null,
|
|
||||||
status = "INVALID_PIN",
|
|
||||||
source = "local-db",
|
|
||||||
errorMessage = "PIN must be 6 digits"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val rows = jdbcTemplate.query(
|
|
||||||
"""
|
|
||||||
select city, state
|
|
||||||
from india_pincode_city_state
|
|
||||||
where pincode = ?
|
|
||||||
and nullif(trim(city), '') is not null
|
|
||||||
and nullif(trim(state), '') is not null
|
|
||||||
group by city, state
|
|
||||||
order by count(*) desc, city asc, state asc
|
|
||||||
limit 1
|
|
||||||
""".trimIndent(),
|
|
||||||
{ rs, _ ->
|
|
||||||
val city = rs.getString("city")?.trim()?.ifBlank { null }
|
|
||||||
val state = rs.getString("state")?.trim()?.ifBlank { null }
|
|
||||||
if (city == null || state == null) null else "$city, $state"
|
|
||||||
},
|
|
||||||
normalizedPin.toInt()
|
|
||||||
).filterNotNull()
|
|
||||||
|
|
||||||
val resolved = rows.firstOrNull()
|
|
||||||
if (resolved != null) {
|
|
||||||
PincodeLookupResult(
|
|
||||||
resolvedCityState = resolved,
|
|
||||||
rawResponse = null,
|
|
||||||
status = "OK",
|
|
||||||
source = "local-db"
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
PincodeLookupResult(
|
|
||||||
resolvedCityState = null,
|
|
||||||
rawResponse = null,
|
|
||||||
status = "ZERO_RESULTS",
|
|
||||||
source = "local-db"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
logger.warn("Local pincode lookup failed: {}", ex.message)
|
|
||||||
PincodeLookupResult(
|
|
||||||
resolvedCityState = null,
|
|
||||||
rawResponse = null,
|
|
||||||
status = "ERROR",
|
|
||||||
source = "local-db",
|
|
||||||
errorMessage = ex.message
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val PIN_REGEX = Regex("\\d{6}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,21 @@
|
|||||||
package com.android.trisolarisserver.component.geo
|
package com.android.trisolarisserver.component.geo
|
||||||
|
|
||||||
|
import com.android.trisolarisserver.repo.property.IndiaPincodeCityStateRepo
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.data.domain.PageRequest
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class PincodeResolver(
|
class PincodeResolver(
|
||||||
private val localPincodeDirectoryClient: LocalPincodeDirectoryClient,
|
private val indiaPincodeCityStateRepo: IndiaPincodeCityStateRepo,
|
||||||
private val dataGovPincodeClient: DataGovPincodeClient,
|
private val dataGovPincodeClient: DataGovPincodeClient,
|
||||||
private val postalPincodeClient: PostalPincodeClient,
|
private val postalPincodeClient: PostalPincodeClient,
|
||||||
private val googleGeocodingClient: GoogleGeocodingClient
|
private val googleGeocodingClient: GoogleGeocodingClient
|
||||||
) {
|
) {
|
||||||
|
private val logger = LoggerFactory.getLogger(PincodeResolver::class.java)
|
||||||
|
|
||||||
fun resolve(pinCode: String): PincodeResolveResult {
|
fun resolve(pinCode: String): PincodeResolveResult {
|
||||||
val primary = localPincodeDirectoryClient.resolve(pinCode)
|
val primary = resolveFromLocalDb(pinCode)
|
||||||
if (primary.status == "OK" && primary.resolvedCityState != null) {
|
if (primary.status == "OK" && primary.resolvedCityState != null) {
|
||||||
return PincodeResolveResult(primary, null, null, null)
|
return PincodeResolveResult(primary, null, null, null)
|
||||||
}
|
}
|
||||||
@@ -34,6 +39,53 @@ class PincodeResolver(
|
|||||||
)
|
)
|
||||||
return PincodeResolveResult(primary, secondary, tertiary, quaternary)
|
return PincodeResolveResult(primary, secondary, tertiary, quaternary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun resolveFromLocalDb(pinCode: String): PincodeLookupResult {
|
||||||
|
val normalizedPin = pinCode.trim()
|
||||||
|
if (!PIN_REGEX.matches(normalizedPin)) {
|
||||||
|
return PincodeLookupResult(
|
||||||
|
resolvedCityState = null,
|
||||||
|
rawResponse = null,
|
||||||
|
status = "INVALID_PIN",
|
||||||
|
source = "local-db",
|
||||||
|
errorMessage = "PIN must be 6 digits"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return try {
|
||||||
|
val candidate = indiaPincodeCityStateRepo
|
||||||
|
.findCityStateCandidates(normalizedPin.toInt(), PageRequest.of(0, 1))
|
||||||
|
.firstOrNull()
|
||||||
|
if (candidate != null) {
|
||||||
|
PincodeLookupResult(
|
||||||
|
resolvedCityState = "${candidate.city}, ${candidate.state}",
|
||||||
|
rawResponse = null,
|
||||||
|
status = "OK",
|
||||||
|
source = "local-db"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
PincodeLookupResult(
|
||||||
|
resolvedCityState = null,
|
||||||
|
rawResponse = null,
|
||||||
|
status = "ZERO_RESULTS",
|
||||||
|
source = "local-db"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
logger.warn("Local pincode lookup failed: {}", ex.message)
|
||||||
|
PincodeLookupResult(
|
||||||
|
resolvedCityState = null,
|
||||||
|
rawResponse = null,
|
||||||
|
status = "ERROR",
|
||||||
|
source = "local-db",
|
||||||
|
errorMessage = ex.message
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val PIN_REGEX = Regex("\\d{6}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class PincodeResolveResult(
|
data class PincodeResolveResult(
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.android.trisolarisserver.models.property
|
||||||
|
|
||||||
|
import jakarta.persistence.Column
|
||||||
|
import jakarta.persistence.Entity
|
||||||
|
import jakarta.persistence.GeneratedValue
|
||||||
|
import jakarta.persistence.Id
|
||||||
|
import jakarta.persistence.Table
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "india_pincode_city_state")
|
||||||
|
class IndiaPincodeCityState(
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
@Column(columnDefinition = "uuid")
|
||||||
|
val id: UUID? = null,
|
||||||
|
|
||||||
|
@Column(name = "pincode", nullable = false)
|
||||||
|
val pincode: Int,
|
||||||
|
|
||||||
|
@Column(name = "locality", nullable = false)
|
||||||
|
val locality: String,
|
||||||
|
|
||||||
|
@Column(name = "city", nullable = false)
|
||||||
|
val city: String,
|
||||||
|
|
||||||
|
@Column(name = "state", nullable = false)
|
||||||
|
val state: String,
|
||||||
|
|
||||||
|
@Column(name = "source_file")
|
||||||
|
val sourceFile: String? = null,
|
||||||
|
|
||||||
|
@Column(name = "imported_at", columnDefinition = "timestamptz")
|
||||||
|
val importedAt: OffsetDateTime? = null
|
||||||
|
)
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.android.trisolarisserver.repo.property
|
||||||
|
|
||||||
|
import com.android.trisolarisserver.models.property.IndiaPincodeCityState
|
||||||
|
import org.springframework.data.domain.Pageable
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
import org.springframework.data.jpa.repository.Query
|
||||||
|
import org.springframework.data.repository.query.Param
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
interface IndiaPincodeCityStateRepo : JpaRepository<IndiaPincodeCityState, UUID> {
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
select p.city as city,
|
||||||
|
p.state as state,
|
||||||
|
count(p.id) as hitCount
|
||||||
|
from IndiaPincodeCityState p
|
||||||
|
where p.pincode = :pincode
|
||||||
|
and trim(p.city) <> ''
|
||||||
|
and trim(p.state) <> ''
|
||||||
|
group by p.city, p.state
|
||||||
|
order by count(p.id) desc, p.city asc, p.state asc
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
fun findCityStateCandidates(
|
||||||
|
@Param("pincode") pincode: Int,
|
||||||
|
pageable: Pageable
|
||||||
|
): List<PincodeCityStateCandidate>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PincodeCityStateCandidate {
|
||||||
|
val city: String
|
||||||
|
val state: String
|
||||||
|
val hitCount: Long
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user