fix(tradein): PR #469 BLOCK — h.reviews_count + DSN psycopg strip

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).
This commit is contained in:
lekss361 2026-05-23 16:58:14 +03:00
parent 925d7d15cc
commit 09698c5124
2 changed files with 5 additions and 2 deletions

View file

@ -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")

View file

@ -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,