#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Скрипт для миграции данных из SQLite в PostgreSQL. 1. Считывает данные из sqlite:////home/matrixhasyou/swarm-services/domovoy-bot/database/domovoy.db 2. Записывает данные в postgresql://gemini_admin:secure_swarm_pass_2026@192.168.10.105:5433/domovoy_db """ import sys from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent sys.path.insert(0, str(BASE_DIR)) from sqlalchemy import create_engine, MetaData, Table from sqlalchemy.orm import sessionmaker SQLITE_URL = f"sqlite:///{BASE_DIR / 'database' / 'domovoy.db'}" POSTGRES_URL = "postgresql://gemini_admin:secure_swarm_pass_2026@192.168.10.105:5433/domovoy_db" def migrate(): print(f"🔄 Подключение к SQLite: {SQLITE_URL}") sqlite_engine = create_engine(SQLITE_URL) sqlite_meta = MetaData() sqlite_meta.reflect(bind=sqlite_engine) print(f"🔄 Подключение к PostgreSQL: {POSTGRES_URL}") pg_engine = create_engine(POSTGRES_URL) pg_meta = MetaData() pg_meta.reflect(bind=pg_engine) SqliteSession = sessionmaker(bind=sqlite_engine) PgSession = sessionmaker(bind=pg_engine) sqlite_session = SqliteSession() pg_session = PgSession() # Список таблиц в порядке зависимостей (сначала родители, потом потомки) # Порядок важен из-за внешних ключей (Foreign Keys) tables_order = [ 'users', 'initiative_group', 'messages', 'services', 'verification_requests', 'spy_logs', 'announcements', 'polls', 'spam_warnings', 'message_rates', 'schedules', 'ads', 'payment_reminders', 'profile_history', 'achievements', 'thanks', 'events', 'event_participants', 'scheduled_posts', 'broadcasts', 'broadcast_reads', 'digests', 'email_audit', 'email_export_logs', 'artifacts' ] # Сначала очистим таблицы в PostgreSQL в обратном порядке (чтобы не нарушать Foreign Keys) print("🧹 Очистка целевых таблиц в PostgreSQL...") for table_name in reversed(tables_order): if table_name in pg_meta.tables: pg_table = pg_meta.tables[table_name] try: pg_session.execute(pg_table.delete()) print(f" Удалены старые записи из {table_name}") except Exception as e: print(f" ⚠️ Ошибка очистки {table_name}: {e}") pg_session.commit() print("\n🚀 Начало переноса данных...") for table_name in tables_order: if table_name not in sqlite_meta.tables: print(f" ⚠️ Таблица {table_name} отсутствует в SQLite, пропускаем.") continue sqlite_table = sqlite_meta.tables[table_name] pg_table = pg_meta.tables[table_name] # Получаем данные из SQLite rows = sqlite_session.execute(sqlite_table.select()).all() if not rows: print(f" ℹ️ Таблица {table_name} пуста в SQLite") continue print(f" 📦 Перенос {len(rows)} строк для таблицы {table_name}...") # Подготавливаем данные для вставки data_to_insert = [] for r in rows: # Превращаем строку Row в словарь с именами колонок data_to_insert.append(dict(r._mapping)) # Вставляем данные в PostgreSQL try: pg_session.execute(pg_table.insert(), data_to_insert) pg_session.commit() print(f" ✅ Перенесено {table_name}") except Exception as e: pg_session.rollback() print(f" ❌ Ошибка переноса таблицы {table_name}: {e}") sys.exit(1) sqlite_session.close() pg_session.close() print("\n🎉 Миграция успешно завершена!") if __name__ == "__main__": migrate()