Add city prefix search API using local pincode DB
All checks were successful
build-and-deploy / build-deploy (push) Successful in 35s
All checks were successful
build-and-deploy / build-deploy (push) Successful in 35s
This commit is contained in:
@@ -121,6 +121,33 @@ AUTH + SYSTEM APIS
|
||||
|
||||
- 401 Unauthorized (missing principal / user not found)
|
||||
|
||||
|
||||
- City search API is this one:
|
||||
|
||||
GET /geo/cities/search
|
||||
|
||||
What it does:
|
||||
|
||||
- Searches city names by prefix from local pincode directory table.
|
||||
- Returns unique city + state rows only.
|
||||
- Uses local DB only (no external API call in this endpoint).
|
||||
|
||||
Request body:
|
||||
|
||||
- None.
|
||||
|
||||
Query params:
|
||||
|
||||
- q (required, minimum 2 characters)
|
||||
- limit (optional, default 20, min 1, max 100)
|
||||
|
||||
- Allowed roles: authenticated Firebase user.
|
||||
|
||||
Error Codes
|
||||
|
||||
- 400 Bad Request (q too short)
|
||||
- 401 Unauthorized
|
||||
|
||||
================================================================================
|
||||
PROPERTY + USER APIS
|
||||
================================================================================
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.android.trisolarisserver.controller.system
|
||||
|
||||
import com.android.trisolarisserver.controller.common.requirePrincipal
|
||||
import com.android.trisolarisserver.repo.property.IndiaPincodeCityStateRepo
|
||||
import com.android.trisolarisserver.security.MyPrincipal
|
||||
import org.springframework.data.domain.PageRequest
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.server.ResponseStatusException
|
||||
|
||||
@RestController
|
||||
class GeoSearch(
|
||||
private val indiaPincodeCityStateRepo: IndiaPincodeCityStateRepo
|
||||
) {
|
||||
@GetMapping("/geo/cities/search")
|
||||
fun searchCities(
|
||||
@AuthenticationPrincipal principal: MyPrincipal?,
|
||||
@RequestParam("q") q: String,
|
||||
@RequestParam("limit", required = false, defaultValue = "20") limit: Int
|
||||
): List<CityStateResponse> {
|
||||
requirePrincipal(principal)
|
||||
val query = q.trim()
|
||||
if (query.length < 2) {
|
||||
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "q must be at least 2 characters")
|
||||
}
|
||||
val boundedLimit = limit.coerceIn(1, 100)
|
||||
return indiaPincodeCityStateRepo
|
||||
.searchCityStateByPrefix(query, PageRequest.of(0, boundedLimit))
|
||||
.map { CityStateResponse(city = it.city, state = it.state) }
|
||||
}
|
||||
}
|
||||
|
||||
data class CityStateResponse(
|
||||
val city: String,
|
||||
val state: String
|
||||
)
|
||||
@@ -25,6 +25,23 @@ interface IndiaPincodeCityStateRepo : JpaRepository<IndiaPincodeCityState, UUID>
|
||||
@Param("pincode") pincode: Int,
|
||||
pageable: Pageable
|
||||
): List<PincodeCityStateCandidate>
|
||||
|
||||
@Query(
|
||||
"""
|
||||
select p.city as city,
|
||||
p.state as state
|
||||
from IndiaPincodeCityState p
|
||||
where trim(p.city) <> ''
|
||||
and trim(p.state) <> ''
|
||||
and lower(p.city) like lower(concat(:prefix, '%'))
|
||||
group by p.city, p.state
|
||||
order by p.city asc, p.state asc
|
||||
"""
|
||||
)
|
||||
fun searchCityStateByPrefix(
|
||||
@Param("prefix") prefix: String,
|
||||
pageable: Pageable
|
||||
): List<CityStateRow>
|
||||
}
|
||||
|
||||
interface PincodeCityStateCandidate {
|
||||
@@ -32,3 +49,8 @@ interface PincodeCityStateCandidate {
|
||||
val state: String
|
||||
val hitCount: Long
|
||||
}
|
||||
|
||||
interface CityStateRow {
|
||||
val city: String
|
||||
val state: String
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user