Expand description
Cursor-pagination helpers for registry store backends.
Registries paginate list / search with an opaque keyset cursor
(RFC-ACDP-0002). The standard backend idiom is:
- fetch
limit + 1rows from the database in page order, - decode each row and apply an in-Rust visibility/status filter, then
- return at most
limititems plus anext_cursorfor the page that follows.
Two correctness invariants in that idiom are easy to get wrong, and every backend re-implements them:
- The “more rows?” signal must come from the raw DB row count, not
the post-filter item count. Fetching
limit + 1and testingrows.len() > limitis the sentinel; comparing the filtereditems.len()againstlimitsends clients to a phantom empty page whenever the in-Rust filter drops a row on the final page. - The next cursor must anchor on the last scanned row, not the
last kept item. If a whole page is filtered out, anchoring on the
last kept item yields
Noneand terminates pagination early even though the database had more matching rows; anchoring on the last scanned row keeps the walk going.
paginate_scanned and try_paginate_rows centralize both
invariants (and their regression tests) so a backend supplies only the
per-row decode, the keep-filter, and the cursor extractor. The cursor
encoding stays with the backend — this module is generic over the
cursor type and never inspects it.
Structs§
- Paginated
- A page of results plus the opaque cursor for the page that follows.
Functions§
- paginate_
scanned - Apply a page’s keep-filter and derive its
next_cursorfrom the rows already scanned for the page. - try_
paginate_ rows - Owns the full backend idiom: take the raw
LIMIT limit + 1result set, compute thehas_moresentinel, drop the sentinel row, decode each remaining row with a fallibledecode, then delegate topaginate_scanned.