#!/usr/bin/env python3 import argparse import sys from pathlib import Path import mysql.connector def parse_env_file(env_path: Path): data = {} for raw in env_path.read_text(encoding="utf-8").splitlines(): line = raw.strip() if not line or line.startswith("#") or "=" not in line: continue k, v = line.split("=", 1) data[k.strip()] = v.strip() return data def split_sql_statements(sql_text: str): statements = [] buf = [] in_single = False in_double = False in_line_comment = False in_block_comment = False i = 0 while i < len(sql_text): ch = sql_text[i] nxt = sql_text[i + 1] if i + 1 < len(sql_text) else "" if in_line_comment: if ch == "\n": in_line_comment = False buf.append(ch) i += 1 continue if in_block_comment: if ch == "*" and nxt == "/": in_block_comment = False i += 2 else: i += 1 continue if not in_single and not in_double: if ch == "-" and nxt == "-": in_line_comment = True i += 2 continue if ch == "#": in_line_comment = True i += 1 continue if ch == "/" and nxt == "*": in_block_comment = True i += 2 continue if ch == "'" and not in_double: in_single = not in_single buf.append(ch) i += 1 continue if ch == '"' and not in_single: in_double = not in_double buf.append(ch) i += 1 continue if ch == ";" and not in_single and not in_double: stmt = "".join(buf).strip() if stmt: statements.append(stmt) buf = [] i += 1 continue buf.append(ch) i += 1 tail = "".join(buf).strip() if tail: statements.append(tail) return statements def main(): parser = argparse.ArgumentParser(description="Run SQL migration using mysql-connector") parser.add_argument("--env", default="backend/.env", help="Path to .env file") parser.add_argument("--sql", required=True, help="Path to SQL file") args = parser.parse_args() env = parse_env_file(Path(args.env)) sql_path = Path(args.sql) if not sql_path.exists(): print(f"[ERROR] SQL file not found: {sql_path}") return 1 sql_text = sql_path.read_text(encoding="utf-8") statements = split_sql_statements(sql_text) if not statements: print("[ERROR] No SQL statements found") return 1 conn = mysql.connector.connect( host=env.get("DB_HOST", "127.0.0.1"), port=int(env.get("DB_PORT", "3306")), user=env.get("DB_USER", "root"), password=env.get("DB_PASSWORD", ""), database=env.get("DB_NAME", ""), ) try: cur = conn.cursor(dictionary=True) print(f"[INFO] Running {len(statements)} statements from {sql_path}") for idx, stmt in enumerate(statements, start=1): head = " ".join(stmt.split())[:120] cur.execute(stmt) if cur.with_rows: cur.fetchall() print(f"[OK] {idx:03d}: {head}") conn.commit() print("[INFO] Migration committed successfully") except Exception as e: conn.rollback() print(f"[FAIL] {e}") return 2 finally: conn.close() return 0 if __name__ == "__main__": sys.exit(main())