Fix: Add pagination to admin appointments endpoint
- Added pagination with page/per_page query params - Fixed N+1 query by using eager-loaded user relationship - Removed unused _get_user_email helper function - Updated frontend to handle paginated response - Regenerated API types
This commit is contained in:
parent
1cd60b4bbc
commit
77e7f98e1e
4 changed files with 70 additions and 28 deletions
|
|
@ -2,7 +2,7 @@
|
|||
from datetime import date, datetime, time, timedelta, timezone
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy import select, and_
|
||||
from sqlalchemy import select, and_, func
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
|
|
@ -14,6 +14,7 @@ from schemas import (
|
|||
AvailableSlotsResponse,
|
||||
BookingRequest,
|
||||
AppointmentResponse,
|
||||
PaginatedAppointments,
|
||||
)
|
||||
from shared_constants import SLOT_DURATION_MINUTES, MIN_ADVANCE_DAYS, MAX_ADVANCE_DAYS
|
||||
|
||||
|
|
@ -199,13 +200,6 @@ async def create_booking(
|
|||
appointments_router = APIRouter(prefix="/api/appointments", tags=["appointments"])
|
||||
|
||||
|
||||
async def _get_user_email(db: AsyncSession, user_id: int) -> str:
|
||||
"""Get user email by ID."""
|
||||
result = await db.execute(select(User.email).where(User.id == user_id))
|
||||
email = result.scalar_one_or_none()
|
||||
return email or "unknown"
|
||||
|
||||
|
||||
@appointments_router.get("", response_model=list[AppointmentResponse])
|
||||
async def get_my_appointments(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
|
|
@ -296,34 +290,52 @@ async def cancel_my_appointment(
|
|||
admin_appointments_router = APIRouter(prefix="/api/admin/appointments", tags=["admin-appointments"])
|
||||
|
||||
|
||||
@admin_appointments_router.get("", response_model=list[AppointmentResponse])
|
||||
@admin_appointments_router.get("", response_model=PaginatedAppointments)
|
||||
async def get_all_appointments(
|
||||
page: int = Query(1, ge=1),
|
||||
per_page: int = Query(10, ge=1, le=100),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_current_user: User = Depends(require_permission(Permission.VIEW_ALL_APPOINTMENTS)),
|
||||
) -> list[AppointmentResponse]:
|
||||
"""Get all appointments (admin only), sorted by date descending."""
|
||||
) -> PaginatedAppointments:
|
||||
"""Get all appointments (admin only), sorted by date descending with pagination."""
|
||||
# Get total count
|
||||
count_result = await db.execute(select(func.count(Appointment.id)))
|
||||
total = count_result.scalar() or 0
|
||||
total_pages = (total + per_page - 1) // per_page if total > 0 else 1
|
||||
|
||||
# Get paginated appointments (user relationship is eager-loaded via lazy="joined")
|
||||
offset = (page - 1) * per_page
|
||||
result = await db.execute(
|
||||
select(Appointment)
|
||||
.order_by(Appointment.slot_start.desc())
|
||||
.offset(offset)
|
||||
.limit(per_page)
|
||||
)
|
||||
appointments = result.scalars().all()
|
||||
|
||||
responses = []
|
||||
for apt in appointments:
|
||||
user_email = await _get_user_email(db, apt.user_id)
|
||||
responses.append(AppointmentResponse(
|
||||
# Build responses using the eager-loaded user relationship
|
||||
records = [
|
||||
AppointmentResponse(
|
||||
id=apt.id,
|
||||
user_id=apt.user_id,
|
||||
user_email=user_email,
|
||||
user_email=apt.user.email, # Uses eager-loaded relationship
|
||||
slot_start=apt.slot_start,
|
||||
slot_end=apt.slot_end,
|
||||
note=apt.note,
|
||||
status=apt.status.value,
|
||||
created_at=apt.created_at,
|
||||
cancelled_at=apt.cancelled_at,
|
||||
))
|
||||
)
|
||||
for apt in appointments
|
||||
]
|
||||
|
||||
return responses
|
||||
return PaginatedAppointments(
|
||||
records=records,
|
||||
total=total,
|
||||
page=page,
|
||||
per_page=per_page,
|
||||
total_pages=total_pages,
|
||||
)
|
||||
|
||||
|
||||
@admin_appointments_router.post("/{appointment_id}/cancel", response_model=AppointmentResponse)
|
||||
|
|
@ -363,12 +375,10 @@ async def admin_cancel_appointment(
|
|||
await db.commit()
|
||||
await db.refresh(appointment)
|
||||
|
||||
user_email = await _get_user_email(db, appointment.user_id)
|
||||
|
||||
return AppointmentResponse(
|
||||
id=appointment.id,
|
||||
user_id=appointment.user_id,
|
||||
user_email=user_email,
|
||||
user_email=appointment.user.email, # Uses eager-loaded relationship
|
||||
slot_start=appointment.slot_start,
|
||||
slot_end=appointment.slot_end,
|
||||
note=appointment.note,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue