Skip to content

fix(table-core): correct number-range, filter-depth, autoRemove, and custom faceting semantics - #6503

Merged
KevinVandy merged 2 commits into
betafrom
fix/filtering-semantics
Aug 3, 2026
Merged

fix(table-core): correct number-range, filter-depth, autoRemove, and custom faceting semantics#6503
KevinVandy merged 2 commits into
betafrom
fix/filtering-semantics

Conversation

@KevinVandy

@KevinVandy KevinVandy commented Aug 3, 2026

Copy link
Copy Markdown
Member

Four filtering-semantics fixes from the beta-window triage (cluster 5), with new unit/implementation tests and guide updates across all 10 framework docs. No changeset (handled at release assembly).

Changes

  • filterFn_inNumberRange only matches real numbers. JS loose relational coercion let null, '', and booleans slip into a numeric range (null >= 0 && null <= 20 is true), so the auto-selected number filter leaked empty rows into [0, max] ranges on nullable numeric columns. Numeric strings also stop matching; between/betweenInclusive remain the hybrid string/number range filters.
  • maxLeafRowFilterDepth keeps flatRows/rowsById complete. When the root-down recursion stops at the max depth, the kept rows' unfiltered descendants stay visible through row.subRows but never entered the flat arrays, under-counting facets after filtering. Truncated subtrees now join both. Scoped to the root-down path like the original PR; the leaf-up path drops truncated subRows entirely (pre-existing behavior) and is left as a possible follow-up.
  • A provided autoRemove is authoritative. shouldAutoRemoveFilter no longer ORs the hardcoded empty-string check over a custom autoRemove, so custom filter functions can keep '' as a filter value. undefined always clears (the universal setFilterValue(undefined) sentinel). Built-ins are unaffected: they all test falsy values themselves.
  • Custom faceted factories are no longer frozen. The API-layer memoDeps in columnFacetingFeature duplicated the stock factories' internal tableMemo (same dependencies), so for custom facetedUniqueValues/facetedMinMaxValues/facetedRowModel implementations it only cached them against inputs they do not depend on. The API layer is now a plain pass-through like every other row model: stock results stay referentially stable and compute once per invalidation (pinned by Map-identity tests), the no-factory fallback keeps a stable empty Map, and custom factories own their memoization (tableMemo is exported). The faceting guides document the contract, and the server-side examples now read live data through table.options.meta instead of stale closures.

Closes

Supersedes

Verification

  • table-core: 1,267 tests pass (12 new), tsc + eslint clean.
  • Full repo pnpm test:lib (18 projects) green.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Numeric range filters now reject non-numeric and invalid values consistently.
    • Custom filter removal rules now preserve retained values, including empty strings; undefined always clears the filter.
    • Hierarchical filtering now retains visible descendants when depth limits are reached.
    • Faceting reads now reflect current data without unintended result caching.
  • Documentation

    • Clarified faceting behavior and filtering rules across supported framework guides.
  • Tests

    • Added coverage for filtering, faceting stability, descendant handling, and numeric validation.

…custom faceting semantics

Four filtering-semantics bugs from the beta triage.

filterFn_inNumberRange matched non-numeric values: JavaScript's loose
relational coercion let null, '', and booleans slip into a numeric range
(null >= 0 && null <= 20 is true), so the auto-selected number filter
leaked empty rows into a [0, max] range on nullable numeric columns. The
filter now only matches real numbers. Numeric strings also stop
matching; `between`/`betweenInclusive` remain the hybrid string/number
range filters.

When maxLeafRowFilterDepth stopped the root-down filter recursion, the
kept rows' unfiltered descendants stayed visible through row.subRows but
never entered flatRows or rowsById, so facet counts and other
flat-representation consumers under-counted after filtering. Truncated
subtrees now join both. Scoped to the root-down path; the leaf-up path
drops truncated subRows entirely (pre-existing behavior) and is left as
a possible follow-up.

shouldAutoRemoveFilter ORed a hardcoded empty-string check over a custom
autoRemove, so a filter function that wanted to keep '' as a filter
value could not. A provided autoRemove is now authoritative for defined
values; undefined always clears, since it is the universal
setFilterValue(undefined) sentinel. Built-ins are unaffected: they all
test falsy values themselves.

Custom facetedUniqueValues/facetedMinMaxValues/facetedRowModel factories
were frozen by a redundant memoization layer in columnFacetingFeature.
The stock factories already memoize internally with the same
dependencies, so the API-layer memoDeps only served to cache custom
implementations against inputs they do not depend on. The API layer is
now a plain pass-through like every other row model: stock results stay
referentially stable and compute once per invalidation (pinned by
Map-identity tests), the no-factory fallback keeps a stable empty Map,
and custom factories own their memoization (tableMemo is exported for
this). The faceting guides now document the contract and their
server-side examples read live data through table.options.meta instead
of stale closures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 77407c4e-d842-4cb3-848d-eee9e07abeec

📥 Commits

Reviewing files that changed from the base of the PR and between eed3da9 and e4ea722.

📒 Files selected for processing (4)
  • docs/framework/alpine/guide/column-faceting.md
  • docs/framework/ember/guide/column-faceting.md
  • docs/framework/lit/guide/column-faceting.md
  • docs/framework/octane/guide/column-faceting.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • docs/framework/octane/guide/column-faceting.md
  • docs/framework/ember/guide/column-faceting.md
  • docs/framework/alpine/guide/column-faceting.md

📝 Walkthrough

Walkthrough

The change updates table-core filtering and faceting behavior. It adds tests for numeric ranges, custom autoRemove, truncated descendants, and faceting evaluation. Framework guides and beta triage documentation describe the updated behavior.

Changes

Cluster 5 behavior updates

Layer / File(s) Summary
Faceting evaluation and live server data
packages/table-core/src/features/column-faceting/*, packages/table-core/tests/implementation/features/column-faceting/*, docs/framework/*/guide/column-faceting.md
Faceting APIs invoke utilities directly. Custom factories resolve once, while returned functions run on each read. Fallback empty maps remain referentially stable. Framework examples read current server data through table metadata.
Authoritative autoRemove behavior
packages/table-core/src/features/column-filtering/columnFilteringFeature.types.ts, packages/table-core/src/features/column-filtering/columnFilteringFeature.utils.ts, packages/table-core/tests/unit/features/column-filtering/*, docs/framework/*/guide/column-filtering.md
Custom autoRemove controls removal for defined values. undefined always clears the filter. Retained empty strings remain in filter state.
Numeric range validation
packages/table-core/src/features/column-filtering/filterFns.ts, packages/table-core/tests/unit/fns/filterFns.test.ts
Number-range filtering rejects non-number and NaN row values before range comparison.
Depth-truncated descendants
packages/table-core/src/features/column-filtering/filterRowsUtils.ts, packages/table-core/tests/implementation/features/column-filtering/createFilteredRowModel.test.ts, beta-window-triage.md
Root-down filtering includes retained descendants in flatRows and rowsById when filtering stops at the configured depth. Beta triage records the Cluster 5 fixes as implemented.

Estimated code review effort: 4 (Complex) | ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the four primary table-core semantic fixes.
Linked Issues check ✅ Passed The changes address all linked issues: numeric ranges, depth-limited descendants, autoRemove precedence, and custom faceting updates.
Out of Scope Changes check ✅ Passed The code, tests, documentation, and triage updates directly support the stated fixes and linked issue requirements.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/filtering-semantics

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 Aug 3, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit eed3da9

Command Status Duration Result
nx affected --targets=test:eslint,test:sherif,t... ✅ Succeeded 6m 10s View ↗
nx run-many --targets=build --exclude=examples/** ✅ Succeeded 53s View ↗

☁️ Nx Cloud last updated this comment at 2026-08-03 04:13:47 UTC

@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: 3

🤖 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 `@beta-window-triage.md`:
- Around line 114-117: Split the step-4 entry so PR `#6443` remains associated
only with the `#5801` expansion-reset work, and move the Cluster 5 filtering
issues (`#6007`, `#5987`, `#6101`, and `#6081`) into a separate step. If a consolidated
Cluster 5 PR is known, reference it there; otherwise state that its vehicle is
pending.

In `@docs/framework/alpine/guide/column-faceting.md`:
- Around line 286-287: Update the faceting example’s factory functions so they
no longer close over the one-time serverFacets value. Expose current server
facet data through a meta getter, then read table.options.meta?.serverFacets
inside both returned faceting functions so subsequent server responses update
both APIs.

In `@docs/framework/ember/guide/column-faceting.md`:
- Around line 307-308: Update the custom faceting examples so each returned
resolver reads current facet data inside its function rather than capturing a
one-time fetch result in the factory closure. Apply this to
docs/framework/ember/guide/column-faceting.md lines 307-308,
docs/framework/lit/guide/column-faceting.md lines 290-291, and
docs/framework/octane/guide/column-faceting.md lines 268-269: populate
uniqueValueMap and return ranges from table.options.meta, a reactive store, or
another live source, preserving immediate updates to server facets.
🪄 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 Plus

Run ID: 7dce26c9-9091-4edf-971f-220b888df3e1

📥 Commits

Reviewing files that changed from the base of the PR and between aad2c29 and eed3da9.

📒 Files selected for processing (31)
  • beta-window-triage.md
  • docs/framework/alpine/guide/column-faceting.md
  • docs/framework/alpine/guide/column-filtering.md
  • docs/framework/angular/guide/column-faceting.md
  • docs/framework/angular/guide/column-filtering.md
  • docs/framework/ember/guide/column-faceting.md
  • docs/framework/ember/guide/column-filtering.md
  • docs/framework/lit/guide/column-faceting.md
  • docs/framework/lit/guide/column-filtering.md
  • docs/framework/octane/guide/column-faceting.md
  • docs/framework/octane/guide/column-filtering.md
  • docs/framework/preact/guide/column-faceting.md
  • docs/framework/preact/guide/column-filtering.md
  • docs/framework/react/guide/column-faceting.md
  • docs/framework/react/guide/column-filtering.md
  • docs/framework/solid/guide/column-faceting.md
  • docs/framework/solid/guide/column-filtering.md
  • docs/framework/svelte/guide/column-faceting.md
  • docs/framework/svelte/guide/column-filtering.md
  • docs/framework/vue/guide/column-faceting.md
  • docs/framework/vue/guide/column-filtering.md
  • packages/table-core/src/features/column-faceting/columnFacetingFeature.ts
  • packages/table-core/src/features/column-faceting/columnFacetingFeature.utils.ts
  • packages/table-core/src/features/column-filtering/columnFilteringFeature.types.ts
  • packages/table-core/src/features/column-filtering/columnFilteringFeature.utils.ts
  • packages/table-core/src/features/column-filtering/filterFns.ts
  • packages/table-core/src/features/column-filtering/filterRowsUtils.ts
  • packages/table-core/tests/implementation/features/column-faceting/createFacetedRowModels.test.ts
  • packages/table-core/tests/implementation/features/column-filtering/createFilteredRowModel.test.ts
  • packages/table-core/tests/unit/features/column-filtering/columnFilteringFeature.utils.test.ts
  • packages/table-core/tests/unit/fns/filterFns.test.ts

Comment thread beta-window-triage.md
Comment on lines +114 to +117
4. **[#6443](https://github.com/TanStack/table/pull/6443)** rebase + merge ([#5801](https://github.com/TanStack/table/issues/5801)). (Cluster 5 — [#6007](https://github.com/TanStack/table/issues/6007), [#5987](https://github.com/TanStack/table/issues/5987), [#6101](https://github.com/TanStack/table/issues/6101), [#6081](https://github.com/TanStack/table/issues/6081) — implemented 2026-08-02, pending PR; close [#6313](https://github.com/TanStack/table/pull/6313)/[#6361](https://github.com/TanStack/table/pull/6361) as superseded when it lands.)
5. `_valuesCache`/`defaultColumn` invalidation pair ([#5363](https://github.com/TanStack/table/issues/5363)/[#4485](https://github.com/TanStack/table/issues/4485) + [#5275](https://github.com/TanStack/table/issues/5275)).
6. Sorting defaults ([#4946](https://github.com/TanStack/table/issues/4946) one-liner; [#5147](https://github.com/TanStack/table/issues/5147)/[#5832](https://github.com/TanStack/table/issues/5832) auto-dir sampling).
7. Remaining semantics decisions: [#5909](https://github.com/TanStack/table/issues/5909) (undefined = uncontrolled), [#5778](https://github.com/TanStack/table/issues/5778), [#6101](https://github.com/TanStack/table/issues/6101), [#6081](https://github.com/TanStack/table/issues/6081). (Cluster 3 — [#6115](https://github.com/TanStack/table/issues/6115), [#5833](https://github.com/TanStack/table/issues/5833), [#4939](https://github.com/TanStack/table/issues/4939), [#6136](https://github.com/TanStack/table/issues/6136) — implemented 2026-08-02, pending PR.)
7. Remaining semantics decisions: [#5909](https://github.com/TanStack/table/issues/5909) (undefined = uncontrolled), [#5778](https://github.com/TanStack/table/issues/5778). (Cluster 3 — [#6115](https://github.com/TanStack/table/issues/6115), [#5833](https://github.com/TanStack/table/issues/5833), [#4939](https://github.com/TanStack/table/issues/4939), [#6136](https://github.com/TanStack/table/issues/6136) — implemented 2026-08-02, pending PR.)

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file info =="
wc -l beta-window-triage.md
sed -n '1,140p' beta-window-triage.md | nl -ba

echo
echo "== occurrences of `#6443`, `#5801`, Cluster 5, step 4 =="
rg -n "(`#6443`|`#5801`|Cluster 5|step 4|filtering|defaultColumn|_valuesCache|sorting|Cluster 3)" beta-window-triage.md

Repository: TanStack/table

Length of output: 234


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file info =="
wc -l beta-window-triage.md

echo
echo "== file excerpt =="
python3 - <<'PY'
from pathlib import Path
p = Path("beta-window-triage.md")
for i, line in enumerate(p.read_text(encoding="utf-8").splitlines(), 1):
    if 1 <= i <= 140:
        print(f"{i:4d}: {line}")
PY

echo
echo "== occurrences of key references =="
rg -n "(`#6443`|`#5801`|Cluster 5|step 4|filtering|defaultColumn|_valuesCache|sorting|Cluster 3)" beta-window-triage.md || true

echo
echo "== parse references by line =="
python3 - <<'PY'
from pathlib import Path
import re
text = Path("beta-window-triage.md").read_text(encoding="utf-8")
for match in re.finditer(r"#(\d{3,4})", text):
    line = text.count("\n", 0, match.start()) + 1
    line_text = text.splitlines()[line-1]
    print(f"line {line}: #{match.group(1)}: {line_text[:120]}")
PY

Repository: TanStack/table

Length of output: 50370


Split or relabel the step-4 line.

Step 4 currently merges PR #6443 (#5801 expansion reset) and also describes Cluster 5 filtering fixes (#6007, #5987, #6101, #6081). The filtering fixes do not have a consolidated PR listed, so maintainers may treat the wrong PR as the vehicle for Cluster 5. Split this into separate steps, or replace the parenthetical with the actual Cluster 5 PR when available.

🤖 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 `@beta-window-triage.md` around lines 114 - 117, Split the step-4 entry so PR
`#6443` remains associated only with the `#5801` expansion-reset work, and move the
Cluster 5 filtering issues (`#6007`, `#5987`, `#6101`, and `#6081`) into a separate
step. If a consolidated Cluster 5 PR is known, reference it there; otherwise
state that its vehicle is pending.

Comment thread docs/framework/alpine/guide/column-faceting.md
Comment thread docs/framework/ember/guide/column-faceting.md
@pkg-pr-new

pkg-pr-new Bot commented Aug 3, 2026

Copy link
Copy Markdown
More templates

@tanstack/alpine-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/alpine-table@6503

@tanstack/angular-table

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

@tanstack/angular-table-devtools

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

@tanstack/ember-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/ember-table@6503

@tanstack/lit-table

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

@tanstack/match-sorter-utils

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

@tanstack/octane-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/octane-table@6503

@tanstack/preact-table

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

@tanstack/preact-table-devtools

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

@tanstack/react-table

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

@tanstack/react-table-devtools

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

@tanstack/solid-table

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

@tanstack/solid-table-devtools

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

@tanstack/svelte-table

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

@tanstack/table-core

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

@tanstack/table-devtools

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

@tanstack/vue-table

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

@tanstack/vue-table-devtools

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

commit: e4ea722

…ng examples

The alpine, ember, lit, and octane guides captured a one-time `await fetch`
result in the factory closure, so later server responses could never reach
either faceting API. They now read through `table.options.meta` inside the
returned functions like the other framework guides, using each framework's
own reactive idiom.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@KevinVandy
KevinVandy merged commit 8fcfd34 into beta Aug 3, 2026
9 checks passed
@KevinVandy
KevinVandy deleted the fix/filtering-semantics branch August 3, 2026 04:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant