123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- import logging
- from typing import TypeVar, Any, Optional, Generic, List, Sequence
- from fastapi import Query
- from fastapi_pagination.bases import AbstractPage, AbstractParams, CursorRawParams
- from fastapi_pagination.cursor import encode_cursor
- from fastapi_pagination.ext.sqlmodel import paginate
- from fastapi_pagination.types import Cursor
- from fastapi_pagination.utils import verify_params, create_pydantic_model
- from sqlmodel import asc, desc
- from sqlalchemy.ext.asyncio import AsyncSession
- from app.models.base_model import BaseModel
- ModelType = TypeVar("ModelType", bound=BaseModel)
- class CursorParams(BaseModel, AbstractParams):
- limit: int = Query(20, ge=1, le=100, description="Page offset")
- order: str = Query(default="desc", description="Sort order")
- after: Optional[str] = Query(None, description="Page after")
- before: Optional[str] = Query(None, description="Page before")
- def to_raw_params(self) -> CursorRawParams:
- return CursorRawParams(cursor=None, size=self.limit, include_total=True)
- class CommonPage(AbstractPage[ModelType], Generic[ModelType]):
- __params_type__ = CursorParams
- object: str = "list"
- data: List[ModelType] = []
- first_id: Optional[str] = ""
- last_id: Optional[str] = ""
- has_more: bool = False
- @classmethod
- def create(
- cls,
- items: Sequence[ModelType],
- params: CursorParams,
- *,
- current: Optional[Cursor] = None,
- current_backwards: Optional[Cursor] = None,
- next_: Optional[Cursor] = None,
- previous: Optional[Cursor] = None,
- **kwargs: Any,
- ) -> AbstractPage[ModelType]:
- next_page = encode_cursor(next_)
- return create_pydantic_model(
- CommonPage,
- next_page=next_page,
- first_id=items[0].id if items else None,
- last_id=items[len(items) - 1].id if items else None,
- has_more=False if next_page is None else True,
- data=list(items),
- )
- async def cursor_page(query: Any, db: AsyncSession) -> CommonPage[ModelType]:
- params, _ = verify_params(None, "cursor")
- model = query._propagate_attrs["plugin_subject"].class_
- logging.debug(
- f"Page model={model}, sort={params.order}, filter_parameters=before:{params.before}, after:{params.after}",
- )
- if params.before is not None:
- if params.order.upper() == "DESC":
- query = query.where(model.id > params.before)
- else:
- query = query.where(model.id < params.before)
- if params.after is not None:
- if params.order.upper() == "DESC":
- query = query.where(model.id < params.after)
- else:
- query = query.where(model.id > params.after)
- if params.order.upper() == "DESC":
- query = query.order_by(desc(model.__dict__["created_at"]))
- else:
- query = query.order_by(asc(model.__dict__["created_at"]))
- return await paginate(db, query)
|