Interview question
Implement stable keyset pagination with async SQLAlchemy
Builds descending keyset pagination with a unique tie-breaker, opaque cursor, limit-plus-one query, and stable next page.
TL;DR
Builds descending keyset pagination with a unique tie-breaker, opaque cursor, limit-plus-one query, and stable next page.
SQLAlchemy 2.x select, tuple comparison, deterministic ordering, cursor design, async execution, and pagination stability.
Practice the problem like a real interview: restate, reason, implement, and test.
List orders newest first using (created_at, id) as the keyset. Accept an opaque cursor containing the last visible pair, return at most limit rows, and return a next cursor only when another row exists. Rows inserted before the cursor must not shift or duplicate the next page.
Next in Python Backend Practical Labs: SQLAlchemy version conflict
order by created_at DESC, id DESC
next page where (created_at,id) < (:time,:id)
fetch limit+1; expose limit rows
limit + 1 to determine whether another page exists.select(Order) with descending timestamp and ID ordering.limit rows.from sqlalchemy import select, tuple_
async def order_page(session, limit: int, cursor: str | None):
if not 1 <= limit <= 100:
raise ValueError("invalid limit")
stmt = select(Order).order_by(Order.created_at.desc(), Order.id.desc())
if cursor:
created_at, order_id = decode_cursor(cursor)
stmt = stmt.where(
tuple_(Order.created_at, Order.id) < tuple_(created_at, order_id)
)
rows = list((await session.scalars(stmt.limit(limit + 1))).all())
visible = rows[:limit]
next_cursor = None
if len(rows) > limit and visible:
last = visible[-1]
next_cursor = encode_cursor(last.created_at, last.id)
return visible, next_cursor
With a matching composite index, page lookup is O(log n + page size). Memory remains O(page size).
> with descending order walks in the wrong direction.Spot a weak answer, missing edge case, or clearer explanation? Send it in.
Say thanks with a standalone, one-time $5 contribution. No account required.