mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-22 08:53:46 +08:00
✨ feat(datagrid): 支持列值多选筛选
This commit is contained in:
@@ -73,6 +73,16 @@ describe('filterRowsByGridConditions', () => {
|
||||
]).map((row) => row.id)).toEqual([1]);
|
||||
});
|
||||
|
||||
it('filters a structured value selection including null and empty values', () => {
|
||||
const rowsWithEmpty = [...rows, { id: 4, name: 'Dora', status: '' }];
|
||||
expect(filterRowsByGridConditions(rowsWithEmpty, [{
|
||||
column: 'status',
|
||||
op: 'IN',
|
||||
valueSelection: { values: ['active'], includeNull: true, includeEmpty: true },
|
||||
enabled: true,
|
||||
}]).map((row) => row.id)).toEqual([1, 3, 4]);
|
||||
});
|
||||
|
||||
it('supports null checks and OR logic', () => {
|
||||
expect(filterRowsByGridConditions(rows, [
|
||||
{ column: 'status', op: 'IS_NULL', enabled: true },
|
||||
|
||||
@@ -124,6 +124,13 @@ const matchSingleCondition = (row: Record<string, any>, condition: FilterConditi
|
||||
const cell = row?.[column];
|
||||
const cellText = normalizeCellText(cell);
|
||||
|
||||
const valueSelection = condition?.valueSelection;
|
||||
if (valueSelection) {
|
||||
return (valueSelection.values || []).some((item) => cellText === String(item))
|
||||
|| (!!valueSelection.includeNull && isNullishCell(cell))
|
||||
|| (!!valueSelection.includeEmpty && !isNullishCell(cell) && isEmptyCell(cell));
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case 'IS_NULL':
|
||||
return isNullishCell(cell);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { buildOrderBySQL, buildPaginatedSelectSQL, quoteQualifiedIdent, reverseOrderBySQL } from './sql';
|
||||
import { buildOrderBySQL, buildPaginatedSelectSQL, buildWhereSQL, quoteQualifiedIdent, reverseOrderBySQL } from './sql';
|
||||
|
||||
describe('buildOrderBySQL', () => {
|
||||
it('does not add fallback ORDER BY for DuckDB without explicit sort', () => {
|
||||
@@ -12,6 +12,16 @@ describe('buildOrderBySQL', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildWhereSQL', () => {
|
||||
it('builds one grouped expression for a structured value selection', () => {
|
||||
expect(buildWhereSQL('mysql', [{
|
||||
column: 'status',
|
||||
op: 'IN',
|
||||
valueSelection: { values: ['active', 'waiting,review'], includeNull: true, includeEmpty: true },
|
||||
}])).toBe("WHERE ((`status` IN ('active', 'waiting,review') OR `status` IS NULL OR `status` = ''))");
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildPaginatedSelectSQL', () => {
|
||||
it('uses SQL Server TOP for the first page to support old compatibility levels', () => {
|
||||
const sql = buildPaginatedSelectSQL('sqlserver', 'SELECT * FROM [Users]', ' ORDER BY [ID] ASC', 101, 0);
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { splitQualifiedNameSegments, stripIdentifierQuotes } from './qualifiedName';
|
||||
|
||||
export type FilterValueSelection = {
|
||||
values: string[];
|
||||
includeNull?: boolean;
|
||||
includeEmpty?: boolean;
|
||||
};
|
||||
|
||||
export type FilterCondition = {
|
||||
id?: number;
|
||||
enabled?: boolean;
|
||||
@@ -8,6 +14,7 @@ export type FilterCondition = {
|
||||
op?: string;
|
||||
value?: string;
|
||||
value2?: string;
|
||||
valueSelection?: FilterValueSelection;
|
||||
};
|
||||
|
||||
const normalizeIdentPart = (ident: string) => stripIdentifierQuotes(ident);
|
||||
@@ -369,6 +376,19 @@ export const buildWhereSQL = (dbType: string, conditions: FilterCondition[]) =>
|
||||
if (!column) return;
|
||||
|
||||
const col = quoteIdentPart(dbType, column);
|
||||
const valueSelection = cond?.valueSelection;
|
||||
if (valueSelection) {
|
||||
const selectedValues = Array.from(new Set((valueSelection.values || []).map((item) => String(item))));
|
||||
const selectionParts: string[] = [];
|
||||
if (selectedValues.length > 0) {
|
||||
selectionParts.push(`${col} IN (${selectedValues.map((item) => `'${escapeLiteral(item)}'`).join(', ')})`);
|
||||
}
|
||||
if (valueSelection.includeNull) selectionParts.push(`${col} IS NULL`);
|
||||
if (valueSelection.includeEmpty) selectionParts.push(`${col} = ''`);
|
||||
if (selectionParts.length === 0) return;
|
||||
appendWherePart(selectionParts.length === 1 ? selectionParts[0] : `(${selectionParts.join(' OR ')})`);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case 'IS_NULL':
|
||||
|
||||
Reference in New Issue
Block a user