fix(db): support Temporal values in query comparison operators#1519
Open
obeattie wants to merge 1 commit intoTanStack:mainfrom
Open
fix(db): support Temporal values in query comparison operators#1519obeattie wants to merge 1 commit intoTanStack:mainfrom
obeattie wants to merge 1 commit intoTanStack:mainfrom
Conversation
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()).
More templates
@tanstack/angular-db
@tanstack/browser-db-sqlite-persistence
@tanstack/capacitor-db-sqlite-persistence
@tanstack/cloudflare-durable-objects-db-sqlite-persistence
@tanstack/db
@tanstack/db-ivm
@tanstack/db-sqlite-persistence-core
@tanstack/electric-db-collection
@tanstack/electron-db-sqlite-persistence
@tanstack/expo-db-sqlite-persistence
@tanstack/node-db-sqlite-persistence
@tanstack/offline-transactions
@tanstack/powersync-db-collection
@tanstack/query-db-collection
@tanstack/react-db
@tanstack/react-native-db-sqlite-persistence
@tanstack/rxdb-db-collection
@tanstack/solid-db
@tanstack/svelte-db
@tanstack/tauri-db-sqlite-persistence
@tanstack/trailbase-db-collection
@tanstack/vue-db
commit: |
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.
🎯 Changes
Fixes a
TypeErrorwhen 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 theirvalueOf()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 descriptiveTypeErrorrather than fall back to string-lex comparison. Non-Temporal values continue to use native operators.eqis unchanged — it still goes throughnormalizeValue, soZonedDateTimeequality 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, andDuration's equivalent-forms case (PT60MvsPT1H: equal under.compare()but not.equals()).✅ Checklist
pnpm test.🚀 Release Impact