Repository navigation
feat(results): page query results from the stats strip (#816) - #1014
Merged
Merged
Conversation
The starter query the object tree generated carried its own row bound, so applyQueryLimit returned it untouched and dropped the offset silently. Two defects hid each other: the control was missing, and because it was missing nobody ever triggered the dropped offset behind it. The preview cap now leaves the SQL text and travels as the limit execution option, so a user written LIMIT n means exactly one thing, a hard bound we do not page past. hasMore additionally requires prepared.wasLimited, because we can only offer page two of a bound this layer applied. supportsResultPagination is declared by every provider from its own prepareQuery; the search provider declares this.product.acceptsOffsetClause, because one class serves two type-ids that differ exactly there. No chrome below the grid: LoadMoreFooter is gone and the former "(more available)" text in the stats strip is the control. Closes #816 Co-authored-by: Lazzaro Davide <211658270+DevvoLazza@users.noreply.github.com> Co-authored-by: Dharshini_RS <231443604+Dharshini-RS03@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Member
Author
|
Hi @Dharshini-RS03 and @DevvoLazza, |
This was referenced Sep 20, 2026
The embedded adapter had no supersession check. A Load More in flight would resolve after a Run had replaced the grid, append its stale page on top of the new rows and rewrite resultQuery, so the tab held rows from two statements while naming one. That is #881's class, in the copy the standalone hook already guards. The control never rendered before, so the window was unreachable until this branch. The adapter cannot abort, because the host owns the fetch behind onQueryExecute, so ownership is the mechanism: a per-tab map of the last run to claim each tab, checked on the success arm and the failure arm of all four paths. The failure arm matters as much, since a superseded page must not clear the newer run's flags or raise a toast nobody is waiting for. Every claim write now takes over both flags in one write. Leaving one behind stranded the other: a Run that disowned a page could not clear the isLoadingMore that page had set, and the control reads disabled={isLoadingMore}. Cancel skipped a paging tab for the same reason, so its predicate widened to match. Closes #816 Co-authored-by: Lazzaro Davide <211658270+DevvoLazza@users.noreply.github.com> Co-authored-by: Dharshini_RS <231443604+Dharshini-RS03@users.noreply.github.com>
) Merging main into this branch resolved the `object-route.ts` conflict by deleting the line number from eight of the nine citations in the edit-affordance docblock and leaving the ninth stale, plus a stray blank line inside the block. `tests/unit/lib/api/object-route-edit.test.ts` is the guard for exactly that and went red on the merge commit, before this branch's own second commit existed. Numbers recomputed from each anchor at this tree, not carried over: #985 moved the provider sites this docblock points at. Co-authored-by: Lazzaro Davide <211658270+DevvoLazza@users.noreply.github.com> Co-authored-by: Dharshini_RS <231443604+Dharshini-RS03@users.noreply.github.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.



Closes #816. This supersedes #933 and #942, and both of their authors are co-authors on the commit.
Two people built this independently while I was slow to settle who had it, which is my fault and not theirs. Rather than pick a winner I took the design in #816 plus the seven review items on #942 and built it once, keeping what each of them got right. @DevvoLazza and @Dharshini-RS03 are credited in the commit and the squash will carry both trailers.
What was wrong
The starter query the object tree generated carried its own row bound, so
applyQueryLimitreturned it untouched and dropped the offset silently.prepareQuerystill reportedlimit: 500while the real bound in the statement was 50, sohasMorecomputed50 === 500and the control never rendered. Two defects hid each other: the control was missing, and because it was missing nobody ever triggered the dropped offset behind it.What changed
The preview cap leaves the SQL text and travels as the
limitexecution option, so a user writtenLIMIT nmeans exactly one thing, a hard bound we do not page past.hasMoreadditionally requiresprepared.wasLimited, because we can only offer page two of a bound this layer applied.supportsResultPaginationis declared by every provider in the repo, each value read from that provider's ownprepareQueryrather than from a list. Twelve apply the offset. Cassandra and Elasticsearch refuse it, MongoDB and Redis pin it to zero, and LibreDB never setswasLimited. The search provider declaresthis.product.acceptsOffsetClause, because one class serves two type-ids that differ exactly there: a literaltruewould offer a control that makes Elasticsearch throw, and a literalfalsewould hide one OpenSearch can serve.No chrome below the grid.
LoadMoreFooterand its render site are gone. The former(more available)text in the stats strip is the control, reading50 rows - load 50 morein the sametext-xs font-monolanguage as its neighbours. The grid keeps its height whether or not another page exists, which the old footer did not.An unordered query still paginates, and the grid says once, beside the auto-limited badge, that order across pages is not guaranteed. We do not inject an
ORDER BYto avoid that.Beyond the two documents
Three things neither the design nor the review named, found while mapping the code:
src/app/api/db/transaction/route.tscomputed the samehasMoreand needed the same conjunct.src/lib/export/scope.tsreadshasMoreto decide export truncation, so the export dialog was telling Cassandra and Elasticsearch users to load rows no control can load. The grid's three-way decision now lives in one place,pageOfferFor, and both the grid and the export scope read it.fields: []and the columns went with it. Found by driving the real UI, not by reading.Verification
All gates run separately, each with its own exit code: format, lint, typecheck, knip, chart:check, channels:showcase:check, readme:check, security:check, test, build, build:lib, attw, test:coverage and coverage:check. 566 test files, 18694 passing, coverage 59259/59259 lines.
Not measured here: the twelve
helm-chart-*test files, which need a built chart dependency, and the Go launcher checks. Every provider value was measured throughprepareQueryagainst unconnected configurations rather than live engines, apart from PostgreSQL and SQLite, which were driven in a browser.