All checks were successful
Deploy / changes (push) Successful in 8s
Deploy / build-frontend (push) Has been skipped
Deploy / deploy-caddy (push) Has been skipped
Deploy / build-backend (push) Successful in 2m15s
Deploy / build-worker (push) Successful in 3m14s
Deploy / deploy (push) Successful in 1m28s
Deploy / deploy-status (push) Successful in 1s
Deploy / perimeter-smoke (push) Successful in 10s
73 lines
3.1 KiB
Python
73 lines
3.1 KiB
Python
"""Lookup ЗУ под изъятие/резервирование из ``land_reservation`` (#1091, #1062, #1067).
|
||
|
||
Читает land_reservation (м.136, наполняется reservation_ingest task) и возвращает
|
||
актуальные постановления по кад-номеру. Геометрия не хранится — join к cad_parcels.geom
|
||
делается на уровне analyze (follow-up после merge #1115).
|
||
|
||
Graceful: нет cad_num / таблица ещё не задеплоена (OperationalError/ProgrammingError) → [].
|
||
Зеркалит стиль ird_overlay_lookup.py.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import logging
|
||
|
||
from sqlalchemy import text
|
||
from sqlalchemy.exc import OperationalError, ProgrammingError
|
||
from sqlalchemy.orm import Session
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
_LOOKUP_SQL = text(
|
||
"""
|
||
SELECT reservation_kind, basis_act, act_number, act_date, purpose, doc_url
|
||
FROM land_reservation
|
||
WHERE cad_num = CAST(:cad_num AS text)
|
||
AND is_active
|
||
ORDER BY act_date DESC NULLS LAST, id DESC
|
||
"""
|
||
)
|
||
|
||
|
||
def parcel_reservations(db: Session, cad_num: str | None) -> list[dict[str, object]]:
|
||
"""Возвращает актуальные постановления об изъятии/резервировании по кад-номеру.
|
||
|
||
Args:
|
||
db: сессия SQLAlchemy.
|
||
cad_num: кадастровый номер ЗУ (например, «66:41:0101001:123»).
|
||
None → пустой список.
|
||
|
||
Returns:
|
||
Список словарей: [{reservation_kind, basis_act, act_number, act_date,
|
||
purpose, doc_url}]. Пустой список если cad_num=None / нет записей /
|
||
таблица не задеплоена.
|
||
"""
|
||
if not cad_num:
|
||
return []
|
||
try:
|
||
# #2464: SAVEPOINT перед проглатыванием ошибки. Сессия ОБЩАЯ с analyze_parcel
|
||
# (build_ird_analyze_block зовёт шесть таких lookup'ов подряд в одном словаре),
|
||
# и на Postgres упавший запрос оставляет транзакцию в aborted-состоянии —
|
||
# падают все следующие, включая запись прогона. Образец рядом:
|
||
# ppt_tep_lookup.py делает ровно так же.
|
||
with db.begin_nested():
|
||
rows = db.execute(_LOOKUP_SQL, {"cad_num": cad_num}).mappings().all()
|
||
except (OperationalError, ProgrammingError) as exc:
|
||
# Таблица ещё не задеплоена / БД-ошибка — graceful degrade.
|
||
logger.warning("parcel_reservations: land_reservation недоступна, skip: %s", exc)
|
||
return []
|
||
|
||
return [
|
||
{
|
||
"reservation_kind": r["reservation_kind"],
|
||
"basis_act": r["basis_act"],
|
||
"act_number": r["act_number"],
|
||
"act_date": r["act_date"],
|
||
"purpose": r["purpose"],
|
||
"doc_url": r["doc_url"],
|
||
}
|
||
for r in rows
|
||
]
|
||
|
||
|
||
__all__ = ["parcel_reservations"]
|