Skip to content

refactor: column identifiers to their own type#2425

Draft
knudtty wants to merge 2 commits into
mainfrom
aaron/refactor-column-identifiers
Draft

refactor: column identifiers to their own type#2425
knudtty wants to merge 2 commits into
mainfrom
aaron/refactor-column-identifiers

Conversation

@knudtty

@knudtty knudtty commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Screenshots or video

Before After

How to test on Vercel preview

Preview routes:

Steps:

References

  • Linear Issue:
  • Related PRs:

@changeset-bot

changeset-bot Bot commented Jun 8, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: a9d442d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel

vercel Bot commented Jun 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview, Comment Jun 8, 2026 4:04pm
hyperdx-storybook Ready Ready Preview, Comment Jun 8, 2026 4:04pm

Request Review

@greptile-apps

greptile-apps Bot commented Jun 8, 2026

Copy link
Copy Markdown

Greptile Summary

This PR refactors parseKeyPath's return type from string[] to a strongly-typed ColumnKey discriminated union (NativeColumnKey | MapColumnKey), introducing NATIVE_COLUMN as a sentinel and columnKeyToDotPath() as the explicit dot-path renderer that replaces the fragile .join('.') pattern scattered across the codebase.

  • Adds ColumnKey, NativeColumnKey, MapColumnKey types with Zod schemas in types.ts, exports them from guards.ts via the isMapColumn type guard, and updates every call site from parseKeyPath(x).join('.') to columnKeyToDotPath(parseKeyPath(x)).
  • Updates metadata.ts internal SQL to use the NATIVE_COLUMN constant rather than the inline 'NativeColumn' string, and refreshes all tests to match the new return shape.

Confidence Score: 4/5

Safe to merge — all call-site changes are semantically equivalent to the old join('.') pattern, and the new type structure correctly discriminates native vs. map columns throughout.

The refactoring is correct across all changed call sites. The only gap is that MapColumnKeySchema does not reject an empty string for the column field, meaning a malformed input like ['service.name'] (bracket at index 0) silently becomes a MapColumnKey with an empty column name and can propagate to SQL generation. This is an edge case unlikely to be triggered in practice, but the schema invariant is incomplete.

packages/common-utils/src/types.ts — the MapColumnKeySchema column field validation.

Important Files Changed

Filename Overview
packages/common-utils/src/types.ts Adds NATIVE_COLUMN sentinel, NativeColumnKeySchema, MapColumnKeySchema, ColumnKeySchema, and derived TypeScript types; MapColumnKeySchema allows empty string for column.
packages/common-utils/src/core/metadata.ts parseKeyPath return type changed to ColumnKey; new columnKeyToDotPath helper; all internal usages updated correctly; SQL ordering clause now uses NATIVE_COLUMN constant.
packages/common-utils/src/guards.ts Adds isMapColumn type guard; correctly mirrors old path.length >= 2 check with column !== NATIVE_COLUMN comparison.
packages/common-utils/src/tests/metadata.test.ts Tests updated to match new ColumnKey return shape; all parseKeyPath cases correctly updated including the native-column and incomplete-bracket edge cases.
packages/common-utils/src/filters.ts filtersToQuery updated to columnKeyToDotPath(parseKeyPath(key)), semantically identical to the old join('.') pattern.
packages/common-utils/src/queryParser.ts buildMapContains updated from path.length < 2 to !isMapColumn(col); behavior is identical.
packages/app/src/components/DBSearchPageFilters/utils.ts parseMapFieldName updated to use isMapColumn and col.column/col.key; the old path.slice(1).join('.') was always equivalent to path[1] since parseKeyPath returned at most 2 elements.
packages/app/src/searchFilters.tsx Three setFilterValue/setFilterRange/clearFilter key normalizations updated to columnKeyToDotPath; all semantically equivalent.
packages/app/src/hooks/useDashboardFilters.tsx Two key normalization sites updated to columnKeyToDotPath(parseKeyPath()); semantically equivalent to the old pattern.
packages/app/src/hooks/useAutoCompleteOptions.tsx fieldName construction updated; semantically identical output.
packages/common-utils/src/core/eventDeltas.ts Removed an unnecessary eslint-disable comment before the recurse function declaration; per-use suppressions inside the function remain in place.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Raw key string\ne.g. SpanAttributes['k8s.pod.name']"] --> B["parseKeyPath(key)"]
    B --> C{Bracket notation\ndetected?}
    C -- Yes --> D["ColumnKey\n{ column: 'SpanAttributes', key: 'k8s.pod.name' }"]
    C -- No --> E["ColumnKey\n{ column: NATIVE_COLUMN, key: 'ServiceName' }"]
    D --> F["isMapColumn(col) → true"]
    E --> G["isMapColumn(col) → false"]
    F --> H["columnKeyToDotPath(col)\n→ 'SpanAttributes.k8s.pod.name'"]
    G --> I["columnKeyToDotPath(col)\n→ 'ServiceName'"]
    F --> J["SQL path\nmapContains(col.column, col.key)"]
    H --> K["FilterState key / Lucene field"]
    I --> K
Loading

Fix All in Claude Code Fix All in Conductor Fix All in Cursor Fix All in Codex

Reviews (1): Last reviewed commit: "WIP" | Re-trigger Greptile

Comment on lines +1922 to +1927
export const MapColumnKeySchema = z.object({
column: z.string().refine(s => s !== NATIVE_COLUMN, {
message: `column must not equal "${NATIVE_COLUMN}"; use NativeColumnKeySchema for native columns`,
}),
key: z.string(),
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 MapColumnKeySchema only rejects NATIVE_COLUMN for column but does not reject an empty string. parseKeyPath("['service.name']") (bracket starting at index 0) produces { column: '', key: 'service.name' }, which passes this schema as a MapColumnKey. Downstream callers like buildMapContains would then emit mapContains(\`, 'service.name')— invalid SQL. Addingmin(1)` closes the gap and makes the schema's invariant explicit.

Suggested change
export const MapColumnKeySchema = z.object({
column: z.string().refine(s => s !== NATIVE_COLUMN, {
message: `column must not equal "${NATIVE_COLUMN}"; use NativeColumnKeySchema for native columns`,
}),
key: z.string(),
});
export const MapColumnKeySchema = z.object({
column: z
.string()
.min(1, { message: 'column must be a non-empty string' })
.refine(s => s !== NATIVE_COLUMN, {
message: `column must not equal "${NATIVE_COLUMN}"; use NativeColumnKeySchema for native columns`,
}),
key: z.string(),
});

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

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