Skip to content

improvement(tables): add per-column-type behavior registry - #6104

Closed
j15z wants to merge 6 commits into
stagingfrom
feat/advanced-table-column-types
Closed

improvement(tables): add per-column-type behavior registry#6104
j15z wants to merge 6 commits into
stagingfrom
feat/advanced-table-column-types

Conversation

@j15z

@j15z j15z commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add a per-column-type behavior registry (column-types.ts) so each of the 6 column types' SQL cast, parse, validate, format, and conversion-compatibility rules live in one place instead of ~10 scattered switch statements across sql.ts, validation.ts, and columns/service.ts
  • Migrate those four call sites to delegate to the registry
  • Consolidate duplicated select-value helpers into select-values.ts
  • Fix CsvColumnType type drift (was missing select) by splitting it into ColumnType (coercion target) and InferableColumnType (CSV type-inference output); fix a bug where a whitespace-only CSV number cell imported as 0 instead of null
  • Fix the same select drift in the test-fixture factory (packages/testing)

Type of Change

  • Improvement (internal refactor + two small bug fixes, no new column type yet)

Testing

  • bun run type-check (sim, @sim/testing) — clean
  • bun run lint — clean
  • All CI check:* audits — clean
  • lib/table suite: 536 passing (was 486 before this PR; +50 new — 48 direct column-types.ts tests, 2 for the CSV whitespace fix)
  • @sim/testing suite: 39 passing
  • No behavior change for the 6 existing column types except the CSV whitespace fix

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 30, 2026 9:59pm

Request Review

@cursor

cursor Bot commented Jul 30, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches core row validation, coercion, SQL filtering/sorting casts, and column type-change compatibility across the table stack; behavior is intended to be equivalent aside from the CSV whitespace fix, but regressions would affect writes, imports, and schema migrations.

Overview
Introduces column-types.ts, a registry where each column type defines SQL cast, parse, validate, format, and type-conversion compatibility in one place, keyed off COLUMN_TYPES so a missing type fails at compile time.

validation.ts, sql.ts, and columns/service.ts no longer duplicate large switch blocks; they delegate to parseColumnValue, isValidColumnValue, sqlCastForColumnType, and isValueCompatibleWithColumnType. resolveSelectOptionId and splitMultiSelectInput move from validation.ts into select-values.ts so select logic stays shared without pulling @sim/db into the pure registry.

CSV import fixes type drift: coercion targets use ColumnType derived from COLUMN_TYPES (includes select), inference uses a separate InferableColumnType, whitespace-only number cells import as null instead of 0, and select CSV values pass through as text until schema coercion. The testing factory’s TableColumnType adds select. Large column-types.test.ts coverage plus import/select test updates.

Reviewed by Cursor Bugbot for commit a15b7d4. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR centralizes table column behavior while preserving existing behavior for all registered column types.

  • Adds a registry for SQL casting, parsing, validation, formatting, and conversion compatibility.
  • Routes validation, SQL generation, and column conversion through the registry.
  • Consolidates select-value helpers into a dependency-light module.
  • Corrects CSV and test-factory type unions to include select columns.
  • Treats whitespace-only numeric CSV cells as empty instead of zero.

Confidence Score: 5/5

The PR appears safe to merge with no actionable behavioral, build, data-integrity, or security defects identified.

The registered column types retain their previous coercion, validation, compatibility, and SQL-cast behavior, while the CSV changes correctly feed select values into schema-level resolution and prevent whitespace-only numbers from becoming zero.

Important Files Changed

Filename Overview
apps/sim/lib/table/column-types.ts Introduces the six-type behavior registry and preserves the prior parsing, validation, SQL-cast, and conversion semantics for registered types.
apps/sim/lib/table/validation.ts Replaces duplicated parsing and validation switches with registry delegation without changing behavior for supported schemas.
apps/sim/lib/table/columns/service.ts Delegates type-conversion compatibility checks to behavior definitions equivalent to the removed switch branches.
apps/sim/lib/table/import.ts Aligns CSV coercion types with supported column types, passes select text to schema-level resolution, and maps whitespace-only numeric cells to null.
apps/sim/lib/table/select-values.ts Moves select option resolution and multi-select splitting into a shared pure helper module with equivalent behavior.
apps/sim/lib/table/sql.ts Delegates numeric and timestamp SQL cast selection to the registry while preserving generated query behavior.
packages/testing/src/factories/table.factory.ts Aligns testing fixtures with the production column-type union by supporting select columns.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Input[Raw cell value] --> Registry[Column type registry]
  Registry --> Parse[Parse and coerce]
  Registry --> Validate[Validate stored value]
  Registry --> Format[Format display value]
  Registry --> Compatible[Check type conversion]
  Registry --> Cast[Select SQL cast]
  Parse --> Persist[Row persistence]
  Validate --> Persist
  Compatible --> Migration[Column type migration]
  Cast --> Query[Filter and sort query]
Loading

Reviews (1): Last reviewed commit: "fix(testing): add missing select type to..." | Re-trigger Greptile

j15z and others added 6 commits July 30, 2026 14:52
Each column type's SQL cast, parse, validate, format, and conversion-
compatibility rules were implemented as independent switch statements
scattered across sql.ts, validation.ts, and columns/service.ts. Adding
a type meant hand-updating every switch, and a missed one failed
silently and differently depending which switch it was.

column-types.ts is the single per-type definition those switches will
delegate to, keyed by a Record typed against COLUMN_TYPES so a missing
entry is a compile error instead of a runtime surprise.

select-values.ts gains resolveSelectOptionId/splitMultiSelectInput
(moved here rather than importing validation.ts, which pulls in
@sim/db and would taint or cycle with this otherwise-pure module) so
the registry's select behavior has a shared, pure home to depend on.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
jsonbCastForType's switch is replaced by a delegate to the new
registry's sqlCastForColumnType, so a new column type's sort/filter
cast only needs to be declared once, in column-types.ts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…istry

coerceValueToColumnType and validateRowAgainstSchema's switches are
replaced by delegates to the registry's parse/isValidValue, so a new
column type's coercion and shape-check rules only need to be declared
once. The now-dead optionIds helper is removed, and
resolveSelectOptionId/splitMultiSelectInput move to select-values.ts
(their tests move with them) now that the registry depends on them
living there instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… registry

isValueCompatibleWithType's switch — the gate updateColumnType checks
before committing a column's type change — is replaced by a delegate
to the registry's isValueCompatibleWithColumnType, so a new column
type's conversion rules only need to be declared once.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tespace bug

CsvColumnType was a hand-duplicated, narrower copy of COLUMN_TYPES and
had silently drifted to exclude 'select' — papered over at its one
call site with an unsafe `as CsvColumnType` cast. Split it into two
honestly-scoped types: ColumnType (= COLUMN_TYPES, what a CSV cell's
target column can actually be) and InferableColumnType (the 4 types
inferColumnType can actually guess from raw text, declared
independently so it can't silently inherit types it was never taught
to detect).

Also fixes a real divergence found in the process: coerceValue's
number case ran Number(value) without guarding whitespace-only input
first, so a blank CSV cell imported as 0 instead of null.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
TableColumnType had also drifted out of sync with COLUMN_TYPES,
missing 'select'. It can't import COLUMN_TYPES to derive itself
(packages/* can't import apps/*), so it stays hand-maintained —
documented in place so the next drift is at least explained.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@j15z
j15z force-pushed the feat/advanced-table-column-types branch from cefc034 to a15b7d4 Compare July 30, 2026 22:00

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a15b7d4. Configure here.

* column type" and "every type we can guess from raw text" are different,
* independently-sized questions. See `InferableColumnType`.
*/
export type ColumnType = (typeof COLUMN_TYPES)[number]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Duplicate ColumnType barrel export

Medium Severity

The new ColumnType export in import.ts duplicates an existing ColumnType alias already available from types.ts (via ColumnDefinition['type']). This redundancy causes a name collision when both are re-exported from the barrel, leading to an ambiguous export.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a15b7d4. Configure here.

@j15z

j15z commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

#6106

@j15z j15z closed this Jul 30, 2026
@j15z
j15z deleted the feat/advanced-table-column-types branch July 30, 2026 22:22
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