diff --git a/src/clients/countries.py b/src/clients/countries.py index 8ca1260..9668e46 100644 --- a/src/clients/countries.py +++ b/src/clients/countries.py @@ -54,7 +54,7 @@ def get_list_by_codes(self, alpha2codes: set[str]) -> Optional[list[CountryModel currencies=country.get("currencies"), languages=country.get("languages"), ) - for country in response + for country in response.get("results", []) ] return None diff --git a/src/clients/places.py b/src/clients/places.py index bc7139e..e1bf1b2 100644 --- a/src/clients/places.py +++ b/src/clients/places.py @@ -3,7 +3,7 @@ from urllib.parse import urlencode, urljoin from src.clients.base.base import BaseClient -from src.models.places import PlaceModel +from src.models.places import PlaceModel, UpdatePlaceModel from src.settings import settings @@ -33,20 +33,23 @@ def get_place(self, place_id: int) -> Optional[PlaceModel]: return None - def get_list(self) -> Optional[list[PlaceModel]]: + def get_list(self, page: int, size: int) -> Optional[list[PlaceModel]]: """ Получение списка любимых мест. - TODO: добавить пагинацию. + :param page: Номер страницы. + :param size: Количество объектов на странице. :return: """ endpoint = "/api/v1/places" query_params = { "limit": 20, + "page": page, + "size": size, } url = urljoin(self.base_url, f"{endpoint}?{urlencode(query_params)}") if response := self._request(self.GET, url): - return [self.__build_model(place) for place in response.get("data", [])] + return [self.__build_model(place) for place in response.get("items", [])] return None @@ -66,6 +69,24 @@ def create_place(self, place: PlaceModel) -> Optional[PlaceModel]: return None + def update_place( + self, place_id: int, place: UpdatePlaceModel + ) -> tuple[bool, PlaceModel | None]: + """ + Обновление объекта любимого места по его идентификатору. + :param place_id: Идентификатор объекта. + :param place: Объект любимого места для обновления. + :return: + """ + + endpoint = f"/api/v1/places/{place_id}" + url = urljoin(self.base_url, endpoint) + if response := self._request(self.PATCH, url, body=place.dict()): + if place_data := response.get("data"): + return True, self.__build_model(place_data) + + return False, None + def delete_place(self, place_id: int) -> bool: """ Удаление объекта любимого места по его идентификатору. diff --git a/src/models/places.py b/src/models/places.py index 3c3cca6..e57359b 100644 --- a/src/models/places.py +++ b/src/models/places.py @@ -17,3 +17,13 @@ class PlaceModel(TimeStampMixin, BaseModel): country: Optional[str] = Field(title="ISO Alpha2-код страны") city: Optional[str] = Field(title="Название города") locality: Optional[str] = Field(title="Местонахождение") + + +class UpdatePlaceModel(TimeStampMixin, BaseModel): + """ + Модель для обновления места. + """ + + latitude: float | None = Field(title="Широта") + longitude: float | None = Field(title="Долгота") + description: str | None = Field(title="Описание") diff --git a/src/schema/mutation.py b/src/schema/mutation.py index ad5a467..767e297 100644 --- a/src/schema/mutation.py +++ b/src/schema/mutation.py @@ -3,7 +3,7 @@ import graphene from graphql import ResolveInfo -from src.models.places import PlaceModel +from src.models.places import PlaceModel, UpdatePlaceModel from src.schema.query import Place from src.services.places import PlacesService @@ -48,6 +48,42 @@ def mutate( return CreatePlace(place=place, result=bool(place)) +class UpdatePlace(graphene.Mutation): + """ + Функции для обновления объекта любимого места. + """ + + class Arguments: + place_id = graphene.Int() + latitude = graphene.Float() + longitude = graphene.Float() + description = graphene.String() + + result = graphene.Boolean() + place = graphene.Field(Place) + + @staticmethod + def mutate(parent: Optional[dict], info: ResolveInfo, place_id: int, latitude: float | None = None, longitude: float | None = None, description: str | None = None) -> "UpdatePlace": + """ + Обработка запроса для обновления объекта по его идентификатору. + :param parent: Информация о родительском объекте (при наличии). + :param info: Объект с метаинформацией и данных о контексте запроса. + :param place_id: Идентификатор объекта для обновления. + :param latitude: Широта. + :param longitude: Долгота. + :param description: Описание. + :return: + """ + + # получение результата обновления объекта + model = UpdatePlaceModel( + latitude=latitude, longitude=longitude, description=description + ) + result, place = PlacesService().update_place(place_id, model) + + return UpdatePlace(result=result, place=place) + + class DeletePlace(graphene.Mutation): """ Функции для удаления объекта любимого места. diff --git a/src/schema/query.py b/src/schema/query.py index d43f7a0..670827a 100644 --- a/src/schema/query.py +++ b/src/schema/query.py @@ -69,26 +69,32 @@ class Query(graphene.ObjectType): """ #: запрос для получения списка объектов любимых мест - places = graphene.List(Place) + places = graphene.List(Place, page=graphene.Int(), size=graphene.Int()) #: запрос для получения конкретного объекта любимого места по идентификатору place = Field(Place, place_id=ID(required=True)) @staticmethod def resolve_places( - parent: Optional[dict], info: ResolveInfo + parent: Optional[dict], info: ResolveInfo, page: int | None = None, size: int | None = None, ) -> Optional[list[PlaceModel]]: """ Получение списка объектов любимых мест. :param parent: Объект любимого места. :param info: Объект с метаинформацией и данных о контексте запроса. + :param page: Номер страницы. + :param size: Количество объектов на странице. :return: """ # pylint: disable=unused-argument - return PlacesService().get_places() + if page is None: + page = 1 + if size is None: + size = 20 + return PlacesService().get_places(page=page, size=size) @staticmethod def resolve_place( diff --git a/src/services/places.py b/src/services/places.py index e28e604..d7a8a5a 100644 --- a/src/services/places.py +++ b/src/services/places.py @@ -1,7 +1,7 @@ from typing import Optional from src.clients.places import PlacesClient -from src.models.places import PlaceModel +from src.models.places import PlaceModel, UpdatePlaceModel class PlacesService: @@ -18,14 +18,14 @@ def get_place(self, place_id: int) -> Optional[PlaceModel]: return PlacesClient().get_place(place_id) - def get_places(self) -> Optional[list[PlaceModel]]: + def get_places(self, page: int, size: int) -> Optional[list[PlaceModel]]: """ Получение списка любимых мест. :return: """ - return PlacesClient().get_list() + return PlacesClient().get_list(page=page, size=size) def create_place(self, place: PlaceModel) -> Optional[PlaceModel]: """ @@ -37,6 +37,9 @@ def create_place(self, place: PlaceModel) -> Optional[PlaceModel]: return PlacesClient().create_place(place) + def update_place(self, place_id: int, model: UpdatePlaceModel) -> tuple[bool, PlaceModel | None]: + return PlacesClient().update_place(place_id, model) + def delete_place(self, place_id: int) -> bool: """ Удаление объекта любимого места по его идентификатору.