75 lines
2.6 KiB
Python
75 lines
2.6 KiB
Python
from fastapi import APIRouter, Depends, Query
|
|
from sqlalchemy import and_, or_, select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from ..cursors import decode, encode
|
|
from ..db import get_session
|
|
from ..models import Check
|
|
from ..schemas import ID_PATTERN, ChecksPage, CheckState
|
|
from ..timeutil import to_utc
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/checks", response_model=ChecksPage)
|
|
async def list_checks(
|
|
agent_id: str | None = Query(default=None, max_length=128, pattern=ID_PATTERN),
|
|
cursor: str | None = Query(default=None, max_length=512),
|
|
back: bool = Query(default=False),
|
|
limit: int = Query(default=100, ge=1, le=500),
|
|
session: AsyncSession = Depends(get_session),
|
|
) -> ChecksPage:
|
|
# PH-review: bidirectional cursor. Natural sort is ASC (agent_id, check_id).
|
|
if back:
|
|
stmt = select(Check).order_by(Check.agent_id.desc(), Check.check_id.desc())
|
|
else:
|
|
stmt = select(Check).order_by(Check.agent_id, Check.check_id)
|
|
if agent_id is not None:
|
|
stmt = stmt.where(Check.agent_id == agent_id)
|
|
if cursor is not None:
|
|
last_agent, last_check = decode(cursor, 2)
|
|
if back:
|
|
stmt = stmt.where(
|
|
or_(
|
|
Check.agent_id < last_agent,
|
|
and_(Check.agent_id == last_agent, Check.check_id < last_check),
|
|
)
|
|
)
|
|
else:
|
|
stmt = stmt.where(
|
|
or_(
|
|
Check.agent_id > last_agent,
|
|
and_(Check.agent_id == last_agent, Check.check_id > last_check),
|
|
)
|
|
)
|
|
rows = (await session.execute(stmt.limit(limit + 1))).scalars().all()
|
|
has_more = len(rows) > limit
|
|
rows = rows[:limit]
|
|
if back:
|
|
rows = list(reversed(rows))
|
|
next_cursor: str | None = None
|
|
prev_cursor: str | None = None
|
|
if rows:
|
|
if back:
|
|
next_cursor = encode(rows[-1].agent_id, rows[-1].check_id)
|
|
if has_more:
|
|
prev_cursor = encode(rows[0].agent_id, rows[0].check_id)
|
|
else:
|
|
if has_more:
|
|
next_cursor = encode(rows[-1].agent_id, rows[-1].check_id)
|
|
if cursor is not None:
|
|
prev_cursor = encode(rows[0].agent_id, rows[0].check_id)
|
|
items = [
|
|
CheckState(
|
|
agent_id=r.agent_id,
|
|
check_id=r.check_id,
|
|
status=r.status,
|
|
last_observed_at=to_utc(r.last_observed_at),
|
|
exit_code=r.exit_code,
|
|
incident_key=r.incident_key,
|
|
summary=r.summary,
|
|
)
|
|
for r in rows
|
|
]
|
|
return ChecksPage(items=items, next_cursor=next_cursor, prev_cursor=prev_cursor)
|