Skip to content

Micro-optimize table-core#6347

Draft
aquapi wants to merge 15 commits into
TanStack:betafrom
aquapi:beta
Draft

Micro-optimize table-core#6347
aquapi wants to merge 15 commits into
TanStack:betafrom
aquapi:beta

Conversation

@aquapi

@aquapi aquapi commented Jun 25, 2026

Copy link
Copy Markdown

🎯 Changes

Mainly change array methods like forEach/filter to c-style loops, reduce closures and make some code easier to understand.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm test:pr.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of special numeric values during sorting, so non-finite numbers are treated more consistently.
    • Aggregations now behave more reliably across numeric, empty, and mixed-value inputs.
  • Refactor

    • Optimized several table operations behind the scenes for better performance and maintainability.
    • Refined column setup, row sorting, memoization, and tree-flattening logic without changing public APIs.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9b636b8c-b1f5-4dcb-a420-8fe600065fcc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR refactors several table-core helpers: column construction and defaults, sorting preparation, aggregation reducers, column flattening, and memoization logic. It also changes numeric string handling in sort functions and column.id string coercion.

Changes

Table core internal updates

Layer / File(s) Summary
Column ids and flat columns
packages/table-core/src/core/columns/constructColumn.ts, packages/table-core/src/core/columns/coreColumnsFeature.utils.ts
column.id now uses string concatenation, and column_getFlatColumns now builds descendants first before prepending the current column.
Default column defs and recursive normalization
packages/table-core/src/core/columns/coreColumnsFeature.utils.ts
Shared default header and cell resolvers are defined, table_getDefaultColumnDef merges feature defaults and defaultColumn with Object.assign, and grouped columns are normalized through table_getAllColumns_recurseColumns.
Sort normalization and row model
packages/table-core/src/features/row-sorting/createSortedRowModel.ts, packages/table-core/src/fns/sortFns.ts
toString now returns an empty string for non-finite numbers, and sorted row model preparation builds sortable metadata in one pass before recursively sorting with explicit parameters.
Aggregation reducers
packages/table-core/src/fns/aggregationFns.ts
sum, min, max, extent, mean, and median now use index-based loops and preallocated control flow while keeping their existing numeric filtering and return behavior.
Flattening and memo dependency checks
packages/table-core/src/utils.ts
flattenBy delegates to a recursive helper, and memo compares dependency tuples with explicit length and element checks before invoking the wrapped function.
tableMemo debug wiring
packages/table-core/src/utils.ts
tableMemo now derives debug flags and cache state separately, uses noopCallback as a fallback handler, formats timing output with padStart, and assembles instrumentation callbacks into allOptions for both development and non-development paths.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • TanStack/table#6310: Overlaps the same packages/table-core/src/fns/sortFns.ts sort normalization codepath.

Poem

I hopped through columns, neat and small,
And sorted rows stood tall and tall.
I nibbled loops and memo trees,
Then whispered padStart to the breeze.
Now table-core hums soft as clover.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the PR’s performance-focused changes in table-core.
Docstring Coverage ✅ Passed Docstring coverage is 82.35% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nx-cloud

nx-cloud Bot commented Jun 25, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 30aa208

Command Status Duration Result
nx run-many --targets=test:eslint,test:sherif,t... ✅ Succeeded 8m 32s View ↗

☁️ Nx Cloud last updated this comment at 2026-06-27 01:43:26 UTC

@KevinVandy

Copy link
Copy Markdown
Member

I'm open to optimizations like this, but could we split them up by topic (sorting/aggregation/filtering/etc.), have some regression tests if not already there, and attempt to document improvements with some kind of measurement?

@aquapi

aquapi commented Jun 25, 2026

Copy link
Copy Markdown
Author

@KevinVandy how do u want me to split these changes? I think they are small enough to fit in a single PR no?

I will create a repo later to benchmark this branch vs beta branch when this PR is ready for review :)

@pkg-pr-new

pkg-pr-new Bot commented Jun 25, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/angular-table@6347

@tanstack/angular-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/angular-table-devtools@6347

@tanstack/lit-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/lit-table@6347

@tanstack/match-sorter-utils

npm i https://pkg.pr.new/TanStack/table/@tanstack/match-sorter-utils@6347

@tanstack/preact-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/preact-table@6347

@tanstack/preact-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/preact-table-devtools@6347

@tanstack/react-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/react-table@6347

@tanstack/react-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/react-table-devtools@6347

@tanstack/solid-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/solid-table@6347

@tanstack/solid-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/solid-table-devtools@6347

@tanstack/svelte-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/svelte-table@6347

@tanstack/table-core

npm i https://pkg.pr.new/TanStack/table/@tanstack/table-core@6347

@tanstack/table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/table-devtools@6347

@tanstack/vue-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/vue-table@6347

@tanstack/vue-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/vue-table-devtools@6347

commit: 55ad6b2

@nx-cloud nx-cloud 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.

Important

At least one additional CI pipeline execution has run since the conclusion below was written and it may no longer be applicable.

Nx Cloud is proposing a fix for your failed CI:

We moved the @ts-expect-error comment in utils.ts to the line preceding the full ternary assignment, ensuring it suppresses type errors for both the fn(...deps) and fn() branches. Previously, the comment was placed inline inside the expression and only covered the immediately following line, leaving the fn() call exposed to TS2345. This single-line restructure fixes the type check failure without altering any runtime behaviour.

Tip

We verified this fix by re-running @tanstack/table-core:test:types.

Warning

The suggested diff is too large to display here, but you can view it on Nx Cloud ↗


Because this branch comes from a fork, it is not possible for us to apply fixes directly, but you can apply the changes locally using the available options below.

Apply changes locally with:

npx nx-cloud apply-locally PvU7-XFGo

Apply fix locally with your editor ↗   View interactive diff ↗



🎓 Learn more about Self-Healing CI on nx.dev

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/table-core/src/fns/aggregationFns.ts (1)

136-184: 🎯 Functional Correctness | 🟡 Minor

Add tests for the mean/median edge cases.
Cover empty input, single-row input, odd/even medians, numeric-string coercion in mean, and mixed numeric/non-numeric median inputs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/table-core/src/fns/aggregationFns.ts` around lines 136 - 184, Add
tests around aggregationFn_mean and aggregationFn_median to cover the requested
edge cases. In the aggregationFns test coverage, verify mean handles empty
leafRows, a single row, and numeric-string coercion, and verify median handles
empty input, single-row input, odd/even lengths, and returns undefined for mixed
numeric/non-numeric values. Use the existing aggregationFn_mean and
aggregationFn_median symbols so the tests stay tied to the current
implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/table-core/src/core/columns/coreColumnsFeature.utils.ts`:
- Around line 106-116: The built-in defaults from DefaultColumnDef are only on
the prototype in constructColumn’s defaultColumn, so they are dropped when
constructColumn later spreads the object and loses header/cell. Fix this by
making the default header/cell values own properties on the object returned from
coreColumnsFeature.utils.ts, or by changing constructColumn to preserve
inherited defaults before merging columnDef. Use the constructColumn and
DefaultColumnDef symbols to locate the merge path and ensure defaultColumn
carries the built-in values as enumerable own properties.

In `@packages/table-core/src/features/row-sorting/createSortedRowModel.ts`:
- Around line 154-167: The sorted row model is appending nested descendants to
sortedFlatRows before their parent, so flatRows no longer matches the order of
the returned rows. Update createSortedRowModel/sortData so each cloned parent
row is pushed into sortedFlatRows before recursing into row.subRows, while still
preserving the prototype cloning behavior and recursive sorting of subRows.
- Around line 59-67: The sorting filter in createSortedRowModel is preserving
the wrong value: availableSorting is meant to contain ColumnSort entries, but
the loop currently pushes the column object and loses the desc flag. Update the
logic in createSortedRowModel so the retained item comes from the original
sorting array entry (sorting[i]) rather than the column, while still using
table.getColumn(id) and column_getCanSort(column) to decide whether to keep it.
This ensures sortData continues to receive the full ColumnSort information,
including descending state.

In `@packages/table-core/src/utils.ts`:
- Around line 165-177: The memoization logic in the utility that compares
dependencies is treating an initial empty array as already cached, so a
zero-dependency memo can return before its first computation. Update the
dependency tracking in the compare/memo helper in utils.ts so the first run is
represented by a sentinel state (for example, undefined instead of []), and only
apply the “unchanged” early return after the function has actually computed
once. Keep the existing comparison flow around newDeps, deps, depsChanged, and
onAfterCompare, but ensure [] still triggers the initial fn execution and then
caches the result for later calls.

---

Outside diff comments:
In `@packages/table-core/src/fns/aggregationFns.ts`:
- Around line 136-184: Add tests around aggregationFn_mean and
aggregationFn_median to cover the requested edge cases. In the aggregationFns
test coverage, verify mean handles empty leafRows, a single row, and
numeric-string coercion, and verify median handles empty input, single-row
input, odd/even lengths, and returns undefined for mixed numeric/non-numeric
values. Use the existing aggregationFn_mean and aggregationFn_median symbols so
the tests stay tied to the current implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cf5e269f-ed1f-4995-af82-3b3abc9b72a1

📥 Commits

Reviewing files that changed from the base of the PR and between 64b3642 and 761a500.

📒 Files selected for processing (6)
  • packages/table-core/src/core/columns/constructColumn.ts
  • packages/table-core/src/core/columns/coreColumnsFeature.utils.ts
  • packages/table-core/src/features/row-sorting/createSortedRowModel.ts
  • packages/table-core/src/fns/aggregationFns.ts
  • packages/table-core/src/fns/sortFns.ts
  • packages/table-core/src/utils.ts

Comment thread packages/table-core/src/core/columns/coreColumnsFeature.utils.ts Outdated
Comment thread packages/table-core/src/features/row-sorting/createSortedRowModel.ts Outdated
Comment thread packages/table-core/src/utils.ts
@KevinVandy

KevinVandy commented Jun 26, 2026

Copy link
Copy Markdown
Member

I tried to run benchmarks on this PR to see what the improvements are, but there were too many bugs (regressions) in order to get useful measurements. The code rabbit feedback shows some of the breaking changes, here's some more from my local pr review

Reviewed PR #6347. I would block merge as-is.

Findings

Blocker: descending sorting is broken in
[createSortedRowModel.ts · L59]
. The rewrite pushes column as any into availableSorting instead of the original sort state entry, so sortEntry.desc is always missing later. Smoke check: beta sorted [1,3,2] desc as 3,2,1; PR sorted it as 1,2,3.

Blocker: default column header and cell renderers are dropped.
[coreColumnsFeature.utils.ts · L70]
puts defaults on a prototype, but
[constructColumn.ts · L48]
uses object spread, which only copies own properties. Smoke check: beta resolved { header: 'function', cell: 'function' }; PR resolved both as undefined.

Benchmark

I cloned benchmark-examples/examples/v9 to
[v9-pr-temp-6347]
and installed the PR preview URLs in all copied examples. Result JSON is here:
[pr-6347-v9-vs-pr-2026-06-26T00-47-20.471Z.json]
.

Run shape: v9 beta vs PR preview, sorting + aggregation, 30k and 300k rows, pipeline=operation, 3 measured iterations plus 1 warmup.

Sorting: all 12 descending cases had checksum mismatches. The 12 correct ascending cases were all slower on the PR, roughly 4% to 15% slower.
Aggregation: checksums matched. Results were mixed: 10/18 cases faster, 8/18 slower. At 300k rows, numeric aggregations improved in several cases, but unique regressed by about 44%.
I did not run full pnpm test:pr; I ran the package-preview smoke checks and focused benchmark. Existing local table/perf.md changes were left untouched.

@KevinVandy

Copy link
Copy Markdown
Member

@KevinVandy how do u want me to split these changes? I think they are small enough to fit in a single PR no?

I will create a repo later to benchmark this branch vs beta branch when this PR is ready for review :)

The reason I prefer smaller scoped PRs is because there can be a lot wrong with large PRs. Half of the code changes here are good, but the other half contain breaking changes. I can't accept the PR until it's all perfect. If it's broken up, at least by topic, like improving sorting performance, improving aggregation performance, and so on, then we could integrate the changes in smaller peices.

@aquapi

aquapi commented Jun 26, 2026

Copy link
Copy Markdown
Author

@KevinVandy I will finish all my changes first, do review and fixes until its ready then I'm gonna create an issue with many small PRs attached to it and close this PR

All my breaking changes are because I misread the original code

@aquapi

aquapi commented Jun 26, 2026

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@aquapi

aquapi commented Jun 26, 2026

Copy link
Copy Markdown
Author

@KevinVandy can I get your benchmark repo?

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.

2 participants