Files
qaffee/db/migrate_to_sqlite.py

105 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Migrate MariaDB export to SQLite for qaffee.
Usage:
python3 db/migrate_to_sqlite.py
Creates data/qaffee.db ready for use with the Quarkus backend.
Flyway will baseline at V4 on first startup (no re-migration needed).
"""
import re
import sqlite3
import os
import sys
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
REPO_ROOT = os.path.join(SCRIPT_DIR, '..')
MIGRATION_DIR = os.path.join(REPO_ROOT, 'backend', 'src', 'main', 'resources', 'db', 'migration')
EXPORT_FILE = os.path.join(SCRIPT_DIR, 'mariadb_export.sql')
OUTPUT_FILE = os.path.join(REPO_ROOT, 'data', 'qaffee.db')
# V2 (seed data) is intentionally skipped it inserts dev/test rows that
# conflict with production IDs in the export.
MIGRATIONS = [
'V1__initial_schema.sql',
'V3__company_logo.sql',
'V4__tally_price_at_booking.sql',
]
# Tables to import in FK-safe order (parents before children)
DATA_TABLES = ['company', 'employee', 'product', 'access_link', 'tally_entry']
def apply_migrations(conn: sqlite3.Connection) -> None:
for filename in MIGRATIONS:
path = os.path.join(MIGRATION_DIR, filename)
with open(path, 'r', encoding='utf-8') as f:
sql = f.read()
conn.executescript(sql)
print(f' schema {filename}')
def mariadb_to_sqlite_sql(sql: str) -> str:
# Remove MariaDB sandbox-mode comment at the top
sql = re.sub(r'/\*M!.*?\*/', '', sql, flags=re.DOTALL)
# Strip backtick identifier quotes
sql = sql.replace('`', '')
# Convert 0xABCD hex literals to SQLite X'ABCD' blob literals
sql = re.sub(r'\b0x([0-9A-Fa-f]+)', r"X'\1'", sql)
return sql
def extract_insert(sql: str, table: str) -> str | None:
"""Return the full INSERT INTO <table> VALUES ...; statement, or None."""
pattern = rf'(INSERT INTO {re.escape(table)} VALUES\s*.*?;)'
match = re.search(pattern, sql, re.DOTALL)
return match.group(1) if match else None
def main() -> None:
os.makedirs(os.path.dirname(OUTPUT_FILE), exist_ok=True)
if os.path.exists(OUTPUT_FILE):
os.remove(OUTPUT_FILE)
print(f'Removed existing {OUTPUT_FILE}')
print('Reading MariaDB export ...')
with open(EXPORT_FILE, 'r', encoding='utf-8') as f:
raw_sql = f.read()
sqlite_sql = mariadb_to_sqlite_sql(raw_sql)
print('Creating SQLite database ...')
conn = sqlite3.connect(OUTPUT_FILE)
print('Applying schema migrations:')
apply_migrations(conn)
print('Importing data:')
for table in DATA_TABLES:
stmt = extract_insert(sqlite_sql, table)
if stmt is None:
print(f' skip {table} (no data in export)')
continue
conn.executescript(stmt)
# Count rows for feedback
count = conn.execute(f'SELECT COUNT(*) FROM {table}').fetchone()[0]
print(f' import {table} ({count} rows)')
conn.commit()
conn.close()
size_kb = os.path.getsize(OUTPUT_FILE) // 1024
print(f'\nDone {OUTPUT_FILE} ({size_kb} KB)')
print()
print('Next steps:')
print(' 1. docker compose up --build')
print(' Flyway will baseline at V4 and skip all migrations.')
print(' 2. Verify at https://qaffee.cloud.aquantico.de')
if __name__ == '__main__':
main()