#!/usr/bin/env python3 """Migration: Rename DataSource.autoSync -> ragIndexEnabled, lastSynced -> lastIndexed. This is a one-off migration for the RAG consent & control unification. Safe to run multiple times (checks column existence before acting). Usage: python script_db_migrate_datasource_rag.py [--dry-run] """ import os import sys import argparse import logging from pathlib import Path scriptPath = Path(__file__).resolve() gatewayPath = scriptPath.parent.parent sys.path.insert(0, str(gatewayPath)) os.chdir(str(gatewayPath)) logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s", force=True) logger = logging.getLogger(__name__) import psycopg2 from modules.shared.configuration import APP_CONFIG def _getConnection(): return psycopg2.connect( host=APP_CONFIG.get("DB_HOST", "localhost"), port=int(APP_CONFIG.get("DB_PORT", "5432")), database=APP_CONFIG.get("DB_DATABASE", "poweron_app"), user=APP_CONFIG.get("DB_USER"), password=APP_CONFIG.get("DB_PASSWORD_SECRET"), ) def _columnExists(cur, table: str, column: str) -> bool: cur.execute( """SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = %s AND column_name = %s""", (table, column), ) return cur.fetchone() is not None def migrate(dryRun: bool = False): conn = _getConnection() conn.autocommit = False cur = conn.cursor() renames = [ ("DataSource", "autoSync", "ragIndexEnabled"), ("DataSource", "lastSynced", "lastIndexed"), ] executed = [] for table, oldCol, newCol in renames: if _columnExists(cur, table, oldCol) and not _columnExists(cur, table, newCol): sql = f'ALTER TABLE public."{table}" RENAME COLUMN "{oldCol}" TO "{newCol}";' logger.info("EXEC: %s", sql) if not dryRun: cur.execute(sql) executed.append(sql) elif _columnExists(cur, table, newCol): logger.info("SKIP: %s.%s already exists (migration already applied)", table, newCol) elif not _columnExists(cur, table, oldCol): logger.warning("SKIP: %s.%s does not exist (table schema may differ)", table, oldCol) if not dryRun and executed: conn.commit() logger.info("Migration committed (%d statements)", len(executed)) elif dryRun and executed: conn.rollback() logger.info("DRY RUN — would execute %d statements", len(executed)) else: logger.info("Nothing to do — schema already up to date") cur.close() conn.close() if __name__ == "__main__": parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--dry-run", action="store_true", help="Print SQL without executing") args = parser.parse_args() migrate(dryRun=args.dry_run)