#!/usr/bin/env python3 """ Миграция: Удаление колонки vector_hash из таблицы post_from_telegram_suggest. Колонка больше не нужна, т.к. RAG сервис вынесен в отдельный микросервис и хранит векторы самостоятельно. SQLite не поддерживает DROP COLUMN напрямую (до версии 3.35.0), поэтому используем пересоздание таблицы. """ import argparse import asyncio import os import sys from pathlib import Path # Добавляем корень проекта в путь project_root = Path(__file__).resolve().parent.parent sys.path.insert(0, str(project_root)) import aiosqlite # Пытаемся импортировать logger, если не получается - используем стандартный try: from logs.custom_logger import logger except ImportError: import logging logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" ) logger = logging.getLogger(__name__) DEFAULT_DB_PATH = "database/tg-bot-database.db" async def column_exists(conn: aiosqlite.Connection, table: str, column: str) -> bool: """Проверяет существование колонки в таблице.""" cursor = await conn.execute(f"PRAGMA table_info({table})") columns = await cursor.fetchall() return any(col[1] == column for col in columns) async def get_sqlite_version(conn: aiosqlite.Connection) -> tuple: """Возвращает версию SQLite.""" cursor = await conn.execute("SELECT sqlite_version()") version_str = (await cursor.fetchone())[0] return tuple(map(int, version_str.split("."))) async def main(db_path: str) -> None: """ Удаляет колонку vector_hash из таблицы post_from_telegram_suggest. """ db_path = os.path.abspath(db_path) if not os.path.exists(db_path): logger.error(f"База данных не найдена: {db_path}") return async with aiosqlite.connect(db_path) as conn: # Проверяем существует ли колонка if not await column_exists(conn, "post_from_telegram_suggest", "vector_hash"): logger.info("Колонка vector_hash не существует, миграция не требуется") return # Проверяем версию SQLite version = await get_sqlite_version(conn) logger.info(f"Версия SQLite: {'.'.join(map(str, version))}") # SQLite 3.35.0+ поддерживает DROP COLUMN if version >= (3, 35, 0): logger.info("Используем ALTER TABLE DROP COLUMN") await conn.execute( "ALTER TABLE post_from_telegram_suggest DROP COLUMN vector_hash" ) else: # Для старых версий пересоздаём таблицу logger.info("Используем пересоздание таблицы (SQLite < 3.35.0)") # Получаем список колонок без vector_hash cursor = await conn.execute("PRAGMA table_info(post_from_telegram_suggest)") columns = await cursor.fetchall() column_names = [col[1] for col in columns if col[1] != "vector_hash"] columns_str = ", ".join(column_names) logger.info(f"Колонки для сохранения: {columns_str}") # Пересоздаём таблицу await conn.execute("BEGIN TRANSACTION") try: # Создаём временную таблицу await conn.execute( f"CREATE TABLE post_from_telegram_suggest_backup AS " f"SELECT {columns_str} FROM post_from_telegram_suggest" ) # Удаляем старую таблицу await conn.execute("DROP TABLE post_from_telegram_suggest") # Переименовываем временную await conn.execute( "ALTER TABLE post_from_telegram_suggest_backup " "RENAME TO post_from_telegram_suggest" ) await conn.execute("COMMIT") except Exception as e: await conn.execute("ROLLBACK") raise e await conn.commit() logger.info("Колонка vector_hash успешно удалена") if __name__ == "__main__": parser = argparse.ArgumentParser( description="Удаление колонки vector_hash из post_from_telegram_suggest" ) parser.add_argument( "--db", default=os.environ.get("DATABASE_PATH", DEFAULT_DB_PATH), help="Путь к БД", ) args = parser.parse_args() asyncio.run(main(args.db))