diff --git a/backend/app/services/site_finder/krt_lookup.py b/backend/app/services/site_finder/krt_lookup.py index 5d37c9b4..054af74b 100644 --- a/backend/app/services/site_finder/krt_lookup.py +++ b/backend/app/services/site_finder/krt_lookup.py @@ -64,6 +64,20 @@ _PLANNING_KRT_SQL = text( # Вторичный запрос: planning_projects без матча с ekb_krt_sites — geom-only без реквизитов. # Запускается только если первый не дал результатов, чтобы не путать пользователя # двумя overlapping-источниками. +# +# Regex-топонимы для geom-only КРТ-fallback — собран как ОДИН непрерывный паттерн. +# Раньше literal был разорван переносом строки внутри ОДНОЙ пары '...' внутри SQL, +# и ветки 'Донбасской\n ' / 'Лумумбы\n ' содержали NL+8 пробелов отступа, +# никогда не матчили однострочные full_name (PG `~` — POSIX ARE без (?x)) — #1230. +# Python склеивает соседние строковые литералы на этапе парсинга, поэтому regex попадает +# в SQL одной строкой. Не SQL-injection: статическая константа, без user input. +# При добавлении новых топонимов держим строки <100 chars и НЕ ломаем regex переносом. +_KRT_TOPONYM_REGEX = ( + "[кК][рР][тТ]|комплексн.*развити|Краснофлотцев|Донбасской|Шефской|Азина" + "|Черкасской|Кварцевой|Летчиков|Вилонова|Лумумбы|Студенческой|Васильева" + "|Гурзуфск|Бакинских|Шадринский|Бабушкина" +) + _PLANNING_NO_MATCH_SQL = text( """ SELECT @@ -76,9 +90,9 @@ _PLANNING_NO_MATCH_SQL = text( pp.geom, ST_GeomFromText(CAST(:parcel_wkt AS text), 4326) ) - AND pp.full_name ~ '[кК][рР][тТ]|комплексн.*развити|Краснофлотцев|Донбасской - |Шефской|Азина|Черкасской|Кварцевой|Летчиков|Вилонова|Лумумбы - |Студенческой|Васильева|Гурзуфск|Бакинских|Шадринский|Бабушкина' + AND pp.full_name ~ '""" + + _KRT_TOPONYM_REGEX + + """' ORDER BY pp.dmd_actual_year DESC """ )