fix: honour keyset cursor in paginated live queries - #22
Merged
Merged
Conversation
Make cursor-based pagination correct under Supabase Realtime: - Skip `offset` when a `cursor` is present so keyset requests no longer re-skip rows the cursor already moved past. - Issue a second, unlimited `whereCurrent` request for boundary ties so rows sharing the boundary `orderBy` value are not dropped. - Fold `whereFrom`/`offset` into the query key so distinct windows of one subset no longer collide and delete each other's rows. - Raise the `@tanstack/db` floor to `>=0.5.12` (first version exposing the cursor `whereFrom`/`whereCurrent` expressions). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address three review defects while keeping PR scope (cursor handling + keys): - Render cursor whereFrom/whereCurrent through the adapter's own toPostgrestParams (strict) instead of extractSimpleComparisons, which threw on the composite `or(...)` cursors core emits for multi-column orderBy and serialised Date boundaries with Date.toString() (unparseable by Postgres). - Never let subsetOptionsToQueryKey throw: on an un-pushable cursor, fall back to a deterministic JSON discriminator so distinct windows keep distinct keys. - Treat `limit: 0` as a distinct subset (guard on `!== undefined`) so an empty limit-0 result cannot take over and delete the unlimited query's rows. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
saltcod
approved these changes
Sep 16, 2026
Add live-query window-controller tests that drive the keyset cursor path through the adapter against a mocked PostgREST: single page, window growth (keyset `gt`, no offset), and the boundary tie class (`whereCurrent`). Also document, at the `supabaseQueryFn` tie request, why the unlimited `whereCurrent` read must not be dropped even though core's ordered-source loader usually pre-probes the same boundary tie class. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ivasilov
force-pushed
the
ivasilov/analyze-db-pr-1824
branch
from
September 16, 2026 20:39
547587f to
576bd23
Compare
@tanstack/db 0.9's ordered-source loader issues extra reads around an ordered+limited query (a boundary probe to settle hasNextPage, or a full-source load when the order isn't keyset-expressible), so the exact single-URL assertions no longer hold. Mark these five as todo pending a decision on how to assert query generation under the new loader behaviour. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makes cursor-based pagination correct under Supabase Realtime by fixing three defects in how the adapter handled core's keyset hints.
loadSubsetOptionsToSearchnow skipsoffsetwhenever acursoris present, so keyset requests no longer re-skip rows the cursor already moved past.supabaseQueryFnissues a second, unlimitedwhereCurrentrequest in parallel for boundary ties, so rows sharing the boundaryorderByvalue are no longer dropped.subsetOptionsToQueryKeynow foldswhereFrom/offsetinto the cache key so distinct windows of one subset no longer collide and delete each other's rows (the key still starts with[tableName]so realtime prefix-matching is unaffected).Cursors are rendered through the adapter's own
toPostgrestParams(strict), which handles the compositeor(...)cursors core emits for multi-columnorderByand serialises Date boundaries as ISO 8601; the query-key function never throws (it falls back to a deterministic discriminator on an un-pushable cursor); andlimit: 0is treated as a distinct subset so an empty result cannot take over and delete the unlimited query's rows.The
@tanstack/dbdependency is bumped to the 0.9 line, with the range set to>=0.6 <1.0(0.5.12 was the first version exposing the cursorwhereFrom/whereCurrentexpressions; 0.6 is the practical floor).Tests. Adds end-to-end coverage of windowed (infinite) pagination via
createLiveQueryWindowController: a single page, window growth by keyset cursor (no offset), and the boundary tie class (whereCurrent). Note that on 0.9 the ordered-source loader issues extra reads around an ordered+limited query — a boundary probe (col=eq.<last>) to settlehasNextPage, or a full-source load when the order isn't keyset-expressible (e.g. a string column under the defaultlocalesort) — so five exact single-URL query-generation tests no longer hold and are markedtest.todopending a decision on how to assert generation under the new loader behaviour.Note
The unlimited
whereCurrenttie request must be routed through PR #17's page-size loop once that PR lands — a tie class larger than the API row cap would otherwise be truncated. That change belongs to #17.🤖 Generated with Claude Code