from typing import TYPE_CHECKING, Optional from uuid import UUID from litestar import Controller, get, post, put from litestar.contrib.repository.filters import LimitOffset, SearchFilter from litestar.di import Provide from sqlalchemy.ext.asyncio import AsyncSession from app.domain.city import City, CityReadDTO, CityWriteDTO, Repository, Service from app.lib.responses import ObjectListResponse, ObjectResponse if TYPE_CHECKING: from sqlalchemy.ext.asyncio import AsyncSession DETAIL_ROUTE = "/{city_id:uuid}" def provides_service(db_session: AsyncSession) -> Service: """Constructs repository and service objects for the request.""" return Service(Repository(session=db_session)) class CityController(Controller): dto = CityWriteDTO return_dto = CityReadDTO path = "/cities" dependencies = { "service": Provide(provides_service, sync_to_thread=False), } tags = ["Cities"] @get() async def get_cities( self, service: Service, search: Optional[str] = None ) -> ObjectListResponse[City]: filters = [ LimitOffset(limit=20, offset=0), ] if search is not None: filters.append( SearchFilter( field_name="caption", value=search, ), ) content = await service.list(*filters) return ObjectListResponse(content=content) @post() async def create_city( self, data: City, service: Service, ) -> ObjectResponse[City]: content = await service.create(data) return ObjectResponse(content=content) @get(DETAIL_ROUTE) async def get_city(self, service: Service, city_id: UUID) -> ObjectResponse[City]: content = await service.get(city_id) return ObjectResponse(content=content) @put(DETAIL_ROUTE) async def update_city( self, data: City, service: Service, city_id: UUID ) -> ObjectResponse[City]: data.id = city_id content = await service.update(city_id, data) return ObjectResponse(content=content)