import sys
import os
# Добавляем директорию src в путь для импорта
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from .config import DB_CONFIGS
from .adapters.mongo_adapter import MongoAdapter
from .adapters.sql_adapter import SQLAdapter
class DBConnector:
_instances = {}
def __new__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(DBConnector, cls).__new__(cls)
return cls._instances[cls]
def __init__(self):
if not hasattr(self, 'adapter'):
self.adapter = None
self.db_type = None
def _get_adapter(self, db_type: str, db_config: dict):
if db_type == 'mongodb':
db_instance = db_config.get('db_instance')
return MongoAdapter(db_config, db_instance)
elif db_type in ['sqlite', 'mysql', 'postgresql']:
db_instance = db_config.get('db_instance')
# Добавляем тип базы данных в конфиг для SQL адаптера
config = db_config.copy()
config['type'] = db_type
return SQLAdapter(config, db_instance)
else:
raise ValueError(f"Неподдерживаемый тип базы данных: {db_type}")
def connect(self, db_type: str, db_config: dict = None):
# Если уже подключены к той же базе данных, ничего не делаем
if self.adapter and self.db_type == db_type:
# Проверяем, что соединение все еще активно
try:
if hasattr(self.adapter, 'connection') and self.adapter.connection:
# Для SQLite проверяем состояние соединения
if db_type == 'sqlite':
self.adapter.connection.execute('SELECT 1')
except:
# Если соединение разорвано, отключаемся и переподключаемся
self.disconnect()
else:
return
if self.adapter:
self.disconnect()
config = db_config or DB_CONFIGS.get(db_type)
if not config:
raise ValueError(f"Конфигурация для '{db_type}' не найдена.")
self.db_type = db_type
self.adapter = self._get_adapter(db_type, config)
self.adapter.connect()
def disconnect(self):
if self.adapter:
try:
self.adapter.disconnect()
except Exception as e:
# Логируем ошибку при отключении, но не прерываем выполнение
pass
finally:
self.adapter = None
self.db_type = None
def execute(self, parsed_query: dict):
"""
Выполняет запрос, делегируя его адаптеру.
"""
operation = parsed_query.get('operation', '').upper()
# Если есть raw_mongo - выполняем как raw MongoDB команду
# Это важно для команд типа db.collection.updateOne(...) которые
# парсятся как UPDATE но должны выполняться через execute_raw
if 'raw_mongo' in parsed_query and self.db_type == 'mongodb':
return self.adapter.execute_raw(parsed_query.get('raw_mongo'))
if operation == 'SELECT':
return self.adapter.select(
table=parsed_query.get('table'),
columns=parsed_query.get('columns', []),
condition=parsed_query.get('condition', {})
)
elif operation == 'INSERT':
return self.adapter.insert(
table=parsed_query.get('table'),
data=parsed_query.get('data', {})
)
elif operation == 'UPDATE':
return self.adapter.update(
table=parsed_query.get('table'),
data=parsed_query.get('data', {}),
condition=parsed_query.get('condition', {})
)
elif operation == 'DELETE':
return self.adapter.delete(
table=parsed_query.get('table'),
condition=parsed_query.get('condition', {})
)
elif operation == 'ALTER':
return self.adapter.alter(
table=parsed_query.get('table'),
instruction=parsed_query # Передаем весь словарь для ALTER
)
elif operation == 'RAW_SQL':
# Выполняем сырой SQL запрос
return self.adapter.execute_raw(parsed_query.get('query'))
elif operation == 'RAW_MONGO':
# Выполняем сырую MongoDB команду
return self.adapter.execute_raw(parsed_query.get('raw_mongo'))
elif operation == 'CREATE_TABLE':
# Создание таблицы/коллекции
return self.adapter.create_table(
table_name=parsed_query.get('table'),
schema=parsed_query.get('schema')
)
elif operation == 'DROP_TABLE':
# Удаление таблицы/коллекции
return self.adapter.drop_table(
table_name=parsed_query.get('table')
)
elif operation == 'CREATE_DATABASE':
# Создание базы данных
return self.adapter.create_database(
database_name=parsed_query.get('database')
)
elif operation == 'USE_DATABASE':
# Переключение на базу данных
return self.adapter.use_database(
database_name=parsed_query.get('database')
)
else:
raise ValueError(f"Неизвестная операция: {operation}")