diff --git a/backend/app/api/routes/items.py b/backend/app/api/routes/items.py index f0eb30e4ce..3169da671a 100644 --- a/backend/app/api/routes/items.py +++ b/backend/app/api/routes/items.py @@ -5,12 +5,19 @@ from sqlmodel import col, func, select from app.api.deps import CurrentUser, SessionDep -from app.models import Item, ItemCreate, ItemPublic, ItemsPublic, ItemUpdate, Message +from app.models import ( + Item, + ItemCreate, + ItemPublic, + ItemUpdate, + Message, + PaginatedResponse, +) router = APIRouter(prefix="/items", tags=["items"]) -@router.get("/", response_model=ItemsPublic) +@router.get("/", response_model=PaginatedResponse[ItemPublic]) def read_items( session: SessionDep, current_user: CurrentUser, skip: int = 0, limit: int = 100 ) -> Any: @@ -42,7 +49,7 @@ def read_items( items = session.exec(statement).all() items_public = [ItemPublic.model_validate(item) for item in items] - return ItemsPublic(data=items_public, count=count) + return PaginatedResponse(data=items_public, count=count) @router.get("/{id}", response_model=ItemPublic) diff --git a/backend/app/api/routes/users.py b/backend/app/api/routes/users.py index 1748f58484..b099b67659 100644 --- a/backend/app/api/routes/users.py +++ b/backend/app/api/routes/users.py @@ -15,12 +15,12 @@ from app.models import ( Item, Message, + PaginatedResponse, UpdatePassword, User, UserCreate, UserPublic, UserRegister, - UsersPublic, UserUpdate, UserUpdateMe, ) @@ -32,7 +32,7 @@ @router.get( "/", dependencies=[Depends(get_current_active_superuser)], - response_model=UsersPublic, + response_model=PaginatedResponse[UserPublic], ) def read_users(session: SessionDep, skip: int = 0, limit: int = 100) -> Any: """ @@ -48,7 +48,7 @@ def read_users(session: SessionDep, skip: int = 0, limit: int = 100) -> Any: users = session.exec(statement).all() users_public = [UserPublic.model_validate(user) for user in users] - return UsersPublic(data=users_public, count=count) + return PaginatedResponse(data=users_public, count=count) @router.post( diff --git a/backend/app/models.py b/backend/app/models.py index dcedf9a2f5..645b551c81 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -1,5 +1,6 @@ import uuid from datetime import UTC, datetime +from typing import Generic, TypeVar from pydantic import EmailStr from sqlalchemy import DateTime @@ -10,6 +11,14 @@ def get_datetime_utc() -> datetime: return datetime.now(UTC) +T = TypeVar("T") + + +class PaginatedResponse(SQLModel, Generic[T]): + data: list[T] + count: int + + # Shared properties class UserBase(SQLModel): email: EmailStr = Field(unique=True, index=True, max_length=255) @@ -65,11 +74,6 @@ class UserPublic(UserBase): created_at: datetime | None = None -class UsersPublic(SQLModel): - data: list[UserPublic] - count: int - - # Shared properties class ItemBase(SQLModel): title: str = Field(min_length=1, max_length=255) @@ -107,11 +111,6 @@ class ItemPublic(ItemBase): created_at: datetime | None = None -class ItemsPublic(SQLModel): - data: list[ItemPublic] - count: int - - # Generic message class Message(SQLModel): message: str diff --git a/frontend/src/client/schemas.gen.ts b/frontend/src/client/schemas.gen.ts index ea7b4f5cff..36fc70a946 100644 --- a/frontend/src/client/schemas.gen.ts +++ b/frontend/src/client/schemas.gen.ts @@ -177,25 +177,6 @@ export const ItemUpdateSchema = { title: 'ItemUpdate' } as const; -export const ItemsPublicSchema = { - properties: { - data: { - items: { - '$ref': '#/components/schemas/ItemPublic' - }, - type: 'array', - title: 'Data' - }, - count: { - type: 'integer', - title: 'Count' - } - }, - type: 'object', - required: ['data', 'count'], - title: 'ItemsPublic' -} as const; - export const MessageSchema = { properties: { message: { @@ -226,6 +207,40 @@ export const NewPasswordSchema = { title: 'NewPassword' } as const; +export const PaginatedResponse_ItemPublic_Schema = { + properties: { + data: { + items: {}, + type: 'array', + title: 'Data' + }, + count: { + type: 'integer', + title: 'Count' + } + }, + type: 'object', + required: ['data', 'count'], + title: 'PaginatedResponse[ItemPublic]' +} as const; + +export const PaginatedResponse_UserPublic_Schema = { + properties: { + data: { + items: {}, + type: 'array', + title: 'Data' + }, + count: { + type: 'integer', + title: 'Count' + } + }, + type: 'object', + required: ['data', 'count'], + title: 'PaginatedResponse[UserPublic]' +} as const; + export const PrivateUserCreateSchema = { properties: { email: { @@ -514,25 +529,6 @@ export const UserUpdateMeSchema = { title: 'UserUpdateMe' } as const; -export const UsersPublicSchema = { - properties: { - data: { - items: { - '$ref': '#/components/schemas/UserPublic' - }, - type: 'array', - title: 'Data' - }, - count: { - type: 'integer', - title: 'Count' - } - }, - type: 'object', - required: ['data', 'count'], - title: 'UsersPublic' -} as const; - export const ValidationErrorSchema = { properties: { loc: { diff --git a/frontend/src/client/sdk.gen.ts b/frontend/src/client/sdk.gen.ts index ba79e3f726..fab86c5ef0 100644 --- a/frontend/src/client/sdk.gen.ts +++ b/frontend/src/client/sdk.gen.ts @@ -12,7 +12,7 @@ export class ItemsService { * @param data The data for the request. * @param data.skip * @param data.limit - * @returns ItemsPublic Successful Response + * @returns PaginatedResponse_ItemPublic_ Successful Response * @throws ApiError */ public static readItems(data: ItemsReadItemsData = {}): CancelablePromise { @@ -242,7 +242,7 @@ export class UsersService { * @param data The data for the request. * @param data.skip * @param data.limit - * @returns UsersPublic Successful Response + * @returns PaginatedResponse_UserPublic_ Successful Response * @throws ApiError */ public static readUsers(data: UsersReadUsersData = {}): CancelablePromise { diff --git a/frontend/src/client/types.gen.ts b/frontend/src/client/types.gen.ts index 596b8fc476..e1f8daeb62 100644 --- a/frontend/src/client/types.gen.ts +++ b/frontend/src/client/types.gen.ts @@ -26,11 +26,6 @@ export type ItemPublic = { created_at?: (string | null); }; -export type ItemsPublic = { - data: Array; - count: number; -}; - export type ItemUpdate = { title?: (string | null); description?: (string | null); @@ -45,6 +40,16 @@ export type NewPassword = { new_password: string; }; +export type PaginatedResponse_ItemPublic_ = { + data: Array; + count: number; +}; + +export type PaginatedResponse_UserPublic_ = { + data: Array; + count: number; +}; + export type PrivateUserCreate = { email: string; password: string; @@ -85,11 +90,6 @@ export type UserRegister = { full_name?: (string | null); }; -export type UsersPublic = { - data: Array; - count: number; -}; - export type UserUpdate = { email?: (string | null); is_active?: (boolean | null); @@ -118,7 +118,7 @@ export type ItemsReadItemsData = { skip?: number; }; -export type ItemsReadItemsResponse = (ItemsPublic); +export type ItemsReadItemsResponse = (PaginatedResponse_ItemPublic_); export type ItemsCreateItemData = { requestBody: ItemCreate; @@ -182,7 +182,7 @@ export type UsersReadUsersData = { skip?: number; }; -export type UsersReadUsersResponse = (UsersPublic); +export type UsersReadUsersResponse = (PaginatedResponse_UserPublic_); export type UsersCreateUserData = { requestBody: UserCreate;