TCPDashboard/database/operations.py
Vasily.onl 028371a0e1 Refactor database operations and enhance repository structure
- Introduced a modular repository structure by creating separate repository classes for `Bot`, `MarketData`, and `RawTrade`, improving code organization and maintainability.
- Updated the `DatabaseOperations` class to utilize the new repository classes, enhancing the abstraction of database interactions.
- Refactored the `.env` file to update database connection parameters and add new logging and health monitoring configurations.
- Modified the `okx_config.json` to change default timeframes for trading pairs, aligning with updated requirements.
- Added comprehensive unit tests for the new repository classes, ensuring robust functionality and reliability.

These changes improve the overall architecture of the database layer, making it more scalable and easier to manage.
2025-06-06 21:54:45 +08:00

100 lines
3.4 KiB
Python

"""
Database Operations Module
This module provides a centralized `DatabaseOperations` class that serves as the
main entry point for all database interactions. It follows the Repository pattern
by composing individual repository classes, each responsible for a specific table.
"""
import logging
from typing import Optional, Dict, Any
from sqlalchemy import text
from .repositories import (
BotRepository,
MarketDataRepository,
RawTradeRepository,
DatabaseOperationError,
)
class DatabaseOperations:
"""
Main database operations manager that provides access to all repositories.
This is the main entry point for database operations, providing a
centralized interface to all table-specific repositories.
"""
def __init__(self, logger: Optional[logging.Logger] = None):
"""Initialize database operations with optional logger."""
self.logger = logger
# Initialize repositories
self.bots = BotRepository(logger)
self.market_data = MarketDataRepository(logger)
self.raw_trades = RawTradeRepository(logger)
def health_check(self) -> bool:
"""
Perform a health check on database connections.
Returns:
True if database is healthy, False otherwise
"""
try:
# We use one of the repositories to get a session
with self.market_data.get_session() as session:
result = session.execute(text("SELECT 1"))
return result.fetchone() is not None
except Exception as e:
if self.logger:
self.logger.error(f"Database health check failed: {e}")
return False
def get_stats(self) -> Dict[str, Any]:
"""
Get database statistics.
Returns:
Dictionary containing database statistics
"""
try:
stats = {
'healthy': self.health_check(),
'repositories': {
'bots': 'BotRepository',
'market_data': 'MarketDataRepository',
'raw_trades': 'RawTradeRepository'
}
}
# Use a single session for all counts for efficiency
with self.market_data.get_session() as session:
stats['bot_count'] = session.execute(text("SELECT COUNT(*) FROM bots")).scalar_one()
stats['candle_count'] = session.execute(text("SELECT COUNT(*) FROM market_data")).scalar_one()
stats['raw_trade_count'] = session.execute(text("SELECT COUNT(*) FROM raw_trades")).scalar_one()
return stats
except Exception as e:
if self.logger:
self.logger.error(f"Error getting database stats: {e}")
return {'healthy': False, 'error': str(e)}
# Singleton instance for global access
_db_operations_instance: Optional[DatabaseOperations] = None
def get_database_operations(logger: Optional[logging.Logger] = None) -> DatabaseOperations:
"""
Get the global database operations instance.
Args:
logger: Optional logger for database operations
Returns:
DatabaseOperations instance
"""
global _db_operations_instance
if _db_operations_instance is None:
_db_operations_instance = DatabaseOperations(logger)
return _db_operations_instance