fix(parcels): guard NULL geom + None lat/lon в isochrones/poi-score (#1201) #1251
1 changed files with 28 additions and 10 deletions
|
|
@ -2933,18 +2933,25 @@ def get_isochrones(
|
|||
detail=f"times_min значения вне диапазона 1-60: {invalid_times}",
|
||||
)
|
||||
|
||||
# Получить координаты центроида из доступных геометрий участка
|
||||
# Получить координаты центроида из доступных геометрий участка.
|
||||
# `geom IS NOT NULL` во ВСЕХ ветках UNION (#1201): cad_parcels_geom — VIEW
|
||||
# над cad_parcels с nullable geom, 964 prod-строки. Без фильтра NULL-строка
|
||||
# ранней ветки скрывает валидную из поздней + ST_Centroid(NULL) → NULL → 500.
|
||||
# Зеркало паттерна analyze (parcels.py:1418-1438).
|
||||
coord_row = (
|
||||
db.execute(
|
||||
text("""
|
||||
SELECT ST_X(ST_Centroid(g.geom)) AS lon,
|
||||
ST_Y(ST_Centroid(g.geom)) AS lat
|
||||
FROM (
|
||||
SELECT geom FROM cad_quarters_geom WHERE cad_number = :c
|
||||
SELECT geom FROM cad_quarters_geom
|
||||
WHERE cad_number = :c AND geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM cad_buildings WHERE cad_num = :c
|
||||
SELECT geom FROM cad_buildings
|
||||
WHERE cad_num = :c AND geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM cad_parcels_geom WHERE cad_num = :c
|
||||
SELECT geom FROM cad_parcels_geom
|
||||
WHERE cad_num = :c AND geom IS NOT NULL
|
||||
) g
|
||||
LIMIT 1
|
||||
"""),
|
||||
|
|
@ -2954,7 +2961,11 @@ def get_isochrones(
|
|||
.first()
|
||||
)
|
||||
|
||||
if not coord_row:
|
||||
# belt-and-suspenders: row может вернуться с NULL lat/lon только если в БД
|
||||
# есть строка с НЕ-NULL geom но битый ST_Centroid (топологически невалидный
|
||||
# polygon). Граница `not coord_row` truthy-проверка на RowMapping её бы НЕ
|
||||
# поймала (RowMapping с None-полями всё ещё truthy) → float(None) → 500.
|
||||
if not coord_row or coord_row.get("lat") is None or coord_row.get("lon") is None:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Геометрия для {cad_num} не найдена.",
|
||||
|
|
@ -3029,18 +3040,24 @@ async def get_poi_score(
|
|||
POI берутся из osm_poi_ekb в заданном радиусе (default 2000м).
|
||||
Отсортированы по weight DESC — наиболее значимые объекты первыми.
|
||||
"""
|
||||
# Получить координаты центроида участка из геометрических таблиц
|
||||
# Получить координаты центроида участка из геометрических таблиц.
|
||||
# См. парный комментарий в get_isochrones — `geom IS NOT NULL` во ВСЕХ ветках
|
||||
# UNION (#1201): NULL-строка ранней ветки скрывает валидную из поздней +
|
||||
# ST_Centroid(NULL) → NULL → float(None) → 500. Зеркало analyze (parcels.py:1418-1438).
|
||||
coord_row = (
|
||||
db.execute(
|
||||
text("""
|
||||
SELECT ST_X(ST_Centroid(g.geom)) AS lon,
|
||||
ST_Y(ST_Centroid(g.geom)) AS lat
|
||||
FROM (
|
||||
SELECT geom FROM cad_quarters_geom WHERE cad_number = :c
|
||||
SELECT geom FROM cad_quarters_geom
|
||||
WHERE cad_number = :c AND geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM cad_buildings WHERE cad_num = :c
|
||||
SELECT geom FROM cad_buildings
|
||||
WHERE cad_num = :c AND geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT geom FROM cad_parcels_geom WHERE cad_num = :c
|
||||
SELECT geom FROM cad_parcels_geom
|
||||
WHERE cad_num = :c AND geom IS NOT NULL
|
||||
) g
|
||||
LIMIT 1
|
||||
"""),
|
||||
|
|
@ -3050,7 +3067,8 @@ async def get_poi_score(
|
|||
.first()
|
||||
)
|
||||
|
||||
if not coord_row:
|
||||
# belt-and-suspenders: см. get_isochrones — RowMapping с None-полями truthy.
|
||||
if not coord_row or coord_row.get("lat") is None or coord_row.get("lon") is None:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Геометрия для {cad_num} не найдена.",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue