Verified catalogue of mobiles and laptops sold in India, collected from real retail listings (FastAPI backend, React frontend, Postgres/pgvector). - REST API under /api/elec (read-only catalogue; admin endpoints need login) - MCP server (FastMCP) at /mcp/ with list_categories, search_products, get_product and price_history tools - Real ratings and reviews read from product pages and search results - Production Dockerfile (requirements-api.txt, no PyTorch) and .env.production.example; remote database only via an explicit ELEC_ALLOW_REMOTE_DB host/name allowlist - docs/API.md: endpoint and MCP reference with live examples Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
69 lines
1.7 KiB
Python
69 lines
1.7 KiB
Python
"""Connections to the local electronics database.
|
|
|
|
settings.py has already refused to load unless DB_HOST is local and DB_NAME is
|
|
electronics_catalog, so nothing here can reach another database.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from contextlib import contextmanager
|
|
from typing import Iterator
|
|
|
|
import psycopg
|
|
from psycopg.rows import dict_row
|
|
|
|
from app.infrastructure.settings import (
|
|
DB_CONNECT_TIMEOUT_SECONDS,
|
|
DB_HOST,
|
|
DB_NAME,
|
|
DB_PASSWORD,
|
|
DB_PORT,
|
|
DB_USER,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def connect(*, autocommit: bool = False) -> psycopg.Connection:
|
|
conn = psycopg.connect(
|
|
host=DB_HOST,
|
|
port=DB_PORT,
|
|
dbname=DB_NAME,
|
|
user=DB_USER,
|
|
password=DB_PASSWORD,
|
|
connect_timeout=DB_CONNECT_TIMEOUT_SECONDS,
|
|
autocommit=autocommit,
|
|
row_factory=dict_row,
|
|
)
|
|
try:
|
|
from pgvector.psycopg import register_vector
|
|
|
|
register_vector(conn)
|
|
except Exception: # noqa: BLE001 - the extension is created by migration 0001
|
|
pass
|
|
return conn
|
|
|
|
|
|
@contextmanager
|
|
def transaction() -> Iterator[psycopg.Connection]:
|
|
"""A connection whose work is committed on success, rolled back on error."""
|
|
conn = connect()
|
|
try:
|
|
yield conn
|
|
conn.commit()
|
|
except Exception:
|
|
conn.rollback()
|
|
raise
|
|
finally:
|
|
conn.close()
|
|
|
|
|
|
def check_connection() -> bool:
|
|
try:
|
|
with connect(autocommit=True) as conn:
|
|
conn.execute("SELECT 1")
|
|
return True
|
|
except Exception as exc: # noqa: BLE001 - a health probe reports, never raises
|
|
logger.debug("Database unreachable: %s", exc)
|
|
return False
|