🐛 fix(query-editor): 修复多数据源大查询限流失效

- SQL限流:抽取查询自动限流工具,修复 SELECT 判断大小写不一致导致限制未生效
- 方言适配:按 Oracle/Dameng、SQL Server、MySQL/PostgreSQL 等方言分别注入行数限制
- 自定义驱动:支持 custom 连接根据 driver 解析 Oracle、PostgreSQL、SQL Server 等方言
- MongoDB修复:修正 db.collection.find() 解析边界,并对 find/只读 aggregate 下推 limit
- Oracle优化:DSN 增加 PREFETCH_ROWS 和 LOB FETCH 参数,减少大结果集拉取开销
- 测试覆盖:补充 SQL 方言矩阵、MongoDB 限流和 Oracle DSN 参数测试
Refs #424
This commit is contained in:
Syngnat
2026-04-29 10:29:19 +08:00
parent f51dbcfb2c
commit 05a913ccb2
7 changed files with 640 additions and 360 deletions

View File

@@ -1,6 +1,8 @@
import { describe, expect, it } from 'vitest';
import { convertMongoShellToJsonCommand } from './mongodb';
import { applyMongoQueryAutoLimit, convertMongoShellToJsonCommand } from './mongodb';
const parseCommand = (command: string | undefined) => JSON.parse(command || '{}');
describe('convertMongoShellToJsonCommand', () => {
it('converts show dbs shell shortcut to listDatabases command', () => {
@@ -16,4 +18,105 @@ describe('convertMongoShellToJsonCommand', () => {
command: JSON.stringify({ listCollections: 1, filter: {}, nameOnly: true }),
});
});
it('converts find shell commands without adding implicit limit', () => {
const result = convertMongoShellToJsonCommand('db.users.find({ active: true })');
expect(result.recognized).toBe(true);
expect(parseCommand(result.command)).toEqual({
find: 'users',
filter: { active: true },
});
});
it('keeps explicit find limit values from shell commands', () => {
const result = convertMongoShellToJsonCommand('db.users.find({}).limit(10)');
expect(parseCommand(result.command)).toEqual({
find: 'users',
filter: {},
limit: 10,
});
});
it('keeps explicit zero limit values from shell commands', () => {
const result = convertMongoShellToJsonCommand('db.users.find({}).limit(0)');
expect(parseCommand(result.command)).toEqual({
find: 'users',
filter: {},
limit: 0,
});
});
});
describe('applyMongoQueryAutoLimit', () => {
it('adds limit to raw Mongo find commands', () => {
const result = applyMongoQueryAutoLimit('{"find":"users","filter":{}}', 500);
expect(result.applied).toBe(true);
expect(parseCommand(result.command)).toEqual({
find: 'users',
filter: {},
limit: 500,
});
});
it('adds limit after shell find conversion', () => {
const shell = convertMongoShellToJsonCommand('db.users.find({ active: true })');
const result = applyMongoQueryAutoLimit(shell.command || '', 500);
expect(result.applied).toBe(true);
expect(parseCommand(result.command)).toEqual({
find: 'users',
filter: { active: true },
limit: 500,
});
});
it('does not replace explicit find limits', () => {
const result = applyMongoQueryAutoLimit('{"find":"users","filter":{},"limit":10}', 500);
expect(result.applied).toBe(false);
expect(parseCommand(result.command)).toEqual({
find: 'users',
filter: {},
limit: 10,
});
});
it('adds $limit to read-only aggregate pipelines', () => {
const result = applyMongoQueryAutoLimit('{"aggregate":"users","pipeline":[{"$match":{"active":true}}],"cursor":{}}', 500);
expect(result.applied).toBe(true);
expect(parseCommand(result.command)).toEqual({
aggregate: 'users',
pipeline: [
{ $match: { active: true } },
{ $limit: 500 },
],
cursor: {},
});
});
it('does not add another aggregate $limit', () => {
const command = '{"aggregate":"users","pipeline":[{"$limit":10}],"cursor":{}}';
const result = applyMongoQueryAutoLimit(command, 500);
expect(result.applied).toBe(false);
expect(result.command).toBe(command);
});
it('does not alter aggregate write pipelines', () => {
const command = '{"aggregate":"users","pipeline":[{"$match":{}},{"$out":"tmp_users"}],"cursor":{}}';
const result = applyMongoQueryAutoLimit(command, 500);
expect(result.applied).toBe(false);
expect(result.command).toBe(command);
});
it('does not limit non-read or invalid commands', () => {
expect(applyMongoQueryAutoLimit('{"count":"users","query":{}}', 500).applied).toBe(false);
expect(applyMongoQueryAutoLimit('db.users.find({})', 500).applied).toBe(false);
});
});