UX: paginate booking operations
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, Header, HTTPException, Query, Response
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy import func, or_, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_current_user, get_db
|
||||
@@ -10,6 +10,7 @@ from app.models.customer import Customer
|
||||
from app.models.vehicle import Vehicle
|
||||
from app.schemas import (
|
||||
BookingOut,
|
||||
BookingPageOut,
|
||||
CurrentUser,
|
||||
NextBookingRisk,
|
||||
RegisterReturnRequest,
|
||||
@@ -35,13 +36,16 @@ def _to_out(booking: Booking, customer: Customer, vehicle: Vehicle) -> BookingOu
|
||||
)
|
||||
|
||||
|
||||
@router.get("", response_model=list[BookingOut])
|
||||
@router.get("", response_model=list[BookingOut] | BookingPageOut)
|
||||
def list_bookings(
|
||||
status: str | None = Query(default=None),
|
||||
vehicle_ref: str | None = Query(default=None),
|
||||
query: str | None = Query(default=None, min_length=1, max_length=100),
|
||||
page: int | None = Query(default=None, ge=1),
|
||||
page_size: int = Query(default=25, ge=1, le=25),
|
||||
db: Session = Depends(get_db),
|
||||
_user: CurrentUser = Depends(get_current_user),
|
||||
) -> list[BookingOut]:
|
||||
) -> list[BookingOut] | BookingPageOut:
|
||||
stmt = select(Booking).order_by(Booking.starts_at.desc())
|
||||
if status:
|
||||
stmt = stmt.where(Booking.status == status)
|
||||
@@ -50,10 +54,38 @@ def list_bookings(
|
||||
if vehicle is None:
|
||||
return []
|
||||
stmt = stmt.where(Booking.vehicle_id == vehicle.id)
|
||||
bookings = db.scalars(stmt).all()
|
||||
if query:
|
||||
term = f"%{query.strip()}%"
|
||||
stmt = (
|
||||
stmt.join(Customer, Booking.customer_id == Customer.id)
|
||||
.join(Vehicle, Booking.vehicle_id == Vehicle.id)
|
||||
.where(
|
||||
or_(
|
||||
Booking.public_ref.ilike(term),
|
||||
Customer.first_name.ilike(term),
|
||||
Customer.last_name.ilike(term),
|
||||
Vehicle.public_ref.ilike(term),
|
||||
)
|
||||
)
|
||||
)
|
||||
total = db.scalar(select(func.count()).select_from(stmt.subquery())) or 0
|
||||
page_number = page or 1
|
||||
bookings = db.scalars(
|
||||
stmt if page is None else stmt.offset((page_number - 1) * page_size).limit(page_size)
|
||||
).all()
|
||||
customers = {c.id: c for c in db.scalars(select(Customer)).all()}
|
||||
vehicles = {v.id: v for v in db.scalars(select(Vehicle)).all()}
|
||||
return [_to_out(b, customers[b.customer_id], vehicles[b.vehicle_id]) for b in bookings]
|
||||
items = [_to_out(b, customers[b.customer_id], vehicles[b.vehicle_id]) for b in bookings]
|
||||
if page is None:
|
||||
return items
|
||||
total_pages = max(1, (total + page_size - 1) // page_size)
|
||||
return BookingPageOut(
|
||||
items=items,
|
||||
page=min(page_number, total_pages),
|
||||
page_size=page_size,
|
||||
total=total,
|
||||
total_pages=total_pages,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{public_ref}", response_model=BookingOut)
|
||||
|
||||
Reference in New Issue
Block a user