Skip to content

fix(db): support Temporal values in query comparison operators#1519

Open
obeattie wants to merge 1 commit intoTanStack:mainfrom
obeattie:temporal-comparators
Open

fix(db): support Temporal values in query comparison operators#1519
obeattie wants to merge 1 commit intoTanStack:mainfrom
obeattie:temporal-comparators

Conversation

@obeattie
Copy link
Copy Markdown
Contributor

@obeattie obeattie commented May 7, 2026

🎯 Changes

Fixes a TypeError when query filters use comparison operators (gt/gte/lt/lte) on Temporal values. The evaluators applied JS's native >/< directly, which throws on Temporal types because their valueOf() is designed to throw — a guard against silent miscomparison.

Adds a compareValues(a, b) helper that dispatches to the Temporal types' static .compare() when both operands share a type. Mixed Temporal types and types with no defined ordering (PlainMonthDay) throw a descriptive TypeError rather than fall back to string-lex comparison. Non-Temporal values continue to use native operators.

eq is unchanged — it still goes through normalizeValue, so ZonedDateTime equality treats the zone as part of identity while ordering compares by instant only, mirroring .equals() vs .compare() in the spec.

Tests cover all eight Temporal types, the same-instant/different-zone asymmetry for ZonedDateTime, and Duration's equivalent-forms case (PT60M vs PT1H: equal under .compare() but not .equals()).

✅ 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).

The query compiler's gt/gte/lt/lte evaluators applied JavaScript's native
relational operators directly. That throws TypeError on Temporal values
because Temporal types intentionally make valueOf() throw — a spec-level
guard against silent miscomparison.

Adds a compareValues(a, b) helper that, when both operands share a Temporal
type, dispatches through that type's static .compare() (Instant, PlainDate,
PlainDateTime, PlainTime, PlainYearMonth, ZonedDateTime, Duration). Mixed
Temporal types and types without a defined ordering (PlainMonthDay) throw a
descriptive TypeError rather than fall back to a string-lex pseudo-compare,
keeping us in line with Temporal's design. Non-Temporal values continue to
use native operators (Dates via valueOf, numbers, strings, etc.).

The gt/gte/lt/lte cases in evaluators.ts each switch from `a > b` to
`compareValues(a, b) > 0` (and equivalents). Equality (eq) is unchanged: it
still goes through normalizeValue's tagged toString, which means ZonedDateTime
eq treats the zone as part of identity while ordering compares by instant —
matching .equals() vs .compare() semantics in the spec.

Tests cover all eight Temporal types, the same-instant-different-zone
asymmetry for ZonedDateTime, and Duration's equivalent-forms case (PT60M vs
PT1H — equal under .compare() but not .equals()).
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 7, 2026

More templates

@tanstack/angular-db

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

@tanstack/browser-db-sqlite-persistence

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

@tanstack/capacitor-db-sqlite-persistence

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

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

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

@tanstack/db

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

@tanstack/db-ivm

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

@tanstack/db-sqlite-persistence-core

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

@tanstack/electric-db-collection

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

@tanstack/electron-db-sqlite-persistence

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

@tanstack/expo-db-sqlite-persistence

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

@tanstack/node-db-sqlite-persistence

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

@tanstack/offline-transactions

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

@tanstack/powersync-db-collection

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

@tanstack/query-db-collection

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

@tanstack/react-db

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

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

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

@tanstack/rxdb-db-collection

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

@tanstack/solid-db

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

@tanstack/svelte-db

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

@tanstack/tauri-db-sqlite-persistence

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

@tanstack/trailbase-db-collection

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

@tanstack/vue-db

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

commit: 4aa5a51

@obeattie obeattie marked this pull request as ready for review May 7, 2026 10:37
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