Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,18 @@ export function column_getAutoFilterFn<
const filterFns: Record<string, FilterFn<TFeatures, TData>> | undefined =
column.table._rowModelFns.filterFns

const firstRow = column.table.getCoreRowModel().flatRows[0]
const rows = column.table.getCoreRowModel().flatRows
let value: unknown

const value = firstRow ? firstRow.getValue(column.id) : undefined
// Nullable columns should be inferred from their first available value,
// rather than changing filter behavior based on which row happens to lead.
for (let i = 0; i < rows.length; i++) {
const rowValue = rows[i]!.getValue(column.id)
if (rowValue !== null && rowValue !== undefined) {
value = rowValue
break
}
}

let filterFnName: string

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,22 @@ describe('createFilteredRowModel', () => {
})
})

it('should auto-filter a nullable string column when the first value is null', () => {
type NullableTestRow = { name: string | null }
const table = constructTable<typeof features, NullableTestRow>({
features,
columns: [{ accessorKey: 'name', id: 'name' }],
data: [{ name: null }, { name: 'hello' }, { name: 'welcome' }],
initialState: {
columnFilters: [{ id: 'name', value: 'ell' }],
},
})

expect(
table.getFilteredRowModel().rows.map((row) => row.original.name),
).toEqual(['hello'])
})

describe('unresolvable global filter fn', () => {
afterEach(() => {
vi.unstubAllEnvs()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
constructTable,
filterFn_arrIncludes,
filterFn_equals,
filterFn_includesString,
filterFns,
} from '../../../../src'
import {
Expand Down Expand Up @@ -64,6 +65,19 @@ describe('column_getAutoFilterFn', () => {

expect(column_getAutoFilterFn(column)).toBe(filterFn_equals)
})

it('infers the filter from the first non-null column value', () => {
type NullableSample = { name: string | null }
const table = constructTable({
features,
columns: [{ accessorKey: 'name', id: 'name' }],
data: [{ name: null }, { name: 'hello' }] satisfies Array<NullableSample>,
})

expect(column_getAutoFilterFn(table.getColumn('name')!)).toBe(
filterFn_includesString,
)
})
})

// ---------------------------------------------------------------------------
Expand Down
Loading