🐛 fix(tdengine): 兼容超级表元数据查询结果

- 兼容 stable_name 及不同大小写的超级表字段
- 增加 SHOW STABLES 多种语法回退
- 新增超级表选项解析与去重回归测试
This commit is contained in:
Syngnat
2026-08-03 15:05:16 +08:00
parent 75f897c1ab
commit d06d9a0f7f
3 changed files with 109 additions and 10 deletions

View File

@@ -35,6 +35,7 @@ import {
resolveSqlDialect,
} from '../utils/sqlDialect';
import { splitQualifiedNameLast, stripIdentifierQuotes } from '../utils/qualifiedName';
import { buildTDengineStableOptions, buildTDengineStableQueries } from '../utils/tdengineStableMetadata';
import {
cloneTableDesignerColumnsForPaste,
parseTableDesignerColumns,
@@ -1681,6 +1682,7 @@ ${selectedTrigger.statement}`;
let cancelled = false;
const fetchSuperTables = async () => {
setTdengineStableOptionsLoading(true);
setTdengineStableOptions([]);
try {
const conn = connections.find(c => c.id === tab.connectionId);
if (!conn) return;
@@ -1694,17 +1696,17 @@ ${selectedTrigger.statement}`;
};
const rpcConfig = buildRpcConnectionConfig(config) as any;
const dbName = tab.dbName || '';
const res = await DBQuery(rpcConfig, dbName, 'SHOW STABLES');
if (cancelled) return;
if (res.success && Array.isArray(res.data)) {
const options = res.data.map((row: any) => {
const name = row?.table_name || row?.Table || row?.name || row?.tablename || '';
return { label: String(name), value: String(name) };
}).filter(opt => opt.value);
setTdengineStableOptions(options);
} else {
setTdengineStableOptions([]);
for (const query of buildTDengineStableQueries(dbName)) {
const res = await DBQuery(rpcConfig, dbName, query);
if (cancelled) return;
if (!res?.success || !Array.isArray(res.data)) continue;
const options = buildTDengineStableOptions(res.data);
if (options.length > 0) {
setTdengineStableOptions(options);
return;
}
}
if (!cancelled) setTdengineStableOptions([]);
} catch {
if (!cancelled) setTdengineStableOptions([]);
} finally {

View File

@@ -0,0 +1,32 @@
import { describe, expect, it } from 'vitest';
import {
buildTDengineStableOptions,
buildTDengineStableQueries,
} from './tdengineStableMetadata';
describe('TDengine stable metadata helpers', () => {
it('reads stable_name returned by SHOW STABLES and removes duplicate names', () => {
expect(buildTDengineStableOptions([
{ stable_name: 'meters' },
{ STABLE_NAME: 'meters' },
{ name: 'weather' },
{ stable_name: '' },
{ comment: 'not a stable name' },
])).toEqual([
{ label: 'meters', value: 'meters' },
{ label: 'weather', value: 'weather' },
]);
});
it('keeps TDengine query fallbacks for context and qualified database syntax', () => {
expect(buildTDengineStableQueries('metrics')).toEqual([
'SHOW STABLES',
'SHOW STABLES FROM `metrics`',
'SHOW STABLES FROM metrics',
'SHOW metrics.STABLES',
]);
expect(buildTDengineStableQueries('metrics`prod')).toContain('SHOW STABLES FROM `metrics``prod`');
expect(buildTDengineStableQueries('')).toEqual(['SHOW STABLES']);
});
});

View File

@@ -0,0 +1,65 @@
export interface TDengineStableOption {
label: string;
value: string;
}
const STABLE_NAME_KEYS = [
'stable_name',
'stableName',
'table_name',
'Table',
'name',
'tablename',
'table',
] as const;
const readText = (value: unknown): string => {
if (typeof value !== 'string' && typeof value !== 'number') return '';
return String(value).trim();
};
export const resolveTDengineStableName = (row: unknown): string => {
if (!row || typeof row !== 'object') return '';
const record = row as Record<string, unknown>;
for (const key of STABLE_NAME_KEYS) {
const value = readText(record[key]);
if (value) return value;
}
const normalizedKeys = new Set(STABLE_NAME_KEYS.map((key) => key.toLowerCase()));
for (const [key, value] of Object.entries(record)) {
if (!normalizedKeys.has(key.toLowerCase())) continue;
const text = readText(value);
if (text) return text;
}
return '';
};
export const buildTDengineStableOptions = (rows: unknown[]): TDengineStableOption[] => {
const seen = new Set<string>();
const options: TDengineStableOption[] = [];
for (const row of rows) {
const name = resolveTDengineStableName(row);
if (!name || seen.has(name)) continue;
seen.add(name);
options.push({ label: name, value: name });
}
return options;
};
export const buildTDengineStableQueries = (dbName: string): string[] => {
const normalized = String(dbName || '').trim();
if (!normalized) return ['SHOW STABLES'];
const quoted = normalized.replace(/`/g, '``');
return [
'SHOW STABLES',
`SHOW STABLES FROM \`${quoted}\``,
`SHOW STABLES FROM ${normalized}`,
`SHOW ${normalized}.STABLES`,
];
};