""" Database connection and operations for analytics. """ import os import ssl import logging from motor.motor_asyncio import AsyncIOMotorClient from typing import Optional logger = logging.getLogger(__name__) # Global database connection _client: Optional[AsyncIOMotorClient] = None _database = None async def get_database(): """Get or create MongoDB database connection""" global _client, _database if _database is None: await connect_to_database() return _database async def connect_to_database(): """Connect to MongoDB database""" global _client, _database try: # Get MongoDB connection string from environment mongodb_url = os.getenv("MONGODB_URL") if not mongodb_url: # For learning project, use JSON file fallback if no MongoDB logger.warning("MONGODB_URL not set. Analytics will use JSON file storage.") return None # Create motor client with SSL configuration _client = AsyncIOMotorClient( mongodb_url, tls=True, tlsInsecure=True, serverSelectionTimeoutMS=5000, connectTimeoutMS=20000, socketTimeoutMS=20000 ) # Get database (atlas_analytics by default) database_name = os.getenv("MONGODB_DATABASE", "atlas_analytics") _database = _client[database_name] # Test the connection immediately await _database.command("ping") logger.info(f"Connected to MongoDB database: {database_name}") return _database except Exception as e: logger.warning(f"MongoDB connection failed : {e}") logger.info("Falling back to JSON file storage for analytics") _client = None _database = None return None async def test_connection() -> bool: """Test database connection""" try: db = await get_database() if db is None: return False # Simple ping test await db.command("ping") logger.info("MongoDB connection test successful") return True except Exception as e: logger.error(f"MongoDB connection test failed: {e}") return False async def close_connection(): """Close database connection""" global _client, _database if _client: _client.close() _client = None _database = None logger.info("MongoDB connection closed") # Collection helpers async def get_sessions_collection(): """Get sessions collection""" db = await get_database() return db.sessions if db is not None else None async def get_messages_collection(): """Get messages collection""" db = await get_database() return db.messages if db is not None else None async def get_search_analytics_collection(): """Get search analytics collection""" db = await get_database() return db.search_analytics if db is not None else None