import disnake from disnake.ext import commands from disnake.ext import tasks from typing import Optional, Union, List, Dict, Any, AsyncIterator, Tuple import datetime from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import joinedload, selectinload, contains_eager from sqlalchemy import select, delete, insert, update, func, asc, desc from sqlalchemy import and_, or_, not_ import subprocess import os from types import SimpleNamespace class Model: def __init__(self, model): self.model = model self.m = model async def __aenter__(self): return self.model async def __aexit__(self, exc_type, exc_val, exc_tb): return None class DatabaseManager: def __init__(self, engine, tables_data): self.engine = engine self.session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) self.metadata = tables_data['base'].metadata self.model_classes = {} tables = self.metadata.tables for table_name, table in tables.items(): model_class = next((cls for cls in tables_data['base'].__subclasses__() if cls.__tablename__ == table_name), None) if model_class: #print(f"Table: {table_name}, Model Class: {model_class.__name__}") self.model_classes[table_name] = model_class self.models = {table_name: Model(model) for table_name, model in self.model_classes.items()} self.tables_data = tables_data #функции sqlalchemy self.joinedload = joinedload self.selectinload = selectinload self.contains_eager = contains_eager self.select = select self.delete = delete self.insert = insert self.update = update self.func = func self.desc = desc self.asc = asc self.and_ = and_ self.or_ = or_ self.not_ = not_ #ошибки sqlalchemy exceptions = SimpleNamespace( IntegrityError = IntegrityError ) async def close(self): await self.engine.dispose() async def pg_dump(self, echo=False, backup_file='src/backups/discord_economy_bot_backup.sql'): conn = await self.engine.connect() db_name = self.engine.url.database user = self.engine.url.username host = self.engine.url.host port = self.engine.url.port password = self.engine.url.password os.environ['PGPASSWORD'] = password command = [ 'pg_dump', '-h', host, '-p', str(port), '-U', user, '-F', 'p', # <-- plain text SQL ] + (['-v'] if echo else []) + [ '-f', backup_file, db_name ] try: subprocess.run(command, check=True) if echo: print(f"{datetime.datetime.now():%H:%M:%S %d-%m-%Y} :: SQL backup of '{db_name}' created.") return backup_file except subprocess.CalledProcessError as e: print(f"{datetime.datetime.now():%H:%M:%S %d-%m-%Y} :: Backup failed: {e}") return f"{datetime.datetime.now():%H:%M:%S %d-%m-%Y} :: Backup failed: {e}" finally: await conn.close() async def pg_restore(self, echo = False, backup_file = 'src/backups/backup_file.backup'): conn = await self.engine.connect() db_name = self.engine.url.database user = self.engine.url.username host = self.engine.url.host port = self.engine.url.port password = self.engine.url.password os.environ['PGPASSWORD'] = password # Установка пароля для подключения command = [ 'pg_restore', '-h', host, '-p', str(port), '-U', user, '-d', db_name, # Имя базы данных, в которую будет восстановлено ] + ([ '-v' # Подробный вывод ] if echo else []) + [ backup_file # Путь к файлу резервной копии ] try: subprocess.run(command, check=True) if echo: print(f"{datetime.datetime.now().strftime('%H:%M:%S %d-%m-%Y')}:: Database '{db_name}' restored successfully from '{backup_file}'.") except subprocess.CalledProcessError as e: print(f"{datetime.datetime.now().strftime('%H:%M:%S %d-%m-%Y')}:: Error during restore: {e}") finally: await conn.close()