feat: deals filters

This commit is contained in:
2025-09-01 17:54:45 +04:00
parent 93141da22c
commit 57c3ada2fa
8 changed files with 90 additions and 14 deletions

View File

@ -4,8 +4,10 @@ from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession
from backend.session import get_session
from schemas.base import PaginationSchema
from schemas.base import PaginationSchema, SortingSchema
from utils.pagination import pagination_parameters
from utils.sorting import sorting_parameters
SessionDependency = Annotated[AsyncSession, Depends(get_session)]
PaginationDependency = Annotated[PaginationSchema, Depends(pagination_parameters)]
SortingDependency = Annotated[SortingSchema, Depends(sorting_parameters)]

View File

@ -4,26 +4,42 @@ from sqlalchemy import select
from models import Deal, CardStatusHistory, Board
from repositories.base import BaseRepository
from schemas.base import SortDir
from schemas.deal import UpdateDealSchema, CreateDealSchema
from utils.sorting import apply_sorting
class DealRepository(BaseRepository):
async def get_all(
self,
board_id: Optional[int],
project_id: Optional[int],
page: Optional[int],
items_per_page: Optional[int],
field: Optional[str],
direction: Optional[SortDir],
project_id: Optional[int],
board_id: Optional[int],
status_id: Optional[int],
id: Optional[int],
name: Optional[str],
) -> 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 id:
stmt = stmt.where(Deal.id == id)
if project_id:
stmt = stmt.join(Board).where(Board.project_id == project_id)
if board_id:
stmt = stmt.where(Deal.board_id == board_id)
if status_id:
stmt = stmt.where(Deal.status_id == status_id)
if name:
stmt = stmt.where(Deal.name.ilike(f"%{name}%"))
total_items = len((await self.session.execute(stmt)).all())
if field and direction is not None:
stmt = apply_sorting(stmt, Deal, field, direction)
else:
stmt = stmt.order_by(Deal.lexorank)
if page and items_per_page:

View File

@ -1,6 +1,10 @@
from fastapi import APIRouter, Path, Query
from backend.dependecies import SessionDependency, PaginationDependency
from backend.dependecies import (
SessionDependency,
PaginationDependency,
SortingDependency,
)
from schemas.deal import *
from services import DealService
@ -17,10 +21,22 @@ deal_router = APIRouter(
async def get_deals(
session: SessionDependency,
pagination: PaginationDependency,
board_id: Optional[int] = Query(alias="boardId", default=None),
sorting: SortingDependency,
project_id: Optional[int] = Query(alias="projectId", default=None),
board_id: Optional[int] = Query(alias="boardId", default=None),
status_id: Optional[int] = Query(alias="statusId", default=None),
id: Optional[int] = Query(default=None),
name: Optional[str] = Query(default=None),
):
return await DealService(session).get_deals(pagination, board_id, project_id)
return await DealService(session).get_deals(
pagination,
sorting,
project_id,
board_id,
status_id,
id,
name,
)
@deal_router.post(

View File

@ -1,4 +1,4 @@
from typing import Self, Optional
from typing import Self, Optional, Literal
from pydantic import BaseModel
from pydantic.alias_generators import to_camel
@ -45,6 +45,14 @@ class PaginationInfoSchema(BaseSchema):
total_items: int
type SortDir = Literal["asc", "desc"]
class SortingSchema(BaseSchema):
field: Optional[str] = None
direction: Optional[SortDir] = None
class BaseEnumSchema(BaseSchema):
id: int
name: str

View File

@ -12,6 +12,7 @@ class DealSchema(BaseSchema):
name: str
lexorank: str
status_id: int
board_id: int
created_at: datetime

View File

@ -4,7 +4,7 @@ from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from repositories import DealRepository
from schemas.base import PaginationSchema
from schemas.base import PaginationSchema, SortingSchema
from schemas.deal import *
@ -15,11 +15,15 @@ class DealService:
async def get_deals(
self,
pagination: PaginationSchema,
board_id: Optional[int],
project_id: Optional[int],
sorting: SortingSchema,
*filters,
) -> GetDealsResponse:
deals, total_items = await self.repository.get_all(
board_id, project_id, pagination.page, pagination.items_per_page
pagination.page,
pagination.items_per_page,
sorting.field,
sorting.direction,
*filters,
)
total_pages = 1

21
utils/sorting.py Normal file
View File

@ -0,0 +1,21 @@
from typing import Optional
from fastapi import Query
from sqlalchemy import Select
from schemas.base import SortingSchema, SortDir
from utils.strings import camel_to_snake
async def sorting_parameters(
field: Optional[str] = Query(default=None, alias="sortingField"),
direction: Optional[SortDir] = Query(default=None, alias="sortingDirection"),
) -> SortingSchema:
return SortingSchema(field=camel_to_snake(field), direction=direction)
def apply_sorting(stmt: Select, cls: type, field: str, direction: SortDir) -> Select:
attr = getattr(cls, field)
if direction == "asc":
return stmt.order_by(attr.asc())
return stmt.order_by(attr.desc())

8
utils/strings.py Normal file
View File

@ -0,0 +1,8 @@
import re
from typing import Optional
def camel_to_snake(string: Optional[str]) -> str:
if not string:
return string
return re.sub(r"(?<!^)(?=[A-Z])", "_", string).lower()