"""Refresh helper for mv_layout_velocity (Issue #113 PR B). Not scheduled automatically in this PR — intended for manual invocation or a Celery beat task in a follow-up issue. Usage example (manual, via psql-connected shell or admin endpoint): from sqlalchemy.orm import Session from app.services.site_finder.layout_velocity_refresh import refresh_layout_velocity count = refresh_layout_velocity(db) # logs: "mv_layout_velocity refreshed: 459 rows" """ from __future__ import annotations import logging from sqlalchemy import text from sqlalchemy.orm import Session logger = logging.getLogger(__name__) def refresh_layout_velocity(db: Session, *, concurrently: bool = True) -> int: """REFRESH MATERIALIZED VIEW mv_layout_velocity. Args: db: SQLAlchemy Session (sync). concurrently: When True, uses REFRESH CONCURRENTLY — non-blocking but requires the unique index mv_layout_velocity_pk to exist (created by 94_mv_layout_velocity.sql). Pass False only for the very first populate or when the MV was just recreated. Returns: Row count in the MV after refresh (for observability / alerting). """ mode = "CONCURRENTLY" if concurrently else "" db.execute(text(f"REFRESH MATERIALIZED VIEW {mode} mv_layout_velocity")) row = db.execute(text("SELECT COUNT(*) FROM mv_layout_velocity")).first() count = int(row[0]) if row else 0 logger.info("mv_layout_velocity refreshed: %d rows", count) return count