Repository navigation
Conversation
Replace correlated frequency queries with grouped MODE aggregates. Preserve null handling and tie-breaking, and cover empty ranges and leading/trailing gaps with regression tests. BREAKING CHANGE: MODE with gapFill=true now includes empty buckets as null-valued results across the inclusive query range. Results may contain more rows and exceed the configured datapoint query limit. Use gapFill=false to retain populated-bucket-only results.
Normalize JSON nulls before casting and remove the fallback that replaced unavailable differences with absolute readings. Document carry-forward semantics and add regression coverage. BREAKING CHANGE: With gap filling enabled, the first reading after a leading empty bucket now yields null instead of its absolute value as the difference.
|
This branch has not been deployed
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.



Stored JSON null values caused numeric and boolean datapoint queries to fail during SQL
casting. Normalize JSON null to SQL NULL before conversion, and preserve unavailable
values during boolean conversion instead of interpreting them as false.
This applies to historical and predicted datapoints:
available values return null. COUNT still counts stored rows, including null-valued rows.
empty buckets still carry the previous bucket value when gap filling is enabled.
markers; an all-null range returns no points.
MODE now uses a grouped native aggregate, enabling Timescale gap filling. Numeric ties
still select the smaller value and boolean ties select true. Boolean MEDIAN retains its
threshold of at least 0.5 for a true/1 result.
Compatibility / migration
including leading/trailing gaps and entirely empty ranges. A five-minute query from
08:30 through 09:00 with observations only through 08:55 now returns an additional
(09:00, unavailable) bucket. Callers must handle added rows and unavailable values.
Use gapFill=false if only populated buckets are wanted. Fine-grained sparse ranges
can now exceed the configured result limit (default 100000 points).
available reading, rather than its absolute value. Callers must not assume a zero
baseline when the previous bucket is unavailable.
service's numeric format. They now return 1 or 0, so existing callers may receive real
values where they previously saw unavailable results.
Wire format is unchanged: datapoints use x for timestamp and y for value. The configured
JSON mapper omits null properties. A retained unavailable datapoint therefore appears as
{"x":1767225600000}, not necessarily with an explicit "y":null. Clients must handle an
absent y. Both forms deserialize to a null value. LTTB omits the observation entirely.
No database migration or rewrite of stored datapoints is required.
Validation
The core query suites passed 136 tests (132 new null-query cases plus four existing query
features), with none skipped and UTC explicitly configured on the test JVM. Coverage spans
historical/predicted data, NUMBER/BIG_NUMBER/BOOLEAN, both gap-fill settings, null-only and
empty ranges, ties, recovery after unavailable differences, query bounds and real LTTB
point selection. Each implementation step was checked against failing regressions.
The serialization probe also verified omitted y, explicit-null deserialization, and
preservation of zero and false. All 18 adjacent storage/export/deserialization tests
also passed, with none skipped.
MODE performance
Compared the previous null-safe custom MODE query against the grouped native query using
288 captured EXPLAIN ANALYZE plans on PostgreSQL 17.9 / TimescaleDB 2.26.4, with matching
indexes and seven-day chunks. Three measured warm-cache runs followed one warmup, with
old/new execution order alternated. All tested equal-output data queries improved.
For 20000 numeric observations across 4000 buckets, median execution fell from 3123 ms to
9.2 ms: the old plan scanned the 20000-row CTE 4000 times. Large numeric and boolean
buckets also improved despite sort spills. These are synthetic database execution times,
not end-to-end production guarantees.
Sparse minute-level gap filling across a year now generates 525600 rows instead of 365;
the count query increased from 0.55 ms to 56.8 ms and the default limit rejects that range.
All benchmark data and objects were rolled back.