Skip to content

Commit

Permalink
#22: feat: add common MongoRepository for working with data from Mo…
Browse files Browse the repository at this point in the history
…ngoDB
  • Loading branch information
ReznikovRoman committed Jul 10, 2022
1 parent 53fb06b commit 28df02b
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 1 deletion.
7 changes: 7 additions & 0 deletions src/ugc/containers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging.config
from functools import partial

import orjson
from dependency_injector import containers, providers
Expand Down Expand Up @@ -48,6 +49,12 @@ class Container(containers.DeclarativeContainer):
repositories.RedisRepository,
)

mongo_repository_factory = partial(
providers.Factory,
provides=repositories.MongoRepository,
db=mongo_client,
)

kafka_producer_client = providers.Resource(
producers.init_kafka_producer_client,
servers=providers.List(config.KAFKA_URL),
Expand Down
73 changes: 72 additions & 1 deletion src/ugc/infrastructure/db/repositories.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import functools
from operator import and_
from typing import Generic, Type, TypeVar
from typing import Any, Generic, Type, TypeVar

from aredis_om.model.model import NotFoundError, RedisModel
from bson import ObjectId
from pymongo import ASCENDING

from ugc.domain.factories import BaseModelFactory
from ugc.domain.types import BaseModel
from ugc.helpers import resolve_callables

from .clients import MongoCollectionClient, MongoDatabaseClient
from .types import PaginationCursor

_RM = TypeVar("_RM", bound=RedisModel)
_BM = TypeVar("_BM", bound=BaseModel)

MongoResult = dict[str, Any]


class RedisRepository(Generic[_RM]):
Expand Down Expand Up @@ -72,3 +82,64 @@ def _extract_model_params(defaults: dict | None, **kwargs) -> dict:
params = {k: v for k, v in kwargs.items()}
params.update(defaults)
return params


class MongoRepository(Generic[_BM]):
"""Репозиторий для работы с данными из MongoDB."""

def __init__(self, db: MongoDatabaseClient, factory: BaseModelFactory, collection_name: str) -> None:
assert isinstance(db, MongoDatabaseClient)
self._db = db

assert isinstance(factory, BaseModelFactory)
self._factory = factory

assert isinstance(collection_name, str)
self._collection_name = collection_name

@property
def collection(self) -> MongoCollectionClient:
return self._db[self._collection_name]

def get_paginated_results_iter(
self, *,
limit: int,
cursor: PaginationCursor = None,
ordering: tuple[str, int] | None = None, filter_query: dict | None = None, pagination_query: dict | None = None,
):
"""Получение итератора по результатам с пагинацией."""
if ordering is None:
ordering = ("_id", ASCENDING)
if pagination_query is None:
pagination_query = {"_id": {"$gt": ObjectId(cursor)}}

if cursor is None:
return self.collection.find(filter_query).limit(limit).sort(*ordering)
filter_query.update(pagination_query)
return self.collection.find(filter_query).limit(limit).sort(*ordering)

async def get_paginated_results(
self, *,
limit: int,
cursor: PaginationCursor = None, cursor_field: str,
ordering: tuple[str, int] | None = None, filter_query: dict | None = None, pagination_query: dict | None = None,
) -> tuple[list[_BM], PaginationCursor]:
"""Получение списка документов с использованием `cursor-based` пагинации."""
raw_results = self.get_paginated_results_iter(
limit=limit, cursor=cursor, ordering=ordering, filter_query=filter_query, pagination_query=pagination_query)
results = [
self._factory.create_from_serialized(self.fix_id_field(raw_result))
async for raw_result in raw_results
]

if not results:
return [], None

new_cursor = results[-1].__getattribute__(cursor_field)
return results, new_cursor

@staticmethod
def fix_id_field(data: MongoResult) -> MongoResult:
"""Переименование поля `_id`."""
data["id"] = str(data.pop("_id"))
return data
1 change: 1 addition & 0 deletions src/ugc/infrastructure/db/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PaginationCursor = str | None

0 comments on commit 28df02b

Please sign in to comment.