diff --git a/README.md b/README.md index 2f80603..8eec804 100644 --- a/README.md +++ b/README.md @@ -565,7 +565,6 @@ First, you may want to take a look at the project structure and understand what │ ├── api # Folder containing API-related logic. │ │ ├── __init__.py │ │ ├── dependencies.py # Defines dependencies for use across API endpoints. - │ │ ├── paginated.py # Utilities for API response pagination. │ │ │ │ │ └── v1 # Version 1 of the API. │ │ ├── __init__.py @@ -1020,10 +1019,10 @@ With the `get_multi` method we get a python `dict` with full suport for paginati } ``` -And in the endpoint, we can import from `app/api/paginated` the following functions and Pydantic Schema: +And in the endpoint, we can import from `fastcrud.paginated` the following functions and Pydantic Schema: ```python -from app.api.paginated import ( +from fastcrud.paginated import ( PaginatedListResponse, # What you'll use as a response_model to validate paginated_response, # Creates a paginated response based on the parameters compute_offset, # Calculate the offset for pagination ((page - 1) * items_per_page) diff --git a/pyproject.toml b/pyproject.toml index 807c854..65c81e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ redis = "^5.0.1" arq = "^0.25.0" gunicorn = "^21.2.0" bcrypt = "^4.1.1" -fastcrud = "^0.6.0" +fastcrud = "^0.7.0" [build-system] diff --git a/src/app/api/paginated.py b/src/app/api/paginated.py deleted file mode 100644 index 23b685b..0000000 --- a/src/app/api/paginated.py +++ /dev/null @@ -1,75 +0,0 @@ -from typing import Any, Generic, TypeVar - -from pydantic import BaseModel - -SchemaType = TypeVar("SchemaType", bound=BaseModel) - - -class ListResponse(BaseModel, Generic[SchemaType]): - data: list[SchemaType] - - -class PaginatedListResponse(ListResponse[SchemaType]): - total_count: int - has_more: bool - page: int | None = None - items_per_page: int | None = None - - -def paginated_response(crud_data: dict, page: int, items_per_page: int) -> dict[str, Any]: - """Create a paginated response based on the provided data and pagination parameters. - - Parameters - ---------- - crud_data : ListResponse[SchemaType] - Data to be paginated, including the list of items and total count. - page : int - Current page number. - items_per_page : int - Number of items per page. - - Returns - ------- - dict[str, Any] - A structured paginated response dict containing the list of items, total count, pagination flags, and numbers. - - Note - ---- - The function does not actually paginate the data but formats the response to indicate pagination metadata. - """ - return { - "data": crud_data["data"], - "total_count": crud_data["total_count"], - "has_more": (page * items_per_page) < crud_data["total_count"], - "page": page, - "items_per_page": items_per_page, - } - - -def compute_offset(page: int, items_per_page: int) -> int: - """Calculate the offset for pagination based on the given page number and items per page. - - The offset represents the starting point in a dataset for the items on a given page. - For example, if each page displays 10 items and you want to display page 3, the offset will be 20, - meaning the display should start with the 21st item. - - Parameters - ---------- - page : int - The current page number. Page numbers should start from 1. - items_per_page : int - The number of items to be displayed on each page. - - Returns - ------- - int - The calculated offset. - - Examples - -------- - >>> offset(1, 10) - 0 - >>> offset(3, 10) - 20 - """ - return (page - 1) * items_per_page diff --git a/src/app/api/v1/login.py b/src/app/api/v1/login.py index 388cff8..c38c8df 100644 --- a/src/app/api/v1/login.py +++ b/src/app/api/v1/login.py @@ -1,8 +1,7 @@ from datetime import timedelta from typing import Annotated -import fastapi -from fastapi import Depends, Request, Response +from fastapi import APIRouter, Depends, Request, Response from fastapi.security import OAuth2PasswordRequestForm from sqlalchemy.ext.asyncio import AsyncSession @@ -18,7 +17,7 @@ verify_token, ) -router = fastapi.APIRouter(tags=["login"]) +router = APIRouter(tags=["login"]) @router.post("/login", response_model=Token) diff --git a/src/app/api/v1/posts.py b/src/app/api/v1/posts.py index 842a770..e40b567 100644 --- a/src/app/api/v1/posts.py +++ b/src/app/api/v1/posts.py @@ -1,11 +1,10 @@ from typing import Annotated -import fastapi -from fastapi import Depends, Request +from fastapi import APIRouter, Depends, Request +from fastcrud.paginated import PaginatedListResponse, compute_offset, paginated_response from sqlalchemy.ext.asyncio import AsyncSession from ...api.dependencies import get_current_superuser, get_current_user -from ...api.paginated import PaginatedListResponse, compute_offset, paginated_response from ...core.db.database import async_get_db from ...core.exceptions.http_exceptions import ForbiddenException, NotFoundException from ...core.utils.cache import cache @@ -14,7 +13,7 @@ from ...schemas.post import PostCreate, PostCreateInternal, PostRead, PostUpdate from ...schemas.user import UserRead -router = fastapi.APIRouter(tags=["posts"]) +router = APIRouter(tags=["posts"]) @router.post("/{username}/post", response_model=PostRead, status_code=201) diff --git a/src/app/api/v1/rate_limits.py b/src/app/api/v1/rate_limits.py index c5f7563..ed7280a 100644 --- a/src/app/api/v1/rate_limits.py +++ b/src/app/api/v1/rate_limits.py @@ -1,18 +1,17 @@ from typing import Annotated -import fastapi -from fastapi import Depends, Request +from fastapi import APIRouter, Depends, Request +from fastcrud.paginated import PaginatedListResponse, compute_offset, paginated_response from sqlalchemy.ext.asyncio import AsyncSession from ...api.dependencies import get_current_superuser -from ...api.paginated import PaginatedListResponse, compute_offset, paginated_response from ...core.db.database import async_get_db from ...core.exceptions.http_exceptions import DuplicateValueException, NotFoundException, RateLimitException from ...crud.crud_rate_limit import crud_rate_limits from ...crud.crud_tier import crud_tiers from ...schemas.rate_limit import RateLimitCreate, RateLimitCreateInternal, RateLimitRead, RateLimitUpdate -router = fastapi.APIRouter(tags=["rate_limits"]) +router = APIRouter(tags=["rate_limits"]) @router.post("/tier/{tier_name}/rate_limit", dependencies=[Depends(get_current_superuser)], status_code=201) diff --git a/src/app/api/v1/tiers.py b/src/app/api/v1/tiers.py index d8aeee4..4c1f9b1 100644 --- a/src/app/api/v1/tiers.py +++ b/src/app/api/v1/tiers.py @@ -1,17 +1,16 @@ from typing import Annotated -import fastapi -from fastapi import Depends, Request +from fastapi import APIRouter, Depends, Request from sqlalchemy.ext.asyncio import AsyncSession +from fastcrud.paginated import PaginatedListResponse, compute_offset, paginated_response from ...api.dependencies import get_current_superuser -from ...api.paginated import PaginatedListResponse, compute_offset, paginated_response from ...core.db.database import async_get_db from ...core.exceptions.http_exceptions import DuplicateValueException, NotFoundException from ...crud.crud_tier import crud_tiers from ...schemas.tier import TierCreate, TierCreateInternal, TierRead, TierUpdate -router = fastapi.APIRouter(tags=["tiers"]) +router = APIRouter(tags=["tiers"]) @router.post("/tier", dependencies=[Depends(get_current_superuser)], status_code=201) diff --git a/src/app/api/v1/users.py b/src/app/api/v1/users.py index 422cb9c..9c5dfe0 100644 --- a/src/app/api/v1/users.py +++ b/src/app/api/v1/users.py @@ -1,11 +1,10 @@ from typing import Annotated, Any -import fastapi -from fastapi import Depends, Request +from fastapi import APIRouter, Depends, Request from sqlalchemy.ext.asyncio import AsyncSession +from fastcrud.paginated import PaginatedListResponse, compute_offset, paginated_response from ...api.dependencies import get_current_superuser, get_current_user -from ...api.paginated import PaginatedListResponse, compute_offset, paginated_response from ...core.db.database import async_get_db from ...core.exceptions.http_exceptions import DuplicateValueException, ForbiddenException, NotFoundException from ...core.security import blacklist_token, get_password_hash, oauth2_scheme @@ -16,7 +15,7 @@ from ...schemas.tier import TierRead from ...schemas.user import UserCreate, UserCreateInternal, UserRead, UserTierUpdate, UserUpdate -router = fastapi.APIRouter(tags=["users"]) +router = APIRouter(tags=["users"]) @router.post("/user", response_model=UserRead, status_code=201)