feat: Add pagination, search, and filter functionality to user retrieval endpoint
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
"""User repository."""
|
||||
|
||||
from typing import Any
|
||||
from enum import Enum
|
||||
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import selectinload
|
||||
from sqlmodel import select
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
@@ -14,6 +16,28 @@ from app.repositories.base import BaseRepository
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class UserSortField(str, Enum):
|
||||
"""User sort fields."""
|
||||
NAME = "name"
|
||||
EMAIL = "email"
|
||||
ROLE = "role"
|
||||
CREDITS = "credits"
|
||||
CREATED_AT = "created_at"
|
||||
|
||||
|
||||
class SortOrder(str, Enum):
|
||||
"""Sort order."""
|
||||
ASC = "asc"
|
||||
DESC = "desc"
|
||||
|
||||
|
||||
class UserStatus(str, Enum):
|
||||
"""User status filter."""
|
||||
ALL = "all"
|
||||
ACTIVE = "active"
|
||||
INACTIVE = "inactive"
|
||||
|
||||
|
||||
class UserRepository(BaseRepository[User]):
|
||||
"""Repository for user operations."""
|
||||
|
||||
@@ -40,6 +64,83 @@ class UserRepository(BaseRepository[User]):
|
||||
logger.exception("Failed to get all users with plan")
|
||||
raise
|
||||
|
||||
async def get_all_with_plan_paginated(
|
||||
self,
|
||||
page: int = 1,
|
||||
limit: int = 50,
|
||||
search: str | None = None,
|
||||
sort_by: UserSortField = UserSortField.NAME,
|
||||
sort_order: SortOrder = SortOrder.ASC,
|
||||
status_filter: UserStatus = UserStatus.ALL,
|
||||
) -> tuple[list[User], int]:
|
||||
"""Get all users with plan relationship loaded and return total count."""
|
||||
try:
|
||||
# Calculate offset
|
||||
offset = (page - 1) * limit
|
||||
|
||||
# Build base query
|
||||
base_query = select(User).options(selectinload(User.plan))
|
||||
count_query = select(func.count(User.id))
|
||||
|
||||
# Apply search filter
|
||||
if search and search.strip():
|
||||
search_pattern = f"%{search.strip().lower()}%"
|
||||
search_condition = (
|
||||
func.lower(User.name).like(search_pattern) |
|
||||
func.lower(User.email).like(search_pattern)
|
||||
)
|
||||
base_query = base_query.where(search_condition)
|
||||
count_query = count_query.where(search_condition)
|
||||
|
||||
# Apply status filter
|
||||
if status_filter == UserStatus.ACTIVE:
|
||||
base_query = base_query.where(User.is_active == True) # noqa: E712
|
||||
count_query = count_query.where(User.is_active == True) # noqa: E712
|
||||
elif status_filter == UserStatus.INACTIVE:
|
||||
base_query = base_query.where(User.is_active == False) # noqa: E712
|
||||
count_query = count_query.where(User.is_active == False) # noqa: E712
|
||||
|
||||
# Apply sorting
|
||||
if sort_by == UserSortField.EMAIL:
|
||||
if sort_order == SortOrder.DESC:
|
||||
base_query = base_query.order_by(User.email.desc())
|
||||
else:
|
||||
base_query = base_query.order_by(User.email.asc())
|
||||
elif sort_by == UserSortField.ROLE:
|
||||
if sort_order == SortOrder.DESC:
|
||||
base_query = base_query.order_by(User.role.desc())
|
||||
else:
|
||||
base_query = base_query.order_by(User.role.asc())
|
||||
elif sort_by == UserSortField.CREDITS:
|
||||
if sort_order == SortOrder.DESC:
|
||||
base_query = base_query.order_by(User.credits.desc())
|
||||
else:
|
||||
base_query = base_query.order_by(User.credits.asc())
|
||||
elif sort_by == UserSortField.CREATED_AT:
|
||||
if sort_order == SortOrder.DESC:
|
||||
base_query = base_query.order_by(User.created_at.desc())
|
||||
else:
|
||||
base_query = base_query.order_by(User.created_at.asc())
|
||||
else: # Default to name
|
||||
if sort_order == SortOrder.DESC:
|
||||
base_query = base_query.order_by(User.name.desc())
|
||||
else:
|
||||
base_query = base_query.order_by(User.name.asc())
|
||||
|
||||
# Get total count
|
||||
count_result = await self.session.exec(count_query)
|
||||
total_count = count_result.one()
|
||||
|
||||
# Apply pagination and get results
|
||||
paginated_query = base_query.limit(limit).offset(offset)
|
||||
result = await self.session.exec(paginated_query)
|
||||
users = list(result.all())
|
||||
|
||||
return users, total_count
|
||||
except Exception:
|
||||
logger.exception("Failed to get paginated users with plan")
|
||||
raise
|
||||
|
||||
async def get_by_id_with_plan(self, entity_id: int) -> User | None:
|
||||
"""Get a user by ID with plan relationship loaded."""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user