fix: cards fetch optimization

This commit is contained in:
2025-04-15 10:59:41 +04:00
parent c08c2c04c4
commit 68f94cc9a4
3 changed files with 86 additions and 15 deletions

View File

@@ -5,7 +5,7 @@ from typing import Annotated
from fastapi import APIRouter, Depends, Response, UploadFile from fastapi import APIRouter, Depends, Response, UploadFile
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from backend.dependecies import SessionDependency, CurrentUserDependency from backend.dependecies import SessionDependency, CurrentUserDependency, PaginationDependency
from backend.session import get_session from backend.session import get_session
from generators.deal_pdf_generator.generator import DealTechSpecPdfGenerator from generators.deal_pdf_generator.generator import DealTechSpecPdfGenerator
from models import User from models import User
@@ -78,7 +78,7 @@ async def change_status(
return await CardsService(session).change_status_manual(request, user) return await CardsService(session).change_status_manual(request, user)
@card_router.get( @card_router.post(
'/summaries', '/summaries',
response_model=CardSummaryResponse, response_model=CardSummaryResponse,
operation_id='getCardSummaries', operation_id='getCardSummaries',
@@ -86,9 +86,10 @@ async def change_status(
) )
async def get_summary( async def get_summary(
session: Annotated[AsyncSession, Depends(get_session)], session: Annotated[AsyncSession, Depends(get_session)],
full: Optional[bool] request: GetCardSummariesRequest,
pagination: PaginationDependency,
): ):
return await CardsService(session).get_summary(full) return await CardsService(session).get_summary(request, pagination)
@card_router.post( @card_router.post(

View File

@@ -4,7 +4,7 @@ from typing import List, Optional, Union
from pydantic import constr from pydantic import constr
from schemas.attribute import CardAttributeSchema from schemas.attribute import CardAttributeSchema
from schemas.base import BaseSchema, OkMessageSchema from schemas.base import BaseSchema, OkMessageSchema, PaginationInfoSchema
from schemas.billing import CardBillRequestSchema from schemas.billing import CardBillRequestSchema
from schemas.board import BoardSchema from schemas.board import BoardSchema
from schemas.card_tag import CardTagSchema from schemas.card_tag import CardTagSchema
@@ -164,6 +164,18 @@ class CardChangeStatusRequest(BaseSchema):
new_status: int new_status: int
class GetCardSummariesRequest(BaseSchema):
full: bool
card_id: Optional[int | str] = None
card_name: Optional[str] = None
marketplace_key: Optional[str] = None
shipping_warehouse_id: Optional[int] = None
client_id: Optional[int] = None
project_id: Optional[int] = None
board_id: Optional[int] = None
status_id: Optional[int] = None
class CardCreateRequest(BaseSchema): class CardCreateRequest(BaseSchema):
name: str name: str
status_id: int status_id: int
@@ -345,6 +357,7 @@ class CardQuickCreateResponse(BaseSchema):
class CardSummaryResponse(BaseSchema): class CardSummaryResponse(BaseSchema):
summaries: List[CardSummary] summaries: List[CardSummary]
pagination_info: PaginationInfoSchema
class CardAddServicesResponse(BaseSchema): class CardAddServicesResponse(BaseSchema):

View File

@@ -1,14 +1,16 @@
from collections import defaultdict from collections import defaultdict
import lexorank import lexorank
import math
from fastapi import HTTPException from fastapi import HTTPException
from sqlalchemy import select, func, update, delete, insert, and_ from sqlalchemy import select, func, update, delete, insert, and_, Select
from sqlalchemy.orm import joinedload, selectinload from sqlalchemy.orm import joinedload, selectinload
from starlette import status from starlette import status
from card_attributes import CardAttributesCommandHandler from card_attributes import CardAttributesCommandHandler
from card_attributes.exceptions import CardAttributeException from card_attributes.exceptions import CardAttributeException
from models import * from models import *
from schemas.base import PaginationSchema
from schemas.card import * from schemas.card import *
from schemas.client import ClientDetailsSchema from schemas.client import ClientDetailsSchema
from services import card_group from services import card_group
@@ -179,7 +181,61 @@ class CardsService(BaseService):
.subquery() .subquery()
) )
async def get_summary(self, full: bool = False) -> CardSummaryResponse: @staticmethod
def _apply_pagination(query: Select, pagination: PaginationSchema) -> Select:
offset = (pagination.page - 1) * pagination.items_per_page
query = (
query
.offset(offset)
.limit(pagination.items_per_page)
)
return query
@staticmethod
def _apply_summary_filters(query: Select, request: GetCardSummariesRequest) -> Select:
if not request.full:
return query.where(Card.is_completed == False)
if request.card_id:
query = query.where(Card.id == request.card_id)
if request.card_name:
query = query.where(Card.name.like(f"%{request.card_name}%"))
if request.status_id:
query = query.where(Card.current_status_id == request.status_id)
elif request.board_id:
query = query.where(Card.board_id == request.board_id)
elif request.project_id:
query = (
query
.join(Board)
.where(Board.project_id == request.project_id)
)
if request.client_id:
query = query.where(Card.client_id == request.client_id)
if request.marketplace_key:
query = query.where(Card.base_marketplace_key == request.marketplace_key)
if request.shipping_warehouse_id:
query = query.where(Card.shipping_warehouse_id == request.shipping_warehouse_id)
query = query.order_by(Card.created_at.desc())
return query
async def _summaries_pagination_info(self, query: Select, pagination: PaginationSchema) -> PaginationInfoSchema:
if not pagination.items_per_page:
return PaginationInfoSchema(total_pages=0, total_items=0)
summaries = (await self.session.scalars(query)).all()
total_items = len(summaries)
return PaginationInfoSchema(
total_pages=math.ceil(total_items / pagination.items_per_page),
total_items=total_items,
)
async def get_summary(self, request: GetCardSummariesRequest, pagination: PaginationSchema) -> CardSummaryResponse:
price_subquery = self._get_price_subquery() price_subquery = self._get_price_subquery()
products_quantity_subquery = self._get_products_quantity_subquery() products_quantity_subquery = self._get_products_quantity_subquery()
q = ( q = (
@@ -210,13 +266,14 @@ class CardsService(BaseService):
Card.is_deleted == False, Card.is_deleted == False,
) )
) )
if not full:
q = q.where( q = self._apply_summary_filters(q, request)
Card.is_completed == False,
# Card.current_status != CardStatus.COMPLETED pagination_info = await self._summaries_pagination_info(q, pagination)
)
else: if pagination.page and pagination.items_per_page:
q = q.order_by(Card.created_at.desc()) q = CardsService._apply_pagination(q, pagination)
cards_query = await self.session.execute(q) cards_query = await self.session.execute(q)
summaries = [] summaries = []
for card, total_price, rank, products_count in cards_query.all(): for card, total_price, rank, products_count in cards_query.all():
@@ -247,7 +304,7 @@ class CardsService(BaseService):
attributes=attributes, attributes=attributes,
) )
) )
return CardSummaryResponse(summaries=summaries) return CardSummaryResponse(summaries=summaries, pagination_info=pagination_info)
async def get_all(self) -> CardGetAllResponse: async def get_all(self) -> CardGetAllResponse:
cards_stmt = ( cards_stmt = (