feat: pagination and query params for a deal end-point

This commit is contained in:
2025-08-28 20:24:24 +04:00
parent 4c7a997be6
commit 5fbd6d6185
6 changed files with 66 additions and 20 deletions

View File

@ -1,6 +1,13 @@
from sqlalchemy import Select
from sqlalchemy.ext.asyncio import AsyncSession
class BaseRepository:
def __init__(self, session: AsyncSession):
self.session = session
@staticmethod
def _apply_pagination(query: Select, page: int, items_per_page: int) -> Select:
offset = (page - 1) * items_per_page
query = query.offset(offset).limit(items_per_page)
return query

View File

@ -2,20 +2,35 @@ from typing import Optional
from sqlalchemy import select
from models import Deal, CardStatusHistory
from models import Deal, CardStatusHistory, Board
from repositories.base import BaseRepository
from schemas.deal import UpdateDealSchema, CreateDealSchema
class DealRepository(BaseRepository):
async def get_all(self, board_id: int) -> list[Deal]:
stmt = (
select(Deal)
.where(Deal.is_deleted.is_(False), Deal.board_id == board_id)
.order_by(Deal.lexorank)
)
async def get_all(
self,
board_id: Optional[int],
project_id: Optional[int],
page: Optional[int],
items_per_page: Optional[int],
) -> tuple[list[Deal], int]:
stmt = select(Deal).where(Deal.is_deleted.is_(False))
if board_id:
stmt = stmt.where(Deal.board_id == board_id)
if project_id:
stmt = stmt.join(Board).where(Board.project_id == project_id)
total_items = len((await self.session.execute(stmt)).all())
stmt = stmt.order_by(Deal.lexorank)
if page and items_per_page:
stmt = self._apply_pagination(stmt, page, items_per_page)
result = await self.session.execute(stmt)
return list(result.scalars().all())
return list(result.scalars().all()), total_items
async def get_by_id(self, deal_id: int) -> Optional[Deal]:
stmt = select(Deal).where(Deal.id == deal_id, Deal.is_deleted.is_(False))

View File

@ -1,6 +1,6 @@
from fastapi import APIRouter, Path
from fastapi import APIRouter, Path, Query
from backend.dependecies import SessionDependency
from backend.dependecies import SessionDependency, PaginationDependency
from schemas.deal import *
from services import DealService
@ -10,15 +10,17 @@ deal_router = APIRouter(
@deal_router.get(
"/{boardId}",
"/",
response_model=GetDealsResponse,
operation_id="get_deals",
)
async def get_deals(
session: SessionDependency,
board_id: int = Path(alias="boardId"),
pagination: PaginationDependency,
board_id: Optional[int] = Query(alias="boardId", default=None),
project_id: Optional[int] = Query(alias="projectId", default=None),
):
return await DealService(session).get_deals(board_id)
return await DealService(session).get_deals(pagination, board_id, project_id)
@deal_router.post(

View File

@ -1,7 +1,7 @@
from datetime import datetime
from typing import Optional
from schemas.base import BaseSchema, BaseResponse
from schemas.base import BaseSchema, BaseResponse, PaginationInfoSchema
# region Entities
@ -48,6 +48,7 @@ class UpdateDealRequest(BaseSchema):
class GetDealsResponse(BaseSchema):
deals: list[DealSchema]
pagination_info: PaginationInfoSchema
class CreateDealResponse(BaseResponse):

View File

@ -1,7 +1,10 @@
import math
from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from repositories import DealRepository
from schemas.base import PaginationSchema
from schemas.deal import *
@ -9,10 +12,25 @@ class DealService:
def __init__(self, session: AsyncSession):
self.repository = DealRepository(session)
async def get_deals(self, board_id: int) -> GetDealsResponse:
deals = await self.repository.get_all(board_id)
async def get_deals(
self,
pagination: PaginationSchema,
board_id: Optional[int],
project_id: Optional[int],
) -> GetDealsResponse:
deals, total_items = await self.repository.get_all(
board_id, project_id, pagination.page, pagination.items_per_page
)
total_pages = 1
if pagination.items_per_page:
total_pages = math.ceil(total_items / pagination.items_per_page)
return GetDealsResponse(
deals=[DealSchema.model_validate(deal) for deal in deals]
deals=[DealSchema.model_validate(deal) for deal in deals],
pagination_info=PaginationInfoSchema(
total_pages=total_pages, total_items=total_items
),
)
async def create_deal(self, request: CreateDealRequest) -> CreateDealResponse:

View File

@ -1,10 +1,13 @@
from typing import Optional
from fastapi import Query
from schemas.base import PaginationSchema
async def pagination_parameters(
page: Optional[int] = None, items_per_page: Optional[int] = None
page: Optional[int] = Query(default=None),
items_per_page: Optional[int] = Query(default=None, alias="itemsPerPage"),
) -> PaginationSchema:
return PaginationSchema(page=page, items_per_page=items_per_page)
@ -12,6 +15,6 @@ async def pagination_parameters(
def is_valid_pagination(pagination: Optional[PaginationSchema]) -> bool:
if not pagination:
return False
return all(
[isinstance(pagination.items_per_page, int), isinstance(pagination.page, int)]
return isinstance(pagination.items_per_page, int) and isinstance(
pagination.page, int
)