Skip to content

feat(vue-db): add infinite query binding - #1724

Open
tannerlinsley wants to merge 2 commits into
mainfrom
taren/vue-infinite-query-controller
Open

feat(vue-db): add infinite query binding#1724
tannerlinsley wants to merge 2 commits into
mainfrom
taren/vue-infinite-query-controller

Conversation

@tannerlinsley

@tannerlinsley tannerlinsley commented Aug 13, 2026

Copy link
Copy Markdown
Member

Changes

  • add useLiveInfiniteQuery to @tanstack/vue-db
  • delegate pagination, window ownership, loading, and error state to the shared live-query window controller
  • support reactive dependencies and reactive pre-created collections
  • add runtime and type coverage for paging, live rows, boundary cases, dependency resets, and collection swaps

This replaces the duplicated pagination implementation in #1513 while preserving its API intent. Miguel Romero Karam is credited as a co-author on the commit.

Validation

  • pnpm --filter @tanstack/vue-db test (68 tests, no type errors)
  • pnpm --filter @tanstack/vue-db build
  • ESLint, Prettier, and git diff --check

Checklist

  • I have tested this code locally with pnpm --filter @tanstack/vue-db test.

Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • New Features
    • Added useLiveInfiniteQuery for reactive infinite pagination with live data.
    • Supports query builders and existing live collections.
    • Provides page data, query status, errors, pagination controls, and automatic updates as data changes.
    • Resets pagination when dependencies or collections change.
  • Bug Fixes
    • Added handling for unsupported window configurations, pagination boundaries, and concurrent page requests.

Co-authored-by: miguelrk <miguelromerokaram@gmail.com>
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ffd5317a-8718-4585-9a2e-f2be53f9e548

📥 Commits

Reviewing files that changed from the base of the PR and between 5190891 and 6a31620.

📒 Files selected for processing (2)
  • packages/vue-db/src/useLiveInfiniteQuery.ts
  • packages/vue-db/tests/useLiveInfiniteQuery.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/vue-db/tests/useLiveInfiniteQuery.test.ts
  • packages/vue-db/src/useLiveInfiniteQuery.ts

📝 Walkthrough

Walkthrough

Added the Vue useLiveInfiniteQuery composable. It supports live-query collections and query builders, reactive pagination, window controllers, live updates, dependency resets, collection replacement, public exports, and type and runtime tests.

Changes

Vue live infinite query

Layer / File(s) Summary
API and input contracts
packages/vue-db/src/useLiveInfiniteQuery.ts, packages/vue-db/src/index.ts
Defines configuration and return types, resolves collection and query-builder inputs, and re-exports useLiveInfiniteQuery.
Window controller and reactive state
packages/vue-db/src/useLiveInfiniteQuery.ts
Creates bounded live-query windows, validates collection windows, subscribes to snapshots, disposes reactive resources, and exposes pagination state.
Behavior and type validation
packages/vue-db/tests/useLiveInfiniteQuery.test.ts, packages/vue-db/tests/useLiveInfiniteQuery.test-d.ts, .changeset/curly-ravens-listen.md
Tests pagination, live updates, dependency resets, edge cases, concurrent requests, collection replacement, inferred types, and the package changeset.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Mergeability Score: 🟡 Moderate · up to 6a316

The new infinite-query binding changes pagination and loading behavior, but required regression coverage for no-op promises, nullish inputs, and concurrent fetches is still missing; merge should wait for those tests or explicit owner acceptance.

Sequence Diagram(s)

sequenceDiagram
  participant VueComponent
  participant useLiveInfiniteQuery
  participant LiveQueryCollection
  participant WindowController
  VueComponent->>useLiveInfiniteQuery: provide query input and reactive dependencies
  useLiveInfiniteQuery->>LiveQueryCollection: resolve or create bounded collection
  useLiveInfiniteQuery->>WindowController: create controller
  WindowController-->>useLiveInfiniteQuery: publish snapshots
  useLiveInfiniteQuery-->>VueComponent: expose reactive pages and state
  VueComponent->>useLiveInfiniteQuery: call fetchNextPage()
  useLiveInfiniteQuery->>WindowController: fetch next page
Loading

Possibly related PRs

  • TanStack/db#1642: Introduces shared live-query observer and window infrastructure used by this Vue binding.
  • TanStack/db#1675: Introduces the shared createLiveQueryWindowController used by this implementation.
  • TanStack/db#1723: Adds a framework-specific useLiveInfiniteQuery binding over the shared live-query window controller.

Suggested reviewers: kyleamathews

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely identifies the addition of the infinite query binding to vue-db.
Description check ✅ Passed The description explains the changes, documents validation, confirms testing, and records the generated changeset.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch taren/vue-infinite-query-controller

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Aug 13, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-db

npm i https://pkg.pr.new/@tanstack/angular-db@1724

@tanstack/browser-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/browser-db-sqlite-persistence@1724

@tanstack/capacitor-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/capacitor-db-sqlite-persistence@1724

@tanstack/cloudflare-durable-objects-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/cloudflare-durable-objects-db-sqlite-persistence@1724

@tanstack/db

npm i https://pkg.pr.new/@tanstack/db@1724

@tanstack/db-ivm

npm i https://pkg.pr.new/@tanstack/db-ivm@1724

@tanstack/db-sqlite-persistence-core

npm i https://pkg.pr.new/@tanstack/db-sqlite-persistence-core@1724

@tanstack/electric-db-collection

npm i https://pkg.pr.new/@tanstack/electric-db-collection@1724

@tanstack/electron-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/electron-db-sqlite-persistence@1724

@tanstack/expo-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/expo-db-sqlite-persistence@1724

@tanstack/node-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/node-db-sqlite-persistence@1724

@tanstack/offline-transactions

npm i https://pkg.pr.new/@tanstack/offline-transactions@1724

@tanstack/powersync-db-collection

npm i https://pkg.pr.new/@tanstack/powersync-db-collection@1724

@tanstack/query-db-collection

npm i https://pkg.pr.new/@tanstack/query-db-collection@1724

@tanstack/react-db

npm i https://pkg.pr.new/@tanstack/react-db@1724

@tanstack/react-native-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/react-native-db-sqlite-persistence@1724

@tanstack/rxdb-db-collection

npm i https://pkg.pr.new/@tanstack/rxdb-db-collection@1724

@tanstack/solid-db

npm i https://pkg.pr.new/@tanstack/solid-db@1724

@tanstack/svelte-db

npm i https://pkg.pr.new/@tanstack/svelte-db@1724

@tanstack/tauri-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/tauri-db-sqlite-persistence@1724

@tanstack/trailbase-db-collection

npm i https://pkg.pr.new/@tanstack/trailbase-db-collection@1724

@tanstack/vue-db

npm i https://pkg.pr.new/@tanstack/vue-db@1724

commit: 6a31620

@github-actions

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 132 kB

ℹ️ View Unchanged
Filename Size
packages/db/dist/esm/collection/change-events.js 1.44 kB
packages/db/dist/esm/collection/changes.js 1.51 kB
packages/db/dist/esm/collection/cleanup-queue.js 810 B
packages/db/dist/esm/collection/events.js 434 B
packages/db/dist/esm/collection/index.js 3.86 kB
packages/db/dist/esm/collection/indexes.js 1.99 kB
packages/db/dist/esm/collection/lifecycle.js 1.7 kB
packages/db/dist/esm/collection/mutations.js 2.47 kB
packages/db/dist/esm/collection/state.js 5.51 kB
packages/db/dist/esm/collection/subscription.js 3.77 kB
packages/db/dist/esm/collection/sync.js 3.05 kB
packages/db/dist/esm/collection/transaction-metadata.js 144 B
packages/db/dist/esm/deferred.js 207 B
packages/db/dist/esm/errors.js 5.16 kB
packages/db/dist/esm/event-emitter.js 748 B
packages/db/dist/esm/index.js 3.26 kB
packages/db/dist/esm/indexes/auto-index.js 829 B
packages/db/dist/esm/indexes/base-index.js 784 B
packages/db/dist/esm/indexes/basic-index.js 2.17 kB
packages/db/dist/esm/indexes/btree-index.js 2.29 kB
packages/db/dist/esm/indexes/index-registry.js 820 B
packages/db/dist/esm/indexes/reverse-index.js 557 B
packages/db/dist/esm/live-query-adapter.js 318 B
packages/db/dist/esm/live-query-observer.js 2.35 kB
packages/db/dist/esm/live-query-window-controller.js 3.04 kB
packages/db/dist/esm/local-only.js 916 B
packages/db/dist/esm/local-storage.js 2.12 kB
packages/db/dist/esm/optimistic-action.js 359 B
packages/db/dist/esm/paced-mutations.js 496 B
packages/db/dist/esm/proxy.js 3.75 kB
packages/db/dist/esm/query/builder/functions.js 1.47 kB
packages/db/dist/esm/query/builder/index.js 5.84 kB
packages/db/dist/esm/query/builder/ref-proxy.js 1.24 kB
packages/db/dist/esm/query/compiler/evaluators.js 1.89 kB
packages/db/dist/esm/query/compiler/expressions.js 430 B
packages/db/dist/esm/query/compiler/group-by.js 3.56 kB
packages/db/dist/esm/query/compiler/index.js 6.67 kB
packages/db/dist/esm/query/compiler/joins.js 2.5 kB
packages/db/dist/esm/query/compiler/lazy-targets.js 923 B
packages/db/dist/esm/query/compiler/order-by.js 1.74 kB
packages/db/dist/esm/query/compiler/select.js 1.53 kB
packages/db/dist/esm/query/effect.js 4.77 kB
packages/db/dist/esm/query/expression-helpers.js 1.43 kB
packages/db/dist/esm/query/ir.js 1.25 kB
packages/db/dist/esm/query/live-query-collection.js 360 B
packages/db/dist/esm/query/live/collection-config-builder.js 9.32 kB
packages/db/dist/esm/query/live/collection-registry.js 264 B
packages/db/dist/esm/query/live/collection-subscriber.js 1.95 kB
packages/db/dist/esm/query/live/internal.js 145 B
packages/db/dist/esm/query/live/utils.js 1.81 kB
packages/db/dist/esm/query/optimizer.js 2.92 kB
packages/db/dist/esm/query/predicate-utils.js 2.97 kB
packages/db/dist/esm/query/query-once.js 359 B
packages/db/dist/esm/query/subset-dedupe.js 960 B
packages/db/dist/esm/scheduler.js 1.3 kB
packages/db/dist/esm/SortedMap.js 1.3 kB
packages/db/dist/esm/strategies/debounceStrategy.js 247 B
packages/db/dist/esm/strategies/queueStrategy.js 428 B
packages/db/dist/esm/strategies/throttleStrategy.js 246 B
packages/db/dist/esm/transactions.js 3.04 kB
packages/db/dist/esm/utils.js 927 B
packages/db/dist/esm/utils/array-utils.js 273 B
packages/db/dist/esm/utils/browser-polyfills.js 304 B
packages/db/dist/esm/utils/btree.js 5.61 kB
packages/db/dist/esm/utils/comparison.js 1.15 kB
packages/db/dist/esm/utils/cursor.js 457 B
packages/db/dist/esm/utils/index-optimization.js 2.39 kB
packages/db/dist/esm/utils/type-guards.js 157 B
packages/db/dist/esm/utils/uuid.js 449 B
packages/db/dist/esm/virtual-props.js 360 B

compressed-size-action::db-package-size

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/vue-db/src/useLiveInfiniteQuery.ts (1)

132-162: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse UtilsRecord for the utility constraint.

Replace both Record<string, any> constraints with UtilsRecord. This removes direct any from the exported API and keeps the constraint aligned with Collection.

Proposed fix
-  TUtils extends Record<string, any>,
+  TUtils extends UtilsRecord,
...
-  TUtils extends Record<string, any>,
+  TUtils extends UtilsRecord,

As per coding guidelines, **/*.{ts,tsx}: “Avoid using any types; use unknown instead when the type is truly unknown.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/vue-db/src/useLiveInfiniteQuery.ts` around lines 132 - 162, Replace
the TUtils constraints using Record<string, any> in
UseLiveInfiniteQueryReturnWithCollection and useLiveInfiniteQuery with the
existing UtilsRecord type, keeping the exported API aligned with Collection and
removing direct any usage.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/vue-db/src/useLiveInfiniteQuery.ts`:
- Around line 53-61: Update normalizePageSize to reject values that would
overflow the later peek-ahead increment, not merely values that are safe
integers. Use the existing peek-ahead limit or equivalent upper-bound symbol
when validating pageSize, while preserving DEFAULT_PAGE_SIZE for invalid inputs
and accepting valid positive sizes below that boundary.

In `@packages/vue-db/tests/useLiveInfiniteQuery.test.ts`:
- Around line 172-194: Expand the pagination boundary tests around the existing
“handles $label pagination boundaries” cases to cover resolved no-op behavior
from fetchNextPage() after the final page, concurrent fetchNextPage() calls
before the first resolves with only one page request applied, and
initialPageParam values of undefined and null both defaulting to 0. Assert the
returned promise and query data remain unchanged where applicable, reusing the
existing posts/query helpers and page expectations.

---

Nitpick comments:
In `@packages/vue-db/src/useLiveInfiniteQuery.ts`:
- Around line 132-162: Replace the TUtils constraints using Record<string, any>
in UseLiveInfiniteQueryReturnWithCollection and useLiveInfiniteQuery with the
existing UtilsRecord type, keeping the exported API aligned with Collection and
removing direct any usage.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9c09b24f-0330-4d82-bed2-6da26b9862e6

📥 Commits

Reviewing files that changed from the base of the PR and between 2c35b58 and 5190891.

📒 Files selected for processing (5)
  • .changeset/curly-ravens-listen.md
  • packages/vue-db/src/index.ts
  • packages/vue-db/src/useLiveInfiniteQuery.ts
  • packages/vue-db/tests/useLiveInfiniteQuery.test-d.ts
  • packages/vue-db/tests/useLiveInfiniteQuery.test.ts

Comment thread packages/vue-db/src/useLiveInfiniteQuery.ts
Comment on lines +172 to +194
it.each([
{ label: `empty`, count: 0, pageSize: 5, pageLengths: [0], limit: 6 },
{ label: `single row`, count: 1, pageSize: 5, pageLengths: [1], limit: 6 },
{
label: `zero page size`,
count: 1,
pageSize: 0,
pageLengths: [1],
limit: 21,
},
])(
`handles $label pagination boundaries`,
async ({ label, count, pageSize, pageLengths, limit }) => {
const posts = createPostsCollection(`vue-infinite-${label}`, count)
const query = mountPostsQuery(posts, { pageSize })
await flushVue()

expect(query.pages.value.map((page) => page.length)).toEqual(pageLengths)
expect(query.hasNextPage.value).toBe(false)
expect(
(query.collection.value.utils as LiveQueryCollectionUtils).getWindow(),
).toEqual({ offset: 0, limit })
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Cover the remaining required pagination corner cases.

The boundary tests only assert hasNextPage is false. Add a test that calls fetchNextPage() after the final page and asserts that the promise resolves with unchanged data. Add a test that starts two fetchNextPage() calls before the first resolves and asserts that only one page request applies. Add runtime coverage for initialPageParam: undefined and initialPageParam: null, which both default to 0.

As per coding guidelines, “Test corner cases including: empty arrays/sets, single-element collections, undefined vs null values, resolved promises, async race conditions, and limit/offset edge cases.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/vue-db/tests/useLiveInfiniteQuery.test.ts` around lines 172 - 194,
Expand the pagination boundary tests around the existing “handles $label
pagination boundaries” cases to cover resolved no-op behavior from
fetchNextPage() after the final page, concurrent fetchNextPage() calls before
the first resolves with only one page request applied, and initialPageParam
values of undefined and null both defaulting to 0. Assert the returned promise
and query data remain unchanged where applicable, reusing the existing
posts/query helpers and page expectations.

Source: Coding guidelines

@github-actions

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 3.79 kB

ℹ️ View Unchanged
Filename Size
packages/react-db/dist/esm/index.js 249 B
packages/react-db/dist/esm/useLiveInfiniteQuery.js 1.29 kB
packages/react-db/dist/esm/useLiveQuery.js 920 B
packages/react-db/dist/esm/useLiveQueryEffect.js 355 B
packages/react-db/dist/esm/useLiveSuspenseQuery.js 567 B
packages/react-db/dist/esm/usePacedMutations.js 401 B

compressed-size-action::react-db-package-size

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant