Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| SQLite to PostgreSQL Migration Script | |
| Migrates data from SQLite database to PostgreSQL | |
| """ | |
| import sys | |
| import os | |
| import sqlite3 | |
| import psycopg2 | |
| from psycopg2 import sql | |
| from datetime import datetime | |
| from pathlib import Path | |
| # Add parent directory to path | |
| sys.path.insert(0, str(Path(__file__).parent.parent)) | |
| def connect_sqlite(db_path): | |
| """Connect to SQLite database""" | |
| try: | |
| conn = sqlite3.connect(db_path) | |
| conn.row_factory = sqlite3.Row | |
| print(f"β Connected to SQLite: {db_path}") | |
| return conn | |
| except Exception as e: | |
| print(f"β SQLite connection failed: {e}") | |
| sys.exit(1) | |
| def connect_postgres(config): | |
| """Connect to PostgreSQL database""" | |
| try: | |
| conn = psycopg2.connect( | |
| host=config.get('host', 'localhost'), | |
| port=config.get('port', 5432), | |
| database=config.get('database'), | |
| user=config.get('user'), | |
| password=config.get('password') | |
| ) | |
| print(f"β Connected to PostgreSQL: {config['database']}") | |
| return conn | |
| except Exception as e: | |
| print(f"β PostgreSQL connection failed: {e}") | |
| sys.exit(1) | |
| def get_tables(sqlite_conn): | |
| """Get all table names from SQLite""" | |
| cursor = sqlite_conn.cursor() | |
| cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'") | |
| tables = [row[0] for row in cursor.fetchall()] | |
| cursor.close() | |
| return tables | |
| def migrate_table(table_name, sqlite_conn, pg_conn): | |
| """Migrate a single table from SQLite to PostgreSQL""" | |
| print(f"\nβ Migrating table: {table_name}") | |
| # Get data from SQLite | |
| sqlite_cursor = sqlite_conn.cursor() | |
| sqlite_cursor.execute(f"SELECT * FROM {table_name}") | |
| rows = sqlite_cursor.fetchall() | |
| if not rows: | |
| print(f" β Table {table_name} is empty, skipping...") | |
| return 0 | |
| # Get column names | |
| columns = [description[0] for description in sqlite_cursor.description] | |
| # Prepare PostgreSQL insert | |
| pg_cursor = pg_conn.cursor() | |
| # Build insert query | |
| placeholders = ', '.join(['%s'] * len(columns)) | |
| columns_str = ', '.join([f'"{col}"' for col in columns]) | |
| insert_query = f'INSERT INTO {table_name} ({columns_str}) VALUES ({placeholders}) ON CONFLICT DO NOTHING' | |
| # Insert data | |
| migrated_count = 0 | |
| failed_count = 0 | |
| for row in rows: | |
| try: | |
| pg_cursor.execute(insert_query, tuple(row)) | |
| migrated_count += 1 | |
| except Exception as e: | |
| failed_count += 1 | |
| print(f" β Failed to insert row: {e}") | |
| pg_conn.rollback() | |
| continue | |
| pg_conn.commit() | |
| pg_cursor.close() | |
| sqlite_cursor.close() | |
| print(f" β Migrated {migrated_count} rows") | |
| if failed_count > 0: | |
| print(f" β Failed to migrate {failed_count} rows") | |
| return migrated_count | |
| def update_sequences(pg_conn, tables): | |
| """Update PostgreSQL sequences after migration""" | |
| print("\nβ Updating sequences...") | |
| pg_cursor = pg_conn.cursor() | |
| for table in tables: | |
| try: | |
| # Find primary key column (assuming it's named 'id') | |
| pg_cursor.execute(f""" | |
| SELECT MAX(id) FROM {table} | |
| """) | |
| max_id = pg_cursor.fetchone()[0] | |
| if max_id: | |
| # Update sequence | |
| pg_cursor.execute(f""" | |
| SELECT setval('{table}_id_seq', {max_id}, true) | |
| """) | |
| print(f" β Updated sequence for {table} to {max_id}") | |
| except Exception as e: | |
| print(f" β No sequence for {table} or error: {e}") | |
| pg_conn.rollback() | |
| pg_conn.commit() | |
| pg_cursor.close() | |
| def verify_migration(sqlite_conn, pg_conn, tables): | |
| """Verify migration by comparing row counts""" | |
| print("\nβ Verifying migration...") | |
| all_match = True | |
| for table in tables: | |
| sqlite_cursor = sqlite_conn.cursor() | |
| pg_cursor = pg_conn.cursor() | |
| sqlite_cursor.execute(f"SELECT COUNT(*) FROM {table}") | |
| sqlite_count = sqlite_cursor.fetchone()[0] | |
| pg_cursor.execute(f"SELECT COUNT(*) FROM {table}") | |
| pg_count = pg_cursor.fetchone()[0] | |
| if sqlite_count == pg_count: | |
| print(f" β {table}: {sqlite_count} rows (match)") | |
| else: | |
| print(f" β {table}: SQLite={sqlite_count}, PostgreSQL={pg_count} (mismatch)") | |
| all_match = False | |
| sqlite_cursor.close() | |
| pg_cursor.close() | |
| return all_match | |
| def main(): | |
| """Main migration function""" | |
| print("=" * 60) | |
| print("SQLite to PostgreSQL Migration Tool") | |
| print("AI Fitness Coach Platform") | |
| print("=" * 60) | |
| # Configuration | |
| SQLITE_DB = os.getenv('SQLITE_DB', 'backend/database/fitness_coach.db') | |
| PG_CONFIG = { | |
| 'host': os.getenv('DB_HOST', 'localhost'), | |
| 'port': int(os.getenv('DB_PORT', 5432)), | |
| 'database': os.getenv('DB_NAME', 'fitness_coach'), | |
| 'user': os.getenv('DB_USER', 'fitness_user'), | |
| 'password': os.getenv('DB_PASSWORD', 'fitness_password') | |
| } | |
| # Check if SQLite database exists | |
| if not os.path.exists(SQLITE_DB): | |
| print(f"β SQLite database not found: {SQLITE_DB}") | |
| sys.exit(1) | |
| # Connect to databases | |
| sqlite_conn = connect_sqlite(SQLITE_DB) | |
| pg_conn = connect_postgres(PG_CONFIG) | |
| try: | |
| # Get tables to migrate | |
| tables = get_tables(sqlite_conn) | |
| print(f"\nFound {len(tables)} tables to migrate:") | |
| for table in tables: | |
| print(f" β’ {table}") | |
| # Confirm migration | |
| response = input("\nProceed with migration? (yes/no): ") | |
| if response.lower() != 'yes': | |
| print("Migration cancelled.") | |
| return | |
| # Migrate each table | |
| print("\nStarting migration...") | |
| total_rows = 0 | |
| for table in tables: | |
| rows = migrate_table(table, sqlite_conn, pg_conn) | |
| total_rows += rows | |
| # Update sequences | |
| update_sequences(pg_conn, tables) | |
| # Verify migration | |
| if verify_migration(sqlite_conn, pg_conn, tables): | |
| print("\n" + "=" * 60) | |
| print(f"β Migration completed successfully!") | |
| print(f"β Total rows migrated: {total_rows}") | |
| print("=" * 60) | |
| else: | |
| print("\n" + "=" * 60) | |
| print("β Migration completed with mismatches!") | |
| print(" Please review the verification results above.") | |
| print("=" * 60) | |
| except Exception as e: | |
| print(f"\nβ Migration failed: {e}") | |
| pg_conn.rollback() | |
| sys.exit(1) | |
| finally: | |
| sqlite_conn.close() | |
| pg_conn.close() | |
| print("\nDatabase connections closed.") | |
| if __name__ == '__main__': | |
| main() | |