from typing import List import aiomysql from app.models.instance import Instance from app.services.db_connector import DBConnector class InstanceService: @staticmethod async def test_connection(instance: Instance) -> dict: """Test database connection using DBConnector.""" result = await DBConnector.test_connection(instance) # Update instance status based on result if result.success: instance.status = "connected" instance.version = result.version else: instance.status = "error" return result.to_dict() @staticmethod async def list_databases(instance: Instance) -> List[str]: """List databases for the given instance type.""" if instance.db_type == "mysql": conn = await aiomysql.connect( host=instance.host, port=instance.port, user=instance.username, password=instance.password, ) try: async with conn.cursor() as cur: await cur.execute("SHOW DATABASES") rows = await cur.fetchall() return [row[0] for row in rows if row[0] not in ("information_schema", "mysql", "performance_schema", "sys")] finally: conn.close() elif instance.db_type in ("postgres", "postgresql"): import asyncpg dsn = f"postgresql://{instance.username}:{instance.password}@{instance.host}:{instance.port}/postgres" conn = await asyncpg.connect(dsn) try: rows = await conn.fetch("SELECT datname FROM pg_database WHERE datistemplate = false") return [r["datname"] for r in rows] finally: await conn.close() elif instance.db_type == "redis": from app.services.redis_connector import RedisConnector conn = await RedisConnector.get_connection(instance) try: db_count = await conn.config_get("databases") num = int(db_count.get("databases", 16)) return [f"db{i}" for i in range(num)] finally: await conn.close() elif instance.db_type == "mongo": from pymongo import MongoClient pwd = instance.password if pwd and not pwd.startswith("$"): from app.core.crypto import decrypt_password try: pwd = decrypt_password(pwd) except Exception: pass uri = f"mongodb://{instance.username}:{pwd}@{instance.host}:{instance.port}/admin" client = MongoClient(uri, serverSelectionTimeoutMS=5000) try: dbs = client.list_database_names() return [d for d in dbs if d not in ("admin", "config", "local")] finally: client.close() elif instance.db_type == "sqlite": return [instance.database or "main"] else: return [] @staticmethod async def list_tables(instance: Instance, database: str) -> List[dict]: """List tables in a database.""" if instance.db_type == "mysql": conn = await aiomysql.connect( host=instance.host, port=instance.port, user=instance.username, password=instance.password, db=database, ) try: async with conn.cursor(aiomysql.DictCursor) as cur: await cur.execute( "SELECT TABLE_NAME as name, TABLE_ROWS as rows, TABLE_TYPE as type " "FROM information_schema.TABLES WHERE TABLE_SCHEMA = %s", (database,) ) return await cur.fetchall() finally: conn.close() elif instance.db_type in ("postgres", "postgresql"): import asyncpg dsn = f"postgresql://{instance.username}:{instance.password}@{instance.host}:{instance.port}/{database}" conn = await asyncpg.connect(dsn) try: rows = await conn.fetch( "SELECT tablename as name FROM pg_tables WHERE schemaname = 'public'" ) return [dict(r) for r in rows] finally: await conn.close() elif instance.db_type == "mongo": from pymongo import MongoClient pwd = instance.password if pwd and not pwd.startswith("$"): from app.core.crypto import decrypt_password try: pwd = decrypt_password(pwd) except Exception: pass uri = f"mongodb://{instance.username}:{pwd}@{instance.host}:{instance.port}/{database}" client = MongoClient(uri, serverSelectionTimeoutMS=5000) try: db_obj = client[database] colls = db_obj.list_collection_names() return [{"name": c} for c in colls] finally: client.close() elif instance.db_type == "sqlite": import sqlite3 db_path = instance.host conn = sqlite3.connect(db_path) cur = conn.execute("SELECT name FROM sqlite_master WHERE type='table'") tables = [{"name": row[0]} for row in cur.fetchall()] conn.close() return tables else: return []