fix: stringify JSON search sidebar filters#2551
Conversation
🦋 Changeset detectedLatest commit: 7f46a87 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
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 |
|
@mfroembgen is attempting to deploy a commit to the HyperDX Team on Vercel. A member of the Team first needs to authorize it. |
Greptile SummaryThis PR replaces ClickHouse JSON typed-subcolumn access (
Confidence Score: 5/5Safe to merge — all changed paths are well-covered by new and updated unit tests, and the generation-counter and round-trip guards prevent the two most dangerous edge cases. The toString(...) replacement is consistently applied across all four query surfaces and the backslash-escaping round-trip is explicitly tested. The canonicalizeFilterQuery round-trip guard means stale filters are rewritten only when they fully parse and reproduce. The load-more generation counter correctly discards stale callbacks, confirmed by two dedicated race-condition tests. No files require special attention. The parsing helpers in metadata.ts are the densest new code but each has targeted unit coverage including backslash and complex type suffix edge cases. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Filter key in sidebar] --> B{Is key in jsonColumns?}
B -- Yes --> C[renderJsonStringExpression toString wrapper]
B -- No --> D{Bracket-form or backtick-quoted?}
D -- Yes --> E[Return unchanged map access]
D -- No --> F[toClickHouseKeyExpression bracket form]
C --> G[SQL filter condition]
E --> G
F --> G
H[Persisted filter loaded] --> I{canonicalizeFilterQuery}
I -- hasJsonFilter AND round-trip match --> J[Re-serialize with escapeFilterStateKeys]
I -- no JSON filter OR compound predicate --> K[Return original filters unchanged]
J --> L[setValue plus setSearchedConfig]
L --> M[canonicalizedFilters memo returns null - cycle stops]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Filter key in sidebar] --> B{Is key in jsonColumns?}
B -- Yes --> C[renderJsonStringExpression toString wrapper]
B -- No --> D{Bracket-form or backtick-quoted?}
D -- Yes --> E[Return unchanged map access]
D -- No --> F[toClickHouseKeyExpression bracket form]
C --> G[SQL filter condition]
E --> G
F --> G
H[Persisted filter loaded] --> I{canonicalizeFilterQuery}
I -- hasJsonFilter AND round-trip match --> J[Re-serialize with escapeFilterStateKeys]
I -- no JSON filter OR compound predicate --> K[Return original filters unchanged]
J --> L[setValue plus setSearchedConfig]
L --> M[canonicalizedFilters memo returns null - cycle stops]
Reviews (18): Last reviewed commit: "fix: stringify JSON search sidebar filte..." | Re-trigger Greptile |
5116fd3 to
73196cd
Compare
fe66a5f to
424cc9a
Compare
424cc9a to
16061b0
Compare
🔴 P0/P1 -- must fix
🟡 P2 -- recommended
🔵 P3 nitpicks (6)
Reviewers (8): correctness, security, adversarial, julik-frontend-races, kieran-typescript, testing, maintainability, api-contract. Testing gaps:
|
b1a0570 to
d2d943e
Compare
d2d943e to
7f46a87
Compare
Summary
toString(ResourceAttributes.\k8s`.`namespace`.`name`), instead of JSON map access or a fixed.:String` suffix.Load more.Why
toString(...)Testing against ClickHouse
26.5.1.882withJSON(max_dynamic_types=8, max_dynamic_paths=64)columns showed that.:Stringis only safe for JSON paths whose active dynamic type is actually String. Integer, boolean, and mixed-type paths can silently return no values with.:String, whiletoString(<JSON path>)returned usable values for all of these real path shapes:ResourceAttributes.k8s.namespace.name(string)ResourceAttributes.cloud.account.id(integer)LogAttributes.endOfBatch(boolean)LogAttributes.level(mixed integer/string)The same
toString(...)expression also worked for distribution/grouping queries.Manual verification
26.5.1.882, whereResourceAttributesandLogAttributesareJSON(max_dynamic_types=8, max_dynamic_paths=64)columns.toString(...).toString(ResourceAttributes.\cloud`.`account`.`id`)andtoString(LogAttributes.`endOfBatch`)`.ResourceAttributes['k8s.namespace.name']filters were canonicalized, results loaded without the ClickHousearrayElementJSON error, Show Distribution loaded, and selected/pinned facets refreshed with matching values plusLoad more.Automated verification
mise exec node@22.16.0 -- node .yarn/releases/yarn-4.13.0.cjs lint:fixmise exec node@22.16.0 -- node ../../.yarn/releases/yarn-4.13.0.cjs ci:lintinpackages/common-utilsmise exec node@22.16.0 -- node ../../.yarn/releases/yarn-4.13.0.cjs ci:unitinpackages/common-utilsmise exec node@22.16.0 -- node .yarn/releases/yarn-4.13.0.cjs workspace @hyperdx/app jest packages/app/src/components/__tests__/DBSearchPageFilters.test.tsx packages/app/src/components/DBSearchPageFilters/utils.test.ts packages/app/src/__tests__/searchFilters.test.ts --runInBand --coverage=falsemise exec node@22.16.0 -- bash -lc 'corepack enable >/dev/null 2>&1 || true; make dev-e2e FILE=filter-key-edge-cases'(18 passed)References
Fixes #2549.
Related to #2482 and #2537.