wag-managment-api-service-v.../Services/MongoDb/database.py

147 lines
4.9 KiB
Python

"""
MongoDB database connection and operations.
This module provides MongoDB connection management with:
1. Connection pooling
2. Lifecycle management
3. Error handling
"""
from typing import Optional, Dict, Any, List, Union
from pymongo import MongoClient
from pymongo.results import InsertOneResult, DeleteResult, UpdateResult
from pymongo.cursor import Cursor
from AllConfigs.NoSqlDatabase.configs import MongoConfig
class MongoInsertMixin:
"""Mixin for MongoDB insert operations."""
def insert_one(self, document: Dict[str, Any]) -> InsertOneResult:
"""Insert a single document."""
return self.collection.insert_one(document)
def insert_many(self, documents: List[Dict[str, Any]]) -> List[InsertOneResult]:
"""Insert multiple documents."""
return self.collection.insert_many(documents)
class MongoFindMixin:
"""Mixin for MongoDB find operations."""
def find_one(self, filter_query: Dict[str, Any]) -> Optional[Dict[str, Any]]:
"""Find a single document."""
return self.collection.find_one(filter_query)
def find_many(self, filter_query: Dict[str, Any]) -> Cursor:
"""Find multiple documents."""
return self.collection.find(filter_query)
class MongoUpdateMixin:
"""Mixin for MongoDB update operations."""
def update_one(self, filter_query: Dict[str, Any], update: Dict[str, Any]) -> UpdateResult:
"""Update a single document."""
return self.collection.update_one(filter_query, update)
def update_many(self, filter_query: Dict[str, Any], update: Dict[str, Any]) -> UpdateResult:
"""Update multiple documents."""
return self.collection.update_many(filter_query, update)
class MongoDeleteMixin:
"""Mixin for MongoDB delete operations."""
def delete_one(self, filter_query: Dict[str, Any]) -> DeleteResult:
"""Delete a single document."""
return self.collection.delete_one(filter_query)
def delete_many(self, filter_query: Dict[str, Any]) -> DeleteResult:
"""Delete multiple documents."""
return self.collection.delete_many(filter_query)
class MongoAggregateMixin:
"""Mixin for MongoDB aggregate operations."""
def aggregate(self, pipeline: List[Dict[str, Any]]) -> Cursor:
"""Execute an aggregation pipeline."""
return self.collection.aggregate(pipeline)
class MongoDBHandler(
MongoInsertMixin,
MongoFindMixin,
MongoUpdateMixin,
MongoDeleteMixin,
MongoAggregateMixin,
):
"""Handler for MongoDB operations with connection management."""
_instance = None
_client: Optional[MongoClient] = None
def __new__(cls):
"""Implement singleton pattern for database connection."""
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
"""Initialize MongoDB connection if not already initialized."""
if not self._client:
# Build connection URL based on whether credentials are provided
if MongoConfig.USER_NAME and MongoConfig.PASSWORD:
connection_url = (
f"mongodb://{MongoConfig.USER_NAME}:{MongoConfig.PASSWORD}"
f"@{MongoConfig.HOST}:{MongoConfig.PORT}"
)
else:
connection_url = f"mongodb://{MongoConfig.HOST}:{MongoConfig.PORT}"
# Build connection options
connection_kwargs = {
"host": connection_url,
"maxPoolSize": 50, # Maximum number of connections in the pool
"minPoolSize": 10, # Minimum number of connections in the pool
"maxIdleTimeMS": 30000, # Maximum time a connection can be idle (30 seconds)
"waitQueueTimeoutMS": 2000, # How long a thread will wait for a connection
"serverSelectionTimeoutMS": 5000, # How long to wait for server selection
}
self._client = MongoClient(**connection_kwargs)
# Test connection
self._client.admin.command('ping')
def close(self):
"""Close MongoDB connection."""
if self._client:
self._client.close()
self._client = None
def __del__(self):
"""Ensure connection is closed on deletion."""
self.close()
@property
def client(self) -> MongoClient:
"""Get MongoDB client."""
return self._client
def get_database(self, database_name: str = None):
"""Get MongoDB database."""
db_name = database_name or MongoConfig.DATABASE_NAME
return self._client[db_name]
def get_collection(self, collection_name: str, database_name: str = None):
"""Get MongoDB collection."""
database = self.get_database(database_name)
return database[collection_name]
# Create a singleton instance
mongodb = MongoDBHandler()