Skip to content

Also use compare small Uint8Array by content logic for joins - #899

Closed
KyleAMathews wants to merge 3 commits into
mainfrom
claude/fix-bug-018BgfHCaNdqb8awa3LefSfu
Closed

KyleAMathews wants to merge 3 commits into
mainfrom
claude/fix-bug-018BgfHCaNdqb8awa3LefSfu

Conversation

@KyleAMathews

Copy link
Copy Markdown
Collaborator

Export the helper function from db-ivm for use in the main db package.

…parison

This fixes a bug where joining collections by small Uint8Array keys would
fail because the keys were compared by reference instead of by content.

The fix normalizes Uint8Array keys (≤128 bytes) to string representations
before using them as Map keys, similar to the approach used in PR #779 for
value comparison. This ensures that Uint8Array instances with the same
byte content are treated as equal, even if they are different objects.

Changes:
- Added normalizeKey() function to convert small Uint8Arrays to string keys
- Updated Index class to normalize keys in all Map operations
- Maintained mapping from normalized keys to original keys for iteration
- Added test case for joining collections with Uint8Array keys

Fixes #896
This refactoring eliminates code duplication by creating shared utilities
for Uint8Array normalization that can be used across both db-ivm and db
packages.

Changes:
- Created new module: packages/db-ivm/src/utils/uint8array.ts
  - Exports UINT8ARRAY_NORMALIZE_THRESHOLD constant (128 bytes)
  - Exports isUint8Array() helper function
  - Exports normalizeUint8Array() for byte array to string conversion
  - Exports normalizeValue() for generic value normalization

- Updated packages/db-ivm/src/indexes.ts:
  - Removed local normalizeKey() function
  - Now imports and uses normalizeValue from shared utilities

- Updated packages/db/src/utils/comparison.ts:
  - Removed duplicate UINT8ARRAY_NORMALIZE_THRESHOLD constant
  - Removed duplicate isUint8Array check logic
  - Now imports and uses shared utilities from @tanstack/db-ivm

- Updated packages/db-ivm/src/index.ts:
  - Added export for utils/uint8array module

Benefits:
- Single source of truth for Uint8Array normalization logic
- Easier maintenance and consistency across packages
- Follows DRY principle

All tests pass (268 tests in db-ivm, 1699 tests in db).
@changeset-bot

changeset-bot Bot commented Nov 24, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 457a409

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@tanstack/db-ivm Patch
@tanstack/db Patch
@tanstack/angular-db Patch
@tanstack/db-collection-e2e Patch
@tanstack/electric-db-collection Patch
@tanstack/powersync-db-collection Patch
@tanstack/react-db Patch
@tanstack/rxdb-db-collection Patch
@tanstack/solid-db Patch
@tanstack/svelte-db Patch
@tanstack/trailbase-db-collection Patch
@tanstack/vue-db Patch

Not sure what this means? Click here to learn what changesets are.

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

@pkg-pr-new

pkg-pr-new Bot commented Nov 24, 2025

Copy link
Copy Markdown
More templates

@tanstack/angular-db

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

@tanstack/db

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

@tanstack/db-ivm

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

@tanstack/electric-db-collection

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

@tanstack/offline-transactions

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

@tanstack/powersync-db-collection

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

@tanstack/query-db-collection

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

@tanstack/react-db

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

@tanstack/rxdb-db-collection

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

@tanstack/solid-db

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

@tanstack/svelte-db

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

@tanstack/trailbase-db-collection

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

@tanstack/vue-db

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

commit: 457a409

@github-actions

Copy link
Copy Markdown
Contributor

Size Change: -36 B (-0.04%)

Total Size: 86.3 kB

Filename Size Change
./packages/db/dist/esm/utils/comparison.js 816 B -36 B (-4.23%)
ℹ️ View Unchanged
Filename Size
./packages/db/dist/esm/collection/change-events.js 1.38 kB
./packages/db/dist/esm/collection/changes.js 977 B
./packages/db/dist/esm/collection/events.js 388 B
./packages/db/dist/esm/collection/index.js 3.24 kB
./packages/db/dist/esm/collection/indexes.js 1.1 kB
./packages/db/dist/esm/collection/lifecycle.js 1.67 kB
./packages/db/dist/esm/collection/mutations.js 2.26 kB
./packages/db/dist/esm/collection/state.js 3.43 kB
./packages/db/dist/esm/collection/subscription.js 2.48 kB
./packages/db/dist/esm/collection/sync.js 2.37 kB
./packages/db/dist/esm/deferred.js 207 B
./packages/db/dist/esm/errors.js 4.19 kB
./packages/db/dist/esm/event-emitter.js 748 B
./packages/db/dist/esm/index.js 2.64 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 1.87 kB
./packages/db/dist/esm/indexes/lazy-index.js 1.1 kB
./packages/db/dist/esm/indexes/reverse-index.js 513 B
./packages/db/dist/esm/local-only.js 837 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.22 kB
./packages/db/dist/esm/query/builder/functions.js 733 B
./packages/db/dist/esm/query/builder/index.js 3.96 kB
./packages/db/dist/esm/query/builder/ref-proxy.js 917 B
./packages/db/dist/esm/query/compiler/evaluators.js 1.35 kB
./packages/db/dist/esm/query/compiler/expressions.js 430 B
./packages/db/dist/esm/query/compiler/group-by.js 1.8 kB
./packages/db/dist/esm/query/compiler/index.js 1.96 kB
./packages/db/dist/esm/query/compiler/joins.js 2 kB
./packages/db/dist/esm/query/compiler/order-by.js 1.25 kB
./packages/db/dist/esm/query/compiler/select.js 1.07 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.26 kB
./packages/db/dist/esm/query/live/collection-registry.js 264 B
./packages/db/dist/esm/query/live/collection-subscriber.js 1.74 kB
./packages/db/dist/esm/query/live/internal.js 130 B
./packages/db/dist/esm/query/optimizer.js 2.56 kB
./packages/db/dist/esm/query/predicate-utils.js 2.88 kB
./packages/db/dist/esm/query/subset-dedupe.js 921 B
./packages/db/dist/esm/scheduler.js 1.21 kB
./packages/db/dist/esm/SortedMap.js 1.18 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 881 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/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
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 3.34 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.11 kB
./packages/react-db/dist/esm/useLiveSuspenseQuery.js 431 B
./packages/react-db/dist/esm/usePacedMutations.js 401 B

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

@samwillis samwillis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we should consider carefully if this is a change we want to make. The performance of joins is important, and currently this implementation makes all joins use a new (slightly) slower code path with the normalisation and tracking of original keys - thats not needed for 99% of joins that use string or numeric keys.

I'm honestly not sure that supporting uint8 arrays as join keys is a good idea or not. We can decide to just push this back on the user and have them normalise a uuid to a string when syncing data - I do wander if that is a better option that adding complexity.

describe(`Operators`, () => {
describe(`Join operation`, () => {
testJoin()
testUint8ArrayKeyJoin()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If we decide to keep this implementation, can we incorporate this into the main testJoin function rather than adding as a new one with just this single test?

*/
#inner: IndexMap<TKey, TValue, TPrefix>
#consolidatedMultiplicity: Map<TKey, number> = new Map() // sum of multiplicities per key
#originalKeys: Map<TKey, TKey> = new Map() // map from normalized keys to original keys

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm a little nervous of the overhead of adding this additional map and the lookups. We are making joins slower for all cases in order to support an edge case.

KyleAMathews added a commit that referenced this pull request Sep 16, 2026
Canonicalize satisfiable join operands through the compilation ValueIdentity, keep nullish operands row-disjoint, and preserve raw lazy-demand values with stable representatives. This restores equality-predicate consistency for binary and other established value domains without adding compound join syntax.

Provenance: #593 Lucas Duailibe and Sam Willis; #861 Vincent Chan; #896 Tomas Zaluckij; #779/#899/#1258 Kyle Mathews and Claude; #899 review by Sam Willis; #1229 Hieu Nguyen, Hiếu Nguyễn Minh, Kevin De Porre, and Claude Opus 4.6; #1797 ValueIdentity architecture by Kyle Mathews. Prior art informed the evidence and design; no prior implementation lines were reused. #593/#861 remain design-gated.

Weight: production source net +30 lines; emitted join module +65 B ESM gzip and +60 B CJS gzip. No public API, export, dependency, compatibility branch, or db-ivm change.
KyleAMathews added a commit that referenced this pull request Sep 16, 2026
Canonicalize satisfiable join operands through the compilation ValueIdentity, keep nullish operands row-disjoint, and preserve raw lazy-demand values with stable representatives. This restores equality-predicate consistency for binary and other established value domains without adding compound join syntax.

Provenance: #593 Lucas Duailibe and Sam Willis; #861 Vincent Chan; #896 Tomas Zaluckij; #779/#899/#1258 Kyle Mathews and Claude; #899 review by Sam Willis; #1229 Hieu Nguyen, Hiếu Nguyễn Minh, Kevin De Porre, and Claude Opus 4.6; #1797 ValueIdentity architecture by Kyle Mathews. Prior art informed the evidence and design; no prior implementation lines were reused. #593/#861 remain design-gated.

Weight: production source net +30 lines; emitted join module +65 B ESM gzip and +60 B CJS gzip. No public API, export, dependency, compatibility branch, or db-ivm change.
KyleAMathews added a commit that referenced this pull request Sep 17, 2026
* fix(db): align join keys with equality identity

Canonicalize satisfiable join operands through the compilation ValueIdentity, keep nullish operands row-disjoint, and preserve raw lazy-demand values with stable representatives. This restores equality-predicate consistency for binary and other established value domains without adding compound join syntax.

Provenance: #593 Lucas Duailibe and Sam Willis; #861 Vincent Chan; #896 Tomas Zaluckij; #779/#899/#1258 Kyle Mathews and Claude; #899 review by Sam Willis; #1229 Hieu Nguyen, Hiếu Nguyễn Minh, Kevin De Porre, and Claude Opus 4.6; #1797 ValueIdentity architecture by Kyle Mathews. Prior art informed the evidence and design; no prior implementation lines were reused. #593/#861 remain design-gated.

Weight: production source net +30 lines; emitted join module +65 B ESM gzip and +60 B CJS gzip. No public API, export, dependency, compatibility branch, or db-ivm change.

* Apply join equality review fixes

* Reduce join result processing overhead
@KyleAMathews

Copy link
Copy Markdown
Collaborator Author

Closing as superseded by merged PR #1834, which fixes binary join-key equality through the shared equality identity path. The approach from this PR remains credited in #1834.

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.

3 participants