feat: deals filters
This commit is contained in:
@ -4,8 +4,10 @@ from fastapi import Depends
|
|||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from backend.session import get_session
|
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.pagination import pagination_parameters
|
||||||
|
from utils.sorting import sorting_parameters
|
||||||
|
|
||||||
SessionDependency = Annotated[AsyncSession, Depends(get_session)]
|
SessionDependency = Annotated[AsyncSession, Depends(get_session)]
|
||||||
PaginationDependency = Annotated[PaginationSchema, Depends(pagination_parameters)]
|
PaginationDependency = Annotated[PaginationSchema, Depends(pagination_parameters)]
|
||||||
|
SortingDependency = Annotated[SortingSchema, Depends(sorting_parameters)]
|
||||||
|
|||||||
@ -4,26 +4,42 @@ from sqlalchemy import select
|
|||||||
|
|
||||||
from models import Deal, CardStatusHistory, Board
|
from models import Deal, CardStatusHistory, Board
|
||||||
from repositories.base import BaseRepository
|
from repositories.base import BaseRepository
|
||||||
|
from schemas.base import SortDir
|
||||||
from schemas.deal import UpdateDealSchema, CreateDealSchema
|
from schemas.deal import UpdateDealSchema, CreateDealSchema
|
||||||
|
from utils.sorting import apply_sorting
|
||||||
|
|
||||||
|
|
||||||
class DealRepository(BaseRepository):
|
class DealRepository(BaseRepository):
|
||||||
async def get_all(
|
async def get_all(
|
||||||
self,
|
self,
|
||||||
board_id: Optional[int],
|
|
||||||
project_id: Optional[int],
|
|
||||||
page: Optional[int],
|
page: Optional[int],
|
||||||
items_per_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]:
|
) -> tuple[list[Deal], int]:
|
||||||
stmt = select(Deal).where(Deal.is_deleted.is_(False))
|
stmt = select(Deal).where(Deal.is_deleted.is_(False))
|
||||||
|
|
||||||
if board_id:
|
if id:
|
||||||
stmt = stmt.where(Deal.board_id == board_id)
|
stmt = stmt.where(Deal.id == id)
|
||||||
if project_id:
|
if project_id:
|
||||||
stmt = stmt.join(Board).where(Board.project_id == 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())
|
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)
|
stmt = stmt.order_by(Deal.lexorank)
|
||||||
|
|
||||||
if page and items_per_page:
|
if page and items_per_page:
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
from fastapi import APIRouter, Path, Query
|
from fastapi import APIRouter, Path, Query
|
||||||
|
|
||||||
from backend.dependecies import SessionDependency, PaginationDependency
|
from backend.dependecies import (
|
||||||
|
SessionDependency,
|
||||||
|
PaginationDependency,
|
||||||
|
SortingDependency,
|
||||||
|
)
|
||||||
from schemas.deal import *
|
from schemas.deal import *
|
||||||
from services import DealService
|
from services import DealService
|
||||||
|
|
||||||
@ -17,10 +21,22 @@ deal_router = APIRouter(
|
|||||||
async def get_deals(
|
async def get_deals(
|
||||||
session: SessionDependency,
|
session: SessionDependency,
|
||||||
pagination: PaginationDependency,
|
pagination: PaginationDependency,
|
||||||
board_id: Optional[int] = Query(alias="boardId", default=None),
|
sorting: SortingDependency,
|
||||||
project_id: Optional[int] = Query(alias="projectId", default=None),
|
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(
|
@deal_router.post(
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from typing import Self, Optional
|
from typing import Self, Optional, Literal
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
@ -45,6 +45,14 @@ class PaginationInfoSchema(BaseSchema):
|
|||||||
total_items: int
|
total_items: int
|
||||||
|
|
||||||
|
|
||||||
|
type SortDir = Literal["asc", "desc"]
|
||||||
|
|
||||||
|
|
||||||
|
class SortingSchema(BaseSchema):
|
||||||
|
field: Optional[str] = None
|
||||||
|
direction: Optional[SortDir] = None
|
||||||
|
|
||||||
|
|
||||||
class BaseEnumSchema(BaseSchema):
|
class BaseEnumSchema(BaseSchema):
|
||||||
id: int
|
id: int
|
||||||
name: str
|
name: str
|
||||||
|
|||||||
@ -12,6 +12,7 @@ class DealSchema(BaseSchema):
|
|||||||
name: str
|
name: str
|
||||||
lexorank: str
|
lexorank: str
|
||||||
status_id: int
|
status_id: int
|
||||||
|
board_id: int
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ from fastapi import HTTPException
|
|||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from repositories import DealRepository
|
from repositories import DealRepository
|
||||||
from schemas.base import PaginationSchema
|
from schemas.base import PaginationSchema, SortingSchema
|
||||||
from schemas.deal import *
|
from schemas.deal import *
|
||||||
|
|
||||||
|
|
||||||
@ -15,11 +15,15 @@ class DealService:
|
|||||||
async def get_deals(
|
async def get_deals(
|
||||||
self,
|
self,
|
||||||
pagination: PaginationSchema,
|
pagination: PaginationSchema,
|
||||||
board_id: Optional[int],
|
sorting: SortingSchema,
|
||||||
project_id: Optional[int],
|
*filters,
|
||||||
) -> GetDealsResponse:
|
) -> GetDealsResponse:
|
||||||
deals, total_items = await self.repository.get_all(
|
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
|
total_pages = 1
|
||||||
|
|||||||
21
utils/sorting.py
Normal file
21
utils/sorting.py
Normal 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
8
utils/strings.py
Normal 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()
|
||||||
Reference in New Issue
Block a user