Skip to main content

Module pagination

Module pagination 

Source
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:

  1. fetch limit + 1 rows from the database in page order,
  2. decode each row and apply an in-Rust visibility/status filter, then
  3. return at most limit items plus a next_cursor for 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 + 1 and testing rows.len() > limit is the sentinel; comparing the filtered items.len() against limit sends 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 None and 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_cursor from the rows already scanned for the page.
try_paginate_rows
Owns the full backend idiom: take the raw LIMIT limit + 1 result set, compute the has_more sentinel, drop the sentinel row, decode each remaining row with a fallible decode, then delegate to paginate_scanned.