Files
feedBack/tests
331857ff2a feat(library): keyset cursor pagination + stable sort tiebreak (#636 item 3, stage 1) (#642)
Stage 1 of the virtualized-grid project (got-feedback/feedBack#636 item 3):
the data layer the DOM-recycling render window will build on, plus a latent
paging bug fixed on the way.

- Every grid sort now appends a unique `filename` tiebreak → a TOTAL order.
  Without it, rows with an equal sort key (e.g. two songs by the same artist)
  could be skipped or duplicated across OFFSET pages.
- query_page gains an opaque `after` keyset cursor: when supplied and the sort
  can keyset (artist[-desc], title[-desc], recent), the page is fetched with a
  WHERE-seek instead of OFFSET — O(page), independent of depth. The seek is
  NULL-aware (NULLs first in ASC / last in DESC) so it's EXACTLY OFFSET-
  equivalent; the legacy `dir=desc` shape is canonicalized so its cursor seeks
  the right direction. Unknown/compound sorts + bad cursors fall back to OFFSET.
- /api/library exposes `after` + `next_cursor`. Only the true local provider is
  handed a cursor (a collection may pin a different sort; remote don't keyset),
  so both page by OFFSET safely.
- Composite (artist NOCASE, filename) / (title NOCASE, filename) /
  (mtime, filename) indexes cover the order; `after` added to the optional
  provider kwargs so legacy providers drop it.

Codex-reviewed; 3 findings fixed (dir=desc canonicalization, NULL-key seek,
cursor only for the local provider).

Tests: tests/test_library_keyset.py (keyset==OFFSET parity for 5 sorts, stable
tiebreak on equal keys, dir=desc, NULL sort keys, bad-cursor + compound-sort
fallback).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 10:40:47 +02:00
..
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00