"""Copy data from a legacy combined data.db into the split databases. The legacy database contained users, sensors and readouts in one file. Run the new migrations first, then import the old rows: alembic upgrade head alembic -c alembic_users.ini upgrade head python migrate_legacy_db.py The legacy file is only read; nothing is deleted from it. """ import argparse from pathlib import Path from sqlalchemy import MetaData, Table, create_engine, inspect, select from sqlalchemy.dialects.sqlite import insert from models import Sensor, SensorReadout from user_models import User def _sqlite_engine(path: Path): if not path.exists(): raise SystemExit(f"database not found: {path}") return create_engine(f"sqlite:///{path}") def _copy_table(source, destination, table) -> int: if table.name not in inspect(source).get_table_names(): return 0 source_table = Table(table.name, MetaData(), autoload_with=source) with source.connect() as conn: rows = [dict(row._mapping) for row in conn.execute(select(source_table))] if not rows: return 0 with destination.begin() as conn: conn.execute(insert(table).on_conflict_do_nothing(), rows) return len(rows) def main() -> None: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--legacy", default="data.db", type=Path) parser.add_argument("--sensors", default="sensors.db", type=Path) parser.add_argument("--main-app", default="main_app.db", type=Path) args = parser.parse_args() legacy = _sqlite_engine(args.legacy) sensors = _sqlite_engine(args.sensors) main_app = _sqlite_engine(args.main_app) if not inspect(sensors).has_table(Sensor.__tablename__): raise SystemExit(f"{args.sensors} has no schema; run alembic upgrade head first") if not inspect(main_app).has_table(User.__tablename__): raise SystemExit( f"{args.main_app} has no schema; run alembic -c alembic_users.ini upgrade head first" ) sensor_count = _copy_table(legacy, sensors, Sensor.__table__) readout_count = _copy_table(legacy, sensors, SensorReadout.__table__) user_count = _copy_table(legacy, main_app, User.__table__) print( f"Copied {sensor_count} sensors, {readout_count} readouts and " f"{user_count} users. The legacy database was not modified." ) if __name__ == "__main__": main()