Skip to content

Commit 49afd60

Browse files
authored
refactor: rewrite defaultFilterRows in typescript and add tests (#19191)
1 parent bbd60b9 commit 49afd60

File tree

3 files changed

+157
-39
lines changed

3 files changed

+157
-39
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* Copyright IBM Corp. 2025
3+
*
4+
* This source code is licensed under the Apache-2.0 license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import { defaultFilterRows } from '../filter';
9+
10+
describe('defaultFilterRows', () => {
11+
const getCellId = (rowId, key) => `${rowId}-${key}`;
12+
13+
const headers = [{ key: 'name' }, { key: 'age' }, { key: 'active' }];
14+
const cellsById = {
15+
'1-name': { value: 'Alice' },
16+
'1-age': { value: 30 },
17+
'1-active': { value: true },
18+
'2-name': { value: 'Bob' },
19+
'2-age': { value: 40 },
20+
'2-active': { value: false },
21+
'3-name': { value: 'Charlie' },
22+
'3-age': { value: 25 },
23+
'3-active': { value: true },
24+
};
25+
const rowIds = ['1', '2', '3'];
26+
const defaultOptions = {
27+
rowIds,
28+
headers,
29+
cellsById,
30+
inputValue: '',
31+
getCellId,
32+
};
33+
34+
it('should filter rows by name', () => {
35+
const result = defaultFilterRows({
36+
...defaultOptions,
37+
inputValue: 'ali',
38+
});
39+
40+
expect(result).toEqual(['1']);
41+
});
42+
43+
it('should filter rows by number (coerced to string)', () => {
44+
const result = defaultFilterRows({
45+
...defaultOptions,
46+
inputValue: '40',
47+
});
48+
49+
expect(result).toEqual(['2']);
50+
});
51+
52+
it('should ignore boolean fields', () => {
53+
const result = defaultFilterRows({
54+
...defaultOptions,
55+
inputValue: 'true',
56+
});
57+
58+
expect(result).toEqual([]);
59+
});
60+
61+
it('should perform a case-insensitive search', () => {
62+
const result = defaultFilterRows({
63+
...defaultOptions,
64+
inputValue: 'CHARLIE',
65+
});
66+
67+
expect(result).toEqual(['3']);
68+
});
69+
70+
it('should return an empty array when nothing matches', () => {
71+
const result = defaultFilterRows({
72+
...defaultOptions,
73+
inputValue: 'xyz',
74+
});
75+
76+
expect(result).toEqual([]);
77+
});
78+
79+
it('should handle an empty `rowIds` array', () => {
80+
const result = defaultFilterRows({
81+
...defaultOptions,
82+
rowIds: [],
83+
inputValue: 'alice',
84+
});
85+
86+
expect(result).toEqual([]);
87+
});
88+
89+
it('should handle a missing cell gracefully', () => {
90+
const incompleteCellsById = { '1-name': { value: 'Alice' } };
91+
92+
const result = defaultFilterRows({
93+
...defaultOptions,
94+
rowIds: ['1'],
95+
cellsById: incompleteCellsById,
96+
inputValue: 'alice',
97+
});
98+
99+
expect(result).toEqual(['1']);
100+
});
101+
102+
it('should return all rows if `inputValue` is empty or only whitespace', () => {
103+
const emptyResult = defaultFilterRows(defaultOptions);
104+
const whitespaceResult = defaultFilterRows({
105+
...defaultOptions,
106+
inputValue: ' ',
107+
});
108+
109+
expect(defaultOptions.inputValue).toEqual('');
110+
expect(emptyResult).toEqual(rowIds);
111+
expect(whitespaceResult).toEqual(rowIds);
112+
});
113+
});

packages/react/src/components/DataTable/tools/filter.js

Lines changed: 0 additions & 39 deletions
This file was deleted.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Copyright IBM Corp. 2016, 2025
3+
*
4+
* This source code is licensed under the Apache-2.0 license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
/**
9+
* Filters row IDs based on whether any of the cell values in the row include
10+
* the input value as a substring. Boolean cell values are ignored.
11+
*/
12+
export const defaultFilterRows = ({
13+
rowIds,
14+
headers,
15+
cellsById,
16+
inputValue,
17+
getCellId,
18+
}: {
19+
/** Table row IDs. */
20+
rowIds: string[];
21+
/** Table headers. */
22+
headers: { key: string }[];
23+
/** Mapping of cell IDs to their corresponding cells. */
24+
cellsById: Record<string, { value: unknown }>;
25+
/** Input value to search for. */
26+
inputValue: string;
27+
/** Function that returns a cell ID given a row ID and a header. */
28+
getCellId: (rowId: string, header: string) => string;
29+
}): string[] => {
30+
const normalizedInput = inputValue.trim().toLowerCase();
31+
32+
if (!normalizedInput) return rowIds;
33+
34+
return rowIds.filter((rowId) =>
35+
headers.some(({ key }) => {
36+
const cellId = getCellId(rowId, key);
37+
const cell = cellsById[cellId];
38+
39+
if (typeof cell.value === 'boolean') return false;
40+
41+
return String(cell.value).toLowerCase().includes(normalizedInput);
42+
})
43+
);
44+
};

0 commit comments

Comments
 (0)