Files
aufmass-web/_aufmass_web/scripts/migrate_sqlite_to_pg.py
T

110 lines
3.4 KiB
Python

import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
from app import create_app
from sqlalchemy import text
import sqlite3
SQLITE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'aufmass.db')
# Tables in FK-safe order (parents first)
TABLE_ORDER = [
'companies',
'users',
'licenses',
'contracts',
'modules',
'aufmass_typen',
'projekte',
'custom_modules',
'company_modules',
'license_modules',
'aufmass',
'lv_positionen',
'positionen',
'project_access',
'custom_module_assignments',
'user_module_permissions',
'view_profiles',
]
def main():
print("=" * 60)
print("SQLite -> PostgreSQL Migration v2")
print("=" * 60)
if not os.path.exists(SQLITE_PATH):
print(f"SQLite DB nicht gefunden: {SQLITE_PATH}")
return
# Read all SQLite data
print("\n1. Lese SQLite-Daten...")
conn = sqlite3.connect(SQLITE_PATH)
conn.row_factory = sqlite3.Row
c = conn.cursor()
sqlite_data = {}
for table_name in TABLE_ORDER:
c.execute(f'SELECT * FROM "{table_name}"')
rows = [dict(r) for r in c.fetchall()]
sqlite_data[table_name] = rows
print(f" {table_name}: {len(rows)} Zeilen")
conn.close()
# Create Flask app -> creates PG tables + seed defaults
print("\n2. Starte Flask-App mit PostgreSQL...")
app = create_app()
with app.app_context():
from app import db
# Delete all existing data in reverse FK order
print(" Entferne vorhandene Daten...")
with db.engine.connect() as c:
for table_name in reversed(TABLE_ORDER):
c.execute(text(f'DELETE FROM "{table_name}"'))
c.commit()
# Import in FK-safe order
print("\n3. Importiere Daten in FK-Reihenfolge...")
meta = __import__('sqlalchemy', fromlist=['MetaData']).MetaData()
meta.reflect(bind=db.engine)
total_ok = 0
total_fail = 0
for table_name in TABLE_ORDER:
rows = sqlite_data.get(table_name, [])
if not rows:
print(f" -- {table_name}: keine Daten")
continue
table = __import__('sqlalchemy', fromlist=['Table']).Table(table_name, meta, autoload_with=db.engine)
pg_cols = {c.name for c in table.columns}
ok = 0
fail = 0
with db.engine.connect() as pg_conn:
for row in rows:
filtered = {k: v for k, v in row.items() if k in pg_cols}
try:
pg_conn.execute(table.insert().values(**filtered))
ok += 1
except Exception as e:
fail += 1
if fail <= 2:
print(f" Fehler {table_name} ID={row.get('id','?')}: {e}")
pg_conn.commit()
total_ok += ok
total_fail += fail
status = "+" if ok else " "
print(f" {status} {table_name}: {ok}/{len(rows)} OK" + (f" ({fail} Fehler)" if fail else ""))
print(f"\nErgebnis: {total_ok} Zeilen importiert" + (f", {total_fail} Fehler" if total_fail else ""))
print("\nFertig! Starte Flask-App neu -> _seed_defaults() ergaenzt Seed-Daten via Upsert.")
print("PostgreSQL ist bereit fuer AufmassWeb.")
if __name__ == '__main__':
main()