From 4a2a8042963587c82bfb8a78fe9c5a7aaa148f57 Mon Sep 17 00:00:00 2001 From: lekss361 Date: Sun, 24 May 2026 15:28:36 +0300 Subject: [PATCH] fix(tradein-estimator): restore CAST in IS NOT NULL predicates (revert audit #9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #509 removed CAST(:target_year AS integer) and CAST(:target_house_type AS text) from the IS NOT NULL predicates in _fetch_analogs, citing audit finding #9 (perf). This broke production: psycopg3 prepared statement could not determine $4 type when target_house_type=None, raising AmbiguousParameter at plan time. The CAST in the THEN branch is not enough — PG planner needs the type to evaluate IS NOT NULL itself. The inline comment at lines 814-816 explicitly documented this requirement; PR #509 misread the audit finding. Per-row CAST cost on ≤300 rows is negligible vs production breakage. Restoring CAST forms; THEN-branch CASTs untouched (they were never removed). Verified prod stack trace 2026-05-24 ~12:25 (target_year=1978, target_house_type=None). --- tradein-mvp/backend/app/services/estimator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tradein-mvp/backend/app/services/estimator.py b/tradein-mvp/backend/app/services/estimator.py index 4e2fc03e..580593d0 100644 --- a/tradein-mvp/backend/app/services/estimator.py +++ b/tradein-mvp/backend/app/services/estimator.py @@ -881,13 +881,13 @@ def _fetch_analogs( -- без типа → PostgreSQL "could not determine data type of parameter" -- (AmbiguousParameter). Явный тип снимает неоднозначность. + CASE - WHEN :target_year IS NOT NULL + WHEN CAST(:target_year AS integer) IS NOT NULL AND year_built IS NOT NULL THEN abs(year_built - CAST(:target_year AS integer)) / 12.0 ELSE 0 END + CASE - WHEN :target_house_type IS NOT NULL + WHEN CAST(:target_house_type AS text) IS NOT NULL AND house_type IS NOT NULL AND house_type <> CAST(:target_house_type AS text) THEN 1.5 @@ -900,13 +900,13 @@ def _fetch_analogs( ST_Distance(geom::geography, ST_MakePoint(:lon, :lat)::geography) / 1000.0 + CASE - WHEN :target_year IS NOT NULL + WHEN CAST(:target_year AS integer) IS NOT NULL AND year_built IS NOT NULL THEN abs(year_built - CAST(:target_year AS integer)) / 12.0 ELSE 0 END + CASE - WHEN :target_house_type IS NOT NULL + WHEN CAST(:target_house_type AS text) IS NOT NULL AND house_type IS NOT NULL AND house_type <> CAST(:target_house_type AS text) THEN 1.5 -- 2.45.3