Skip to content

Fix isWhereSubset to handle AND subset with OR superset#1275

Open
KyleAMathews wants to merge 2 commits intomainfrom
claude/fix-livequery-isnull-bug-NMK6E
Open

Fix isWhereSubset to handle AND subset with OR superset#1275
KyleAMathews wants to merge 2 commits intomainfrom
claude/fix-livequery-isnull-bug-NMK6E

Conversation

@KyleAMathews
Copy link
Collaborator

🎯 Changes

Fixed a bug in the isWhereSubset predicate utility where an AND expression was not correctly recognized as a subset of an OR expression containing matching disjuncts.

The Problem:
When checking if and(eq(project_id, X), isNull(soft_deleted_at)) is a subset of or(and(eq(project_id, X), isNull(soft_deleted_at)), and(eq(project_id, Y), isNull(soft_deleted_at))), the function was incorrectly returning false. This caused the query system to not recognize that data for project X was already loaded when re-requesting it.

The Fix:
Reordered the predicate checks in isWhereSubsetInternal to handle OR expressions in the superset before decomposing AND expressions in the subset. This ensures that when an AND expression structurally matches one of the OR disjuncts, it's recognized as a subset via direct equality rather than being decomposed into individual conjuncts that can't prove the subset relationship.

The key insight: and(A, B) ⊆ or(and(A, B), and(C, D)) must be checked as a whole expression against the OR disjuncts, not by checking if individual conjuncts A or B are subsets of the OR.

Changes Made:

  • Moved OR superset handling before AND subset decomposition in isWhereSubsetInternal
  • Added comprehensive test cases covering the reported bug scenario and related edge cases
  • Added tests for isNull predicate handling in various contexts

✅ Checklist

  • I have tested this code locally with pnpm test.

🚀 Release Impact

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

https://claude.ai/code/session_01TmGem9Pj1NnXfaWY5FZJdb

… when offline

The `isWhereSubsetInternal` function had a critical ordering issue in its
predicate checking logic. When a query with `and(eq(...), isNull(...))` was
checked against a union superset like `or(and(eq(...), isNull(...)), ...)`,
the AND decomposition ran before the OR superset check. This caused the
function to decompose the AND into individual conjuncts (eq and isNull),
neither of which could independently prove subset of the OR expression,
even though the full AND expression was structurally equal to one of the
OR disjuncts.

The fix reorders the checks so that:
1. superset AND is handled first (unchanged)
2. subset OR is handled next (moved up from after AND)
3. superset OR is handled next (moved up from after IN)
4. subset AND decomposition happens last

This ensures that when subset=AND and superset=OR, the full AND expression
is checked against each OR disjunct (where structural equality catches it),
before being decomposed into individual conjuncts that lose the ability to
match compound disjuncts.

Reported scenario: on-demand sync with `isNull(soft_deleted_at)` in a where
clause caused `isLoadingSubset` to stay true after going offline and
remounting, because the DeduplicatedLoadSubset couldn't recognize that
data for the predicate was already loaded.

https://claude.ai/code/session_01TmGem9Pj1NnXfaWY5FZJdb
@changeset-bot
Copy link

changeset-bot bot commented Feb 19, 2026

⚠️ No Changeset found

Latest commit: 0d401ba

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 19, 2026

More templates

@tanstack/angular-db

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

@tanstack/db

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

@tanstack/db-ivm

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

@tanstack/electric-db-collection

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

@tanstack/offline-transactions

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

@tanstack/powersync-db-collection

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

@tanstack/query-db-collection

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

@tanstack/react-db

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

@tanstack/rxdb-db-collection

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

@tanstack/solid-db

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

@tanstack/svelte-db

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

@tanstack/trailbase-db-collection

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

@tanstack/vue-db

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

commit: 0d401ba

@github-actions
Copy link
Contributor

Size Change: -2 B (0%)

Total Size: 92.1 kB

Filename Size Change
./packages/db/dist/esm/query/predicate-utils.js 2.97 kB -2 B (-0.07%)
ℹ️ View Unchanged
Filename Size
./packages/db/dist/esm/collection/change-events.js 1.39 kB
./packages/db/dist/esm/collection/changes.js 1.22 kB
./packages/db/dist/esm/collection/events.js 388 B
./packages/db/dist/esm/collection/index.js 3.32 kB
./packages/db/dist/esm/collection/indexes.js 1.1 kB
./packages/db/dist/esm/collection/lifecycle.js 1.75 kB
./packages/db/dist/esm/collection/mutations.js 2.34 kB
./packages/db/dist/esm/collection/state.js 3.49 kB
./packages/db/dist/esm/collection/subscription.js 3.71 kB
./packages/db/dist/esm/collection/sync.js 2.41 kB
./packages/db/dist/esm/deferred.js 207 B
./packages/db/dist/esm/errors.js 4.7 kB
./packages/db/dist/esm/event-emitter.js 748 B
./packages/db/dist/esm/index.js 2.69 kB
./packages/db/dist/esm/indexes/auto-index.js 742 B
./packages/db/dist/esm/indexes/base-index.js 766 B
./packages/db/dist/esm/indexes/btree-index.js 2.17 kB
./packages/db/dist/esm/indexes/lazy-index.js 1.1 kB
./packages/db/dist/esm/indexes/reverse-index.js 538 B
./packages/db/dist/esm/local-only.js 808 B
./packages/db/dist/esm/local-storage.js 2.1 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 733 B
./packages/db/dist/esm/query/builder/index.js 4.09 kB
./packages/db/dist/esm/query/builder/ref-proxy.js 1.05 kB
./packages/db/dist/esm/query/compiler/evaluators.js 1.43 kB
./packages/db/dist/esm/query/compiler/expressions.js 430 B
./packages/db/dist/esm/query/compiler/group-by.js 1.81 kB
./packages/db/dist/esm/query/compiler/index.js 2.02 kB
./packages/db/dist/esm/query/compiler/joins.js 2.11 kB
./packages/db/dist/esm/query/compiler/order-by.js 1.45 kB
./packages/db/dist/esm/query/compiler/select.js 1.06 kB
./packages/db/dist/esm/query/expression-helpers.js 1.43 kB
./packages/db/dist/esm/query/ir.js 673 B
./packages/db/dist/esm/query/live-query-collection.js 360 B
./packages/db/dist/esm/query/live/collection-config-builder.js 5.44 kB
./packages/db/dist/esm/query/live/collection-registry.js 264 B
./packages/db/dist/esm/query/live/collection-subscriber.js 2.42 kB
./packages/db/dist/esm/query/live/internal.js 145 B
./packages/db/dist/esm/query/optimizer.js 2.62 kB
./packages/db/dist/esm/query/subset-dedupe.js 921 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 2.9 kB
./packages/db/dist/esm/utils.js 924 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 952 B
./packages/db/dist/esm/utils/cursor.js 457 B
./packages/db/dist/esm/utils/index-optimization.js 1.51 kB
./packages/db/dist/esm/utils/type-guards.js 157 B

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

@github-actions
Copy link
Contributor

Size Change: 0 B

Total Size: 3.7 kB

ℹ️ View Unchanged
Filename Size
./packages/react-db/dist/esm/index.js 225 B
./packages/react-db/dist/esm/useLiveInfiniteQuery.js 1.17 kB
./packages/react-db/dist/esm/useLiveQuery.js 1.34 kB
./packages/react-db/dist/esm/useLiveSuspenseQuery.js 559 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.

2 participants

Comments