diff --git a/src/ugc/core/config.py b/src/ugc/core/config.py index d1e146f..53d1152 100644 --- a/src/ugc/core/config.py +++ b/src/ugc/core/config.py @@ -85,7 +85,7 @@ def get_mongodb_url(cls, value, values) -> str: host = values["MONGODB_HOST"] port = values["MONGODB_PORT"] database = values["MONGODB_NAME"] - return f"mongodb://{user}:{password}@{host}:{port}/{database}" + return f"mongodb://{user}:{password}@{host}:{port}/{database}?authSource=admin" @lru_cache() diff --git a/src/ugc/infrastructure/db/clients.py b/src/ugc/infrastructure/db/clients.py new file mode 100644 index 0000000..a8b027f --- /dev/null +++ b/src/ugc/infrastructure/db/clients.py @@ -0,0 +1,42 @@ +from motor.core import AgnosticCollection, AgnosticDatabase +from pymongo import results + + +class MongoDatabaseClient: + """Клиент для работы с базой данной из MongoDB.""" + + collection_cache: dict[tuple, "MongoCollectionClient"] = {} + + def __init__(self, db_client: AgnosticDatabase) -> None: + assert isinstance(db_client, AgnosticDatabase) + self._client = db_client + + def __getattr__(self, name: str) -> "MongoCollectionClient": + if name.startswith("_"): + raise AttributeError(f"Cannot access private collection <{name}>") + return self[name] + + def __getitem__(self, name: str) -> "MongoCollectionClient": + mongo_client = self._client.__getattr__(name) + return self._get_collection_client(name, mongo_client) + + def _get_collection_client(self, name: str, mongo_client: AgnosticCollection) -> "MongoCollectionClient": + cache_key = ("MongoCollectionClient", name, self.__module__) + cached_client = self.collection_cache.get(cache_key) + if cached_client: + return cached_client + new_client = MongoCollectionClient(collection_client=mongo_client) + return new_client + + +class MongoCollectionClient: + """Клиент для работы с коллекций документов MongoDB.""" + + def __init__(self, collection_client: AgnosticCollection) -> None: + assert isinstance(collection_client, AgnosticCollection) + self._client = collection_client + + async def insert_one(self, document: dict) -> results.InsertOneResult: + """Добавление одного документа в коллекцию.""" + result = await self._client.insert_one(document) + return result diff --git a/src/ugc/infrastructure/db/mongo.py b/src/ugc/infrastructure/db/mongo.py index 508bd81..a8a10d9 100644 --- a/src/ugc/infrastructure/db/mongo.py +++ b/src/ugc/infrastructure/db/mongo.py @@ -3,13 +3,33 @@ from typing import TYPE_CHECKING, AsyncIterator import motor.motor_asyncio +from pymongo import ASCENDING, IndexModel + +from .clients import MongoDatabaseClient if TYPE_CHECKING: from motor.core import AgnosticClient, AgnosticDatabase -async def init_mongo(url: str) -> AsyncIterator[AgnosticDatabase]: +async def init_mongo(url: str) -> AsyncIterator[MongoDatabaseClient]: mongo_client: AgnosticClient = motor.motor_asyncio.AsyncIOMotorClient(url) mongo_default_db: AgnosticDatabase = mongo_client.get_default_database() - yield mongo_default_db + await configure_db(mongo_default_db) + db_client = MongoDatabaseClient(mongo_default_db) + yield db_client mongo_client.close + + +async def configure_db(db_client: AgnosticDatabase) -> AgnosticDatabase: + await create_indexes(db_client) + return db_client + + +async def create_indexes(db_client: AgnosticDatabase) -> AgnosticDatabase: + review_unique_index = IndexModel( + keys=[("user_id", ASCENDING), ("film_id", ASCENDING)], + name="review_film_user_unq", + unique=True, + ) + await db_client.reviews.create_indexes([review_unique_index]) + return db_client