fix(geocoding): fix query param string parsing, location field mismatch, and distance_km normalization
- controller: @Query() params arrive as strings in NestJS - now explicitly
parseFloat() all numeric params (lat, lng, radius) before passing to service.
Also validates against NaN before hitting PostGIS.
- controller: reverse geocode now validates and throws 400 on invalid lat/lng.
- service: searchPlaces now normalizes all results to include:
- location: { lat, lng } nested object (frontend was crashing on place.location.lat)
- distance_km: pre-computed string field (frontend was reading undefined distance_km)
- latitude/longitude as actual floats (not decimal strings from DB)
- frontend (App.tsx): fixed map.flyTo() to read place.latitude/place.longitude
instead of the non-existent place.location.lat/lng.
- frontend (App.tsx): fixed search result click handler same way.
- frontend (App.tsx): fixed distance display to compute from res.distance (meters).
- entity: added missing source column to BasePlace entity.
This commit is contained in:
@@ -18,20 +18,39 @@ export class GeocodingController {
|
||||
@ApiQuery({ name: 'country', required: false, enum: ['jordan', 'syria', 'egypt'] })
|
||||
async search(
|
||||
@Query('q') query: string,
|
||||
@Query('lat') lat?: number,
|
||||
@Query('lng') lng?: number,
|
||||
@Query('radius') radius?: number,
|
||||
@Query('lat') lat?: string,
|
||||
@Query('lng') lng?: string,
|
||||
@Query('radius') radius?: string,
|
||||
@Query('country') country?: string,
|
||||
) {
|
||||
return this.geocodingService.searchPlaces(query, lat, lng, radius, country);
|
||||
// NestJS @Query() always receives strings — must parse explicitly for numeric types
|
||||
const parsedLat = lat !== undefined ? parseFloat(lat) : undefined;
|
||||
const parsedLng = lng !== undefined ? parseFloat(lng) : undefined;
|
||||
const parsedRadius = radius !== undefined ? parseFloat(radius) : 20000;
|
||||
|
||||
// Guard against malformed float values (NaN breaks PostGIS)
|
||||
const safeLat = parsedLat !== undefined && !isNaN(parsedLat) ? parsedLat : undefined;
|
||||
const safeLng = parsedLng !== undefined && !isNaN(parsedLng) ? parsedLng : undefined;
|
||||
|
||||
return this.geocodingService.searchPlaces(query, safeLat, safeLng, parsedRadius, country);
|
||||
}
|
||||
|
||||
@Get('reverse')
|
||||
@ApiOperation({ summary: 'Reverse Geocoding (Lat/Lng to Address)' })
|
||||
@ApiQuery({ name: 'lat', required: true })
|
||||
@ApiQuery({ name: 'lng', required: true })
|
||||
async reverse(@Query('lat') lat: number, @Query('lng') lng: number) {
|
||||
return this.geocodingService.reverseGeocode(lat, lng);
|
||||
async reverse(
|
||||
@Query('lat') lat: string,
|
||||
@Query('lng') lng: string,
|
||||
) {
|
||||
const parsedLat = parseFloat(lat);
|
||||
const parsedLng = parseFloat(lng);
|
||||
|
||||
if (isNaN(parsedLat) || isNaN(parsedLng)) {
|
||||
throw new HttpException('Invalid lat/lng values', HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
return this.geocodingService.reverseGeocode(parsedLat, parsedLng);
|
||||
}
|
||||
|
||||
@Post('places')
|
||||
@@ -48,7 +67,7 @@ export class GeocodingController {
|
||||
async deletePlace(
|
||||
@Query('country') country: string,
|
||||
@Query('name') name?: string,
|
||||
@Query('id') id?: number,
|
||||
@Query('id') id?: string,
|
||||
) {
|
||||
if (id) {
|
||||
return this.geocodingService.deletePlaceById(Number(id), country);
|
||||
@@ -73,8 +92,8 @@ export class GeocodingController {
|
||||
|
||||
@Get('places')
|
||||
@ApiOperation({ summary: 'Get recent user submitted places' })
|
||||
async getPlaces(@Query('limit') limit?: number) {
|
||||
return this.geocodingService.getRecentPlaces(limit);
|
||||
async getPlaces(@Query('limit') limit?: string) {
|
||||
return this.geocodingService.getRecentPlaces(limit ? parseInt(limit, 10) : 50);
|
||||
}
|
||||
|
||||
@Get('geojson')
|
||||
|
||||
Reference in New Issue
Block a user