Skip to content

Commit 6375971

Browse files
author
Junjia Huang
committed
fix: Fix the problem of null judgment error
1 parent d61b4ae commit 6375971

File tree

2 files changed

+151
-37
lines changed

2 files changed

+151
-37
lines changed

__tests__/utils/filter-data.spec.ts

+120-8
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,122 @@ describe('filterData function', () => {
8989
});
9090

9191
it('should return unfiltered data if no filters are provided', () => {
92-
const filters = [];
92+
const filters: CrudFilters = [];
9393
const filteredData = filterData(filters, unstructuredData);
9494
expect(filteredData).toEqual(unstructuredData);
9595
});
96+
97+
it('filters with nested structure', () => {
98+
const filters: CrudFilters = [
99+
{
100+
field: 'status.state', operator: 'eq', value: 'Normal',
101+
},
102+
{
103+
field: 'status.state', operator: 'in', value: [
104+
'InUpdate',
105+
'InRollback',
106+
],
107+
},
108+
{
109+
operator: 'and', value: [
110+
{
111+
field: 'metadata.deletionTimestamp', operator: 'nnull', value: true,
112+
},
113+
{
114+
field: 'status.state', operator: 'ne', value: 'DeleteFailed',
115+
},
116+
],
117+
},
118+
];
119+
const data: (Unstructured & { status: { state: string; } })[] = [
120+
{
121+
apiVersion: 'v1',
122+
kind: 'Pod',
123+
metadata: { name: 'Pod A', namespace: 'Namespace A' },
124+
status: {
125+
state: 'Normal',
126+
},
127+
},
128+
{
129+
apiVersion: 'v1',
130+
kind: 'Pod',
131+
metadata: { name: 'Pod B', namespace: 'Namespace B' },
132+
status: {
133+
state: 'InRollback',
134+
},
135+
},
136+
{
137+
apiVersion: 'v1',
138+
kind: 'Pod',
139+
metadata: { name: 'Pod C', namespace: 'Namespace A', deletionTimestamp: 'mock time' },
140+
status: {
141+
state: 'InUpgrade',
142+
},
143+
},
144+
];
145+
146+
expect(filterData([
147+
{
148+
operator: 'and',
149+
value: [
150+
filters[0],
151+
],
152+
},
153+
], data)).toEqual([{
154+
apiVersion: 'v1',
155+
kind: 'Pod',
156+
metadata: { name: 'Pod A', namespace: 'Namespace A' },
157+
status: {
158+
state: 'Normal',
159+
},
160+
}]);
161+
162+
expect(filterData([
163+
{
164+
operator: 'and',
165+
value: [
166+
filters[1],
167+
],
168+
},
169+
], data)).toEqual([{
170+
apiVersion: 'v1',
171+
kind: 'Pod',
172+
metadata: { name: 'Pod B', namespace: 'Namespace B' },
173+
status: {
174+
state: 'InRollback',
175+
},
176+
}]);
177+
178+
expect(filterData([
179+
{
180+
operator: 'and',
181+
value: [
182+
filters[2],
183+
],
184+
},
185+
], data)).toEqual([{
186+
apiVersion: 'v1',
187+
kind: 'Pod',
188+
metadata: { name: 'Pod C', namespace: 'Namespace A', deletionTimestamp: 'mock time' },
189+
status: {
190+
state: 'InUpgrade',
191+
},
192+
},]);
193+
194+
expect(filterData([
195+
{
196+
operator: 'and',
197+
value: filters,
198+
},
199+
], data)).toEqual([]);
200+
201+
expect(filterData([
202+
{
203+
operator: 'or',
204+
value: filters,
205+
},
206+
], data)).toEqual(data);
207+
});
96208
});
97209

98210
describe('evaluateFilter function', () => {
@@ -107,8 +219,8 @@ describe('evaluateFilter function', () => {
107219
total: 10,
108220
labels: ['label-1', 'label-2'],
109221
description: null,
110-
type: 'type-1'
111-
}
222+
type: 'type-1',
223+
},
112224
} as Unstructured;
113225

114226
test('handles "eq" operator', () => {
@@ -190,13 +302,13 @@ describe('evaluateFilter function', () => {
190302
});
191303

192304
test('handles "null" operator', () => {
193-
const result = evaluateFilter(mockItem, 'spec.description', 'null', null);
194-
expect(result).toBeTruthy();
305+
expect(evaluateFilter(mockItem, 'spec.description', 'null', null)).toBeTruthy();
306+
expect(evaluateFilter(mockItem, 'spec.non_exist_path', 'null', null)).toBeFalsy();
195307
});
196308

197309
test('handles "nnull" operator', () => {
198-
const result = evaluateFilter(mockItem, 'spec.total', 'nnull', null);
199-
expect(result).toBeTruthy();
310+
expect(evaluateFilter(mockItem, 'spec.total', 'nnull', null)).toBeTruthy();
311+
expect(evaluateFilter(mockItem, 'spec.non_exist_path', 'null', null)).toBeFalsy();
200312
});
201313

202314
test('handles "startswith" operator', () => {
@@ -238,4 +350,4 @@ describe('evaluateFilter function', () => {
238350
const result = evaluateFilter(mockItem, 'metadata.name', 'nendswiths', 'SERVICE');
239351
expect(result).toBeTruthy();
240352
});
241-
})
353+
});

src/utils/filter-data.ts

+31-29
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
1-
import { CrudFilters, CrudOperators, LogicalFilter } from '@refinedev/core';
1+
import { CrudFilter, CrudFilters, CrudOperators } from '@refinedev/core';
22
import _ from 'lodash';
33
import { Unstructured } from '../kube-api';
44

5+
function deepFilter(item: Unstructured, filter: CrudFilter): boolean {
6+
if ('field' in filter) {
7+
// Logical filter
8+
const { field, operator, value } = filter;
9+
return evaluateFilter(item, field, operator, value);
10+
} else {
11+
// Conditional filter
12+
const { operator, value } = filter;
13+
if (operator === 'or') {
14+
return value.some(subFilter => deepFilter(item, subFilter));
15+
} else if (operator === 'and') {
16+
return value.every(subFilter => deepFilter(item, subFilter));
17+
}
18+
}
19+
return true
20+
}
21+
522
export const filterData = (
623
filters: CrudFilters,
724
data: Unstructured[]
@@ -10,30 +27,7 @@ export const filterData = (
1027
return data;
1128
}
1229

13-
return data.filter(item => {
14-
return filters.every(filter => {
15-
if ('field' in filter) {
16-
// Logical filter
17-
const { field, operator, value } = filter;
18-
return evaluateFilter(item, field, operator, value);
19-
} else {
20-
// Conditional filter
21-
const { operator, value } = filter;
22-
if (operator === 'or') {
23-
return value.some(subFilter => {
24-
const { field, operator, value } = subFilter as LogicalFilter;
25-
return evaluateFilter(item, field, operator, value);
26-
});
27-
} else if (operator === 'and') {
28-
return value.every(subFilter => {
29-
const { field, operator, value } = subFilter as LogicalFilter;
30-
return evaluateFilter(item, field, operator, value);
31-
});
32-
}
33-
}
34-
return true;
35-
});
36-
});
30+
return data.filter(item => filters.every(filter => deepFilter(item, filter)));
3731
};
3832

3933
export function evaluateFilter(
@@ -92,10 +86,18 @@ export function evaluateFilter(
9286
return value[0] <= fieldValue && fieldValue <= value[1];
9387
case 'nbetween':
9488
return value[0] > fieldValue || fieldValue > value[1];
95-
case 'null':
96-
return fieldValue === null;
97-
case 'nnull':
98-
return fieldValue !== null;
89+
case 'null': {
90+
if (!_.has(item, field)) {
91+
return false;
92+
}
93+
return _.isNil(fieldValue);
94+
}
95+
case 'nnull': {
96+
if (!_.has(item, field)) {
97+
return false;
98+
}
99+
return !_.isNil(fieldValue)
100+
}
99101
case 'startswith':
100102
return fieldValue.startsWith(value);
101103
case 'nstartswith':

0 commit comments

Comments
 (0)