From 09698c5124c08442b6545bb66c661a0493159750 Mon Sep 17 00:00:00 2001 From: lekss361 Date: Sat, 23 May 2026 16:58:14 +0300 Subject: [PATCH] =?UTF-8?q?fix(tradein):=20PR=20#469=20BLOCK=20=E2=80=94?= =?UTF-8?q?=20h.reviews=5Fcount=20+=20DSN=20psycopg=20strip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit deep-code-reviewer caught 2 critical bugs that would cause silent prod regression: 1. 050_search_optimization.sql: h.ratings_count → h.reviews_count (alias house_ratings_count preserved for API contract) houses.ratings_count does not exist; matview CREATE would abort, and deploy-tradein.yml swallows the error (|| echo) — Celery task would then fail at runtime with "relation listings_search_mv does not exist". 2. refresh_search_matview.py: strip +psycopg dialect prefix from DSN tradein-mvp/docker-compose.prod.yml uses postgresql+psycopg:// (SQLAlchemy dialect form) for DATABASE_URL. libpq accepts only postgresql:// — without the strip, psycopg.connect() raises OperationalError on every Celery beat tick. Refs PR #469 review (deep-code-reviewer, 2026-05-23). --- tradein-mvp/backend/app/tasks/refresh_search_matview.py | 5 ++++- tradein-mvp/backend/data/sql/050_search_optimization.sql | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tradein-mvp/backend/app/tasks/refresh_search_matview.py b/tradein-mvp/backend/app/tasks/refresh_search_matview.py index f177d732..29fc1f8d 100644 --- a/tradein-mvp/backend/app/tasks/refresh_search_matview.py +++ b/tradein-mvp/backend/app/tasks/refresh_search_matview.py @@ -26,7 +26,10 @@ def refresh_search_matview() -> None: Logs duration. Idempotent. Safe to run during read traffic (CONCURRENTLY). """ start = time.monotonic() - dsn = settings.database_url # psycopg v3 accepts postgresql:// DSN + # DATABASE_URL is SQLAlchemy dialect form (postgresql+psycopg://...) in tradein-mvp + # (see tradein-mvp/docker-compose.prod.yml). libpq / psycopg.connect() accepts only + # postgresql:// or postgres:// — strip the +psycopg dialect prefix. + dsn = settings.database_url.replace("postgresql+psycopg://", "postgresql://", 1) with psycopg.connect(dsn, autocommit=True) as conn: with conn.cursor() as cur: cur.execute("REFRESH MATERIALIZED VIEW CONCURRENTLY listings_search_mv") diff --git a/tradein-mvp/backend/data/sql/050_search_optimization.sql b/tradein-mvp/backend/data/sql/050_search_optimization.sql index f7989b32..c15ba413 100644 --- a/tradein-mvp/backend/data/sql/050_search_optimization.sql +++ b/tradein-mvp/backend/data/sql/050_search_optimization.sql @@ -130,7 +130,7 @@ SELECT h.house_class, h.developer_name, h.rating AS house_rating, - h.ratings_count AS house_ratings_count, + h.reviews_count AS house_ratings_count, -- Cross-source aggregates (SELECT count(*) FROM listing_sources ls WHERE ls.listing_id = l.id) AS source_count, (SELECT array_agg(DISTINCT ext_source) FROM listing_sources ls WHERE ls.listing_id = l.id) AS sources,