feat: pagination and query params for a deal end-point
This commit is contained in:
@ -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
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user