Coverage for app/alembic/utils.py: 97%
32 statements
« prev ^ index » next coverage.py v7.6.10, created at 2026-06-04 22:29 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2026-06-04 22:29 +0000
1import inspect
2from pathlib import Path
4from sqlalchemy import Engine, text
6from app.core.logger import logger
9def read_sql_file(sql_file: Path) -> tuple[str, ...]:
10 if not sql_file.exists():
11 raise FileNotFoundError(f"{sql_file} is missing.")
13 with open(sql_file, "r") as f:
14 contents = f.read().strip()
16 sql_statements = tuple(
17 statement.strip() for statement in contents.split(";") if statement.strip()
18 )
20 if not sql_statements:
21 raise ValueError(
22 f"The file '{sql_file}' exists but contains no SQL statements."
23 )
25 return sql_statements
28def get_sql_migration_file() -> Path:
29 caller_frame = inspect.stack()[1]
30 caller_function_name = caller_frame.function
31 version_file = Path(caller_frame.filename)
33 if caller_function_name not in ("upgrade", "downgrade"):
34 raise ValueError(
35 f"Function '{caller_function_name}' is not a valid Alembic migration function. "
36 "Expected 'upgrade' or 'downgrade'."
37 )
39 return version_file.parent / f"{version_file.stem}_{caller_function_name}.sql"
42def run_sql_statements(write_engine: Engine, sql_file: Path) -> tuple[str, ...]:
43 executed_statements = []
44 with write_engine.begin() as conn:
45 for sql in read_sql_file(sql_file):
46 try:
47 logger.info(f"Executing SQL: {sql}")
48 conn.execute(text(sql))
49 executed_statements.append(sql)
50 except Exception as e:
51 logger.error(f"Failed to execute SQL: {sql}. Error: {e}")
52 raise e
53 return tuple(executed_statements)