Column Definitions & Builders
Relevant source files
The following files were used as context for generating this wiki page:
Column Definitions & Builders constitute the core declarative layer of Better Tables. They allow developers to define table structures, data accessors, and UI behaviors once, which are then utilized by adapters to generate database queries and by UI components to render the table interface. The system transitions from a low-level fluent ColumnBuilder API to a flagship defineTable API that leverages path-based type inference for enhanced developer experience.
Sources: README.md:10-15, plans/011-table-definition-dx-design.md:38-45
Architecture Overview
The column definition system is structured as a multi-layered hierarchy. At the base is the ColumnBuilder, which provides the fluent interface for setting metadata, accessors, and validation. Above this layer are specialized builders for specific data types (Text, Number, Date, etc.), and the top-level betterTables factory which orchestrates the interaction between these definitions and the database adapters.
Builder Hierarchy and Data Flow
The flow of data starts with a declarative definition and results in a ColumnDefinition object, which is the internal contract used by the rest of the system.
The Flagship API: defineTable
The modern way to define columns is through defineTable, which utilizes a path-based approach. This allows for automatic relationship detection and JOIN generation by simply referencing dotted paths (e.g., profile.location).
Path-Based Inference
Path builders (accessible via the t argument in defineTable) provide autocomplete for valid fields and relationship paths based on the database schema. This ensures that the type system rejects paths that the runtime adapter cannot resolve.
- t.text('path'): Maps to string-valued paths.
- t.number('path'): Maps to numeric paths.
- t.count('relation'): A derived aggregate column that counts related records.
Sources: plans/011-table-definition-dx-design.md:73-88, README.md:41-57, plans/060-derived-aggregate-columns.md:158-165
Low-Level Fluent API: ColumnBuilder
The ColumnBuilder class provides a chainable interface for granular configuration of individual columns. It manages metadata, display names, and validation rules.
Key Configuration Methods
| Method | Description | Source |
|---|---|---|
.id(id) | Sets the unique identifier for the column. Required for raw builders. | packages/core/src/builders/column-builder.ts:106 |
.displayName(name) | Sets the human-readable label for the UI. | packages/core/src/builders/column-builder.ts:121 |
.accessor(fn) | Defines how to extract the value from the row data. | packages/core/src/builders/column-builder.ts:137 |
.filterable(bool) | Toggles visibility in the filter UI. Defaults to true. | packages/core/src/builders/column-builder.ts:168 |
.sortable(bool) | Toggles sorting capability for the column. Defaults to true. | packages/core/src/builders/column-builder.ts:153 |
.editable(config) | Enables inline cell editing (Text, Number, Option, Boolean, Date). | plans/053-editable-cells.md:126-135 |
.validation(rules) | Attaches validation rules that run before writes or filters. | plans/005-builder-type-inference.md:65-68 |
Derived and Aggregate Columns
Aggregates are a specialized form of column definition that allow server-side derivations like postsCount. These are serializable and sent to the adapter to be lowered into correlated subqueries.
Specialized Column Types
Better Tables provides specific builders that initialize columns with sensible defaults and appropriate operators for their data types.
Standard Column Types
- Text: Supports operators like
contains,startsWith, andregex. Defaults to non-numeric formatting. - Number: Includes
.range(min, max)and support for numeric operators likegreaterThan. - Option: Used for enums or fixed sets of values. It allows defining
.options([...])with values and labels. - Boolean: Optimized for true/false toggles in the UI.
- Date: Supports date-specific operators like
before,after, andbetween.
Sources: plans/005-builder-type-inference.md:45-55, README.md:150-160, plans/060-derived-aggregate-columns.md:160-168
Honest Defaults for Computed Columns
Columns defined as t.computed or t.custom default to filterable: false and sortable: false because they are client-side derivations without a direct database backing. In contrast, server-side aggregate columns (t.count) remain filterable and sortable by default.
Sources: plans/060-derived-aggregate-columns.md:165-172
Type Inference & Safety
The system uses advanced TypeScript features to ensure type safety from the database to the UI.
- Accessor Inference:
.accessor()infers theTValuefrom the return type of the provided function. - Option Union Checking: For
optioncolumns, the.options()method checks that provided values exist within the union of the accessor's return type. - Path Validation: Within
defineTable, thet.*builders validate that the provided string path exists on the row type or its relations.
Sources: plans/005-builder-type-inference.md:105-125, plans/011-table-definition-dx-design.md:145-160
Summary
Column Definitions & Builders provide the essential metadata that powers the Better Tables ecosystem. By transitioning from low-level fluent builders to the path-based defineTable API, the project simplifies complex relational data management. The system ensures that every column definition is technically accurate and type-safe, enabling automatic JOIN generation and consistent UI behavior across various data types and derived aggregates.