Files
MyGoNavi/frontend/src/components/sidebarV2Utils.command-search.test.ts
Syngnat 8f1e6cf379 ️ perf(frontend): 优化长时运行下的搜索与缓存占用
- 为 V2 cmd+k 搜索预建索引并限制初始/宽泛结果数量
- 清理冷数据库树和 DataViewer 长生命周期快照缓存
- 收紧运行时 SQL 日志预算并在 hydration 时压缩旧缓存
2026-06-22 22:36:39 +08:00

117 lines
3.7 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
V2_COMMAND_SEARCH_INITIAL_TREE_LIMIT,
V2_COMMAND_SEARCH_MAX_TREE_RESULTS,
buildV2CommandSearchTreeIndex,
filterV2CommandSearchTreeItems,
parseV2CommandSearchQuery,
resolveSidebarDatabaseTreePruneKeys,
type V2CommandSearchItem,
} from './sidebarV2Utils';
const buildNodeItems = (count: number): V2CommandSearchItem[] => {
return Array.from({ length: count }, (_, index) => ({
key: `node-table-${index}`,
kind: 'node' as const,
title: `fs_order_${index}`,
meta: `开发240 · front_end_sys_${index % 4}`,
icon: null,
node: {
type: index % 6 === 0 ? 'view' : 'table',
key: `table-${index}`,
title: `fs_order_${index}`,
dataRef: {
tableName: `fs_order_${index}`,
viewName: index % 6 === 0 ? `v_order_${index}` : undefined,
dbName: `front_end_sys_${index % 4}`,
name: `obj_${index}`,
config: {
host: `10.0.0.${index % 16}`,
},
},
},
}));
};
describe('sidebarV2 command search performance helpers', () => {
it('keeps the initial tree result limit when the query is empty', () => {
const items = buildNodeItems(V2_COMMAND_SEARCH_INITIAL_TREE_LIMIT + 80);
expect(
filterV2CommandSearchTreeItems(items, parseV2CommandSearchQuery('')),
).toHaveLength(V2_COMMAND_SEARCH_INITIAL_TREE_LIMIT);
});
it('caps broad keyword matches to avoid rendering the full loaded tree', () => {
const items = buildNodeItems(V2_COMMAND_SEARCH_MAX_TREE_RESULTS + 160);
const result = filterV2CommandSearchTreeItems(
items,
parseV2CommandSearchQuery('fs_order'),
);
expect(result).toHaveLength(V2_COMMAND_SEARCH_MAX_TREE_RESULTS);
expect(result[0]?.key).toBe('node-table-0');
expect(result[result.length - 1]?.key).toBe(`node-table-${V2_COMMAND_SEARCH_MAX_TREE_RESULTS - 1}`);
});
it('returns the same matches when filtering with a prebuilt search index', () => {
const items = buildNodeItems(200);
const index = buildV2CommandSearchTreeIndex(items);
const query = parseV2CommandSearchQuery('@fs_order_1');
expect(filterV2CommandSearchTreeItems(index, query)).toEqual(
filterV2CommandSearchTreeItems(items, query),
);
});
it('prunes only cold collapsed database trees when too many object trees stay loaded', () => {
expect(resolveSidebarDatabaseTreePruneKeys({
treeData: [
{
key: 'conn-1',
title: 'conn-1',
type: 'connection',
children: [
{
key: 'conn-1-db-a',
title: 'db-a',
type: 'database',
children: [{ key: 'a-tables', title: '表', type: 'object-group' }],
},
{
key: 'conn-1-db-b',
title: 'db-b',
type: 'database',
children: [{ key: 'b-tables', title: '表', type: 'object-group' }],
},
{
key: 'conn-1-db-c',
title: 'db-c',
type: 'database',
children: [{ key: 'c-tables', title: '表', type: 'object-group' }],
},
{
key: 'conn-1-db-d',
title: 'db-d',
type: 'database',
children: [{ key: 'd-tables', title: '表', type: 'object-group' }],
},
],
},
],
expandedKeys: ['conn-1-db-c'],
selectedKeys: [],
activeDatabaseKey: 'conn-1-db-d',
touchedAtByDatabaseKey: {
'conn-1-db-a': 10,
'conn-1-db-b': 20,
'conn-1-db-c': 30,
'conn-1-db-d': 40,
},
maxLoadedDatabases: 2,
})).toEqual(['conn-1-db-a', 'conn-1-db-b']);
});
});