fix(analytics): boolean filters & group-by compare against real boolean, not stringified '1'#2287
Merged
Merged
Conversation
…, not stringified '1'
The analytics filter normalizer stringified boolean `true` → `'1'`, which the
ObjectQL strategy then coerced back to the number `1` before passing it into
`engine.aggregate`. Stored boolean fields hold a real `true`/`false`, so
`1 !== true` never matched: boolean metric widgets always returned 0 and
boolean group-by dimensions failed to bucket.
`'1'`/`'0'` was indistinguishable from a numeric 1/0, so the boolean identity
could not be recovered. Fix the roundtrip:
- `stringifyForCube` now serializes booleans as the tokens `'true'`/`'false'`,
preserving the boolean identity through the `string[]` pipeline form.
- New `coerceFilterValueForObjectQL` recovers a real `true`/`false` for the
ObjectQL engine (compares against the stored runtime type); the SQL path keeps
recovering `1`/`0` since better-sqlite3 cannot bind a JS boolean. Shared
numeric recovery extracted into `recoverNumber`.
- ObjectQLStrategy.convertFilter uses the new ObjectQL coercer.
Adds a regression test whose mock engine filters/buckets in-memory rows by
STRICT `===`: a `{ is_critical: true }` filter yields a non-zero count, `false`
matches its rows, and a boolean group-by produces both true/false buckets.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 5 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
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.
Problem
On the analytics dataset query path (
POST /api/v1/analytics/dataset/query), a metric widget filtered on a boolean field (e.g.{ is_critical: true }) always returned 0, and pie/donut/bar charts grouped by a boolean dimension failed to bucket.Root cause
A lossy string roundtrip in the filter normalizer:
stringifyForCubeserialized booleantrue→'1'(filter-normalizer.ts) — indistinguishable from a numeric1.ObjectQLStrategythen coerced'1'back to the number1viacoerceFilterValueForSqland passed{ is_critical: 1 }intoengine.aggregate.true, so1 !== true— the comparison never matched.The SQL strategy needs
1/0(better-sqlite3 cannot bind a JS boolean), but the ObjectQL engine compares against the stored runtime type — sharing one coercer was the defect.Fix
stringifyForCubeserializes booleans as the tokens'true'/'false', preserving boolean identity through thestring[]pipeline form (SQL output unchanged:'true'→1).coerceFilterValueForObjectQLrecovers a realtrue/falsefor the ObjectQL engine; SQL path keeps recovering1/0. Shared numeric recovery extracted intorecoverNumber.ObjectQLStrategy.convertFilteruses the ObjectQL coercer.Test
New
objectql-strategy-boolean-filter.test.ts— the mock engine filters/buckets in-memory rows by strict===(so a stringified1fails it):{ is_critical: true }→ real boolean reaches the engine, count is non-zero (3);{ is_critical: false }→ matches its rows (2);true(3) andfalse(2) buckets.Full service-analytics suite (154 tests) passes; package builds clean.