mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-09 16:09:41 +08:00
🐛 fix(doris): 修复数据库重命名与字段变更预览
Refs #439 - Doris 重命名数据库改走原生 ALTER DATABASE RENAME - Doris 字段/注释预览改为兼容语法,移除 AFTER/FIRST 和无效 NONE - 补充相关回归测试
This commit is contained in:
@@ -162,6 +162,40 @@ describe('tableDesignerSchemaSql', () => {
|
||||
expect(sql).not.toContain('MODIFY COLUMN');
|
||||
});
|
||||
|
||||
it('builds doris alter preview without mysql-only syntax or metadata extra', () => {
|
||||
const sql = buildAlterTablePreviewSql(buildInput({
|
||||
dbType: 'doris',
|
||||
tableName: 'sales.orders',
|
||||
originalColumns: [
|
||||
baseColumn({
|
||||
_key: 'carrier',
|
||||
name: 'carrier_id',
|
||||
type: 'bigint',
|
||||
nullable: 'YES',
|
||||
extra: 'NONE',
|
||||
comment: '承运商id',
|
||||
}),
|
||||
],
|
||||
columns: [
|
||||
baseColumn({
|
||||
_key: 'carrier',
|
||||
name: 'carrier_code',
|
||||
type: 'bigint',
|
||||
nullable: 'YES',
|
||||
extra: 'NONE',
|
||||
comment: '承运商id1',
|
||||
}),
|
||||
],
|
||||
}));
|
||||
|
||||
expect(sql).toContain('ALTER TABLE `sales`.`orders`\nRENAME COLUMN `carrier_id` `carrier_code`;');
|
||||
expect(sql).toContain("ALTER TABLE `sales`.`orders`\nMODIFY COLUMN `carrier_code` bigint NULL COMMENT '承运商id1';");
|
||||
expect(sql).not.toContain('CHANGE COLUMN');
|
||||
expect(sql).not.toContain('AFTER');
|
||||
expect(sql).not.toContain(' FIRST');
|
||||
expect(sql).not.toContain('NONE');
|
||||
});
|
||||
|
||||
it('uses native limited alter syntax for clickhouse and tdengine instead of mysql syntax', () => {
|
||||
const clickhouseSql = buildAlterTablePreviewSql(buildInput({
|
||||
dbType: 'clickhouse',
|
||||
@@ -184,8 +218,8 @@ describe('tableDesignerSchemaSql', () => {
|
||||
expect(tdengineSql).not.toContain('AFTER');
|
||||
});
|
||||
|
||||
it('treats mariadb doris and sphinx as mysql-family only where mysql syntax is intended', () => {
|
||||
for (const dbType of ['mariadb', 'diros', 'sphinx']) {
|
||||
it('treats mariadb and sphinx as mysql-family only where mysql syntax is intended', () => {
|
||||
for (const dbType of ['mariadb', 'sphinx']) {
|
||||
const sql = buildAlterTablePreviewSql(buildInput({ dbType }));
|
||||
expect(sql).toContain('ALTER TABLE `users`');
|
||||
expect(sql).toContain('ADD COLUMN `age` int NULL');
|
||||
|
||||
@@ -125,6 +125,37 @@ const buildMySqlColumnDefinition = (column: EditableColumnSnapshot, dbType: stri
|
||||
].filter(Boolean).join(' ').replace(/\s+/g, ' ').trim();
|
||||
};
|
||||
|
||||
const DORIS_AGG_TYPES = new Set([
|
||||
'SUM',
|
||||
'MIN',
|
||||
'MAX',
|
||||
'REPLACE',
|
||||
'REPLACE_IF_NOT_NULL',
|
||||
'HLL_UNION',
|
||||
'BITMAP_UNION',
|
||||
'QUANTILE_UNION',
|
||||
'GENERIC',
|
||||
]);
|
||||
|
||||
const buildDorisColumnDefinition = (column: EditableColumnSnapshot, dbType: string): string => {
|
||||
const defaultSql = buildDefaultSql(column.default, dbType);
|
||||
const autoIncrementSql = column.isAutoIncrement ? 'AUTO_INCREMENT' : '';
|
||||
const keyText = String(column.key || '').trim().toUpperCase();
|
||||
const extraText = String(column.extra || '').trim().toUpperCase();
|
||||
const keyOrAggSql = ['PRI', 'KEY', 'TRUE'].includes(keyText)
|
||||
? 'KEY'
|
||||
: (DORIS_AGG_TYPES.has(extraText) ? extraText : '');
|
||||
return [
|
||||
quoteIdentifierPart(column.name, dbType),
|
||||
String(column.type || '').trim(),
|
||||
keyOrAggSql,
|
||||
column.nullable === 'NO' ? 'NOT NULL' : 'NULL',
|
||||
defaultSql,
|
||||
autoIncrementSql,
|
||||
`COMMENT '${escapeSqlString(column.comment || '')}'`,
|
||||
].filter(Boolean).join(' ').replace(/\s+/g, ' ').trim();
|
||||
};
|
||||
|
||||
const buildStandardColumnDefinition = (
|
||||
column: EditableColumnSnapshot,
|
||||
dbType: string,
|
||||
@@ -226,6 +257,44 @@ const buildMySqlAlterPreviewSql = (input: BuildAlterTablePreviewInput, dbType: s
|
||||
return alters.length === 0 ? '' : `ALTER TABLE ${tableName}\n${alters.join(',\n')};`;
|
||||
};
|
||||
|
||||
const buildDorisAlterPreviewSql = (input: BuildAlterTablePreviewInput, dbType: string): string => {
|
||||
const tableName = quoteIdentifierPath(input.tableName, dbType);
|
||||
const statements: string[] = [];
|
||||
|
||||
input.originalColumns.forEach((orig) => {
|
||||
if (!input.columns.find((col) => col._key === orig._key)) {
|
||||
statements.push(`ALTER TABLE ${tableName}\nDROP COLUMN ${quoteIdentifierPart(orig.name, dbType)};`);
|
||||
}
|
||||
});
|
||||
|
||||
input.columns.forEach((curr) => {
|
||||
const orig = input.originalColumns.find((col) => col._key === curr._key);
|
||||
if (!orig) {
|
||||
statements.push(`ALTER TABLE ${tableName}\nADD COLUMN ${buildDorisColumnDefinition(curr, dbType)};`);
|
||||
return;
|
||||
}
|
||||
|
||||
let currentName = orig.name;
|
||||
if (curr.name !== orig.name) {
|
||||
statements.push(`ALTER TABLE ${tableName}\nRENAME COLUMN ${quoteIdentifierPart(orig.name, dbType)} ${quoteIdentifierPart(curr.name, dbType)};`);
|
||||
currentName = curr.name;
|
||||
}
|
||||
|
||||
if (definitionChanged(curr, orig)) {
|
||||
statements.push(`ALTER TABLE ${tableName}\nMODIFY COLUMN ${buildDorisColumnDefinition({ ...curr, name: currentName }, dbType)};`);
|
||||
}
|
||||
});
|
||||
|
||||
const origPKKeys = input.originalColumns.filter((col) => col.key === 'PRI').map((col) => col._key);
|
||||
const newPKKeys = input.columns.filter((col) => col.key === 'PRI').map((col) => col._key);
|
||||
const keysChanged = origPKKeys.length !== newPKKeys.length || !origPKKeys.every((key) => newPKKeys.includes(key));
|
||||
if (keysChanged) {
|
||||
statements.push('-- Doris 修改主键/Key 模型需要按表模型手工迁移,已避免生成 MySQL 专属的 DROP/ADD PRIMARY KEY。');
|
||||
}
|
||||
|
||||
return statements.join('\n');
|
||||
};
|
||||
|
||||
const buildPgLikeAlterPreviewSql = (input: BuildAlterTablePreviewInput, dbType: string): string => {
|
||||
const tableParts = splitQualifiedName(input.tableName);
|
||||
const baseTableName = tableParts.objectName || stripIdentifierQuotes(input.tableName);
|
||||
@@ -537,6 +606,7 @@ export const buildAlterTablePreviewSql = (input: BuildAlterTablePreviewInput): s
|
||||
if (isSqlServerDialect(dbType)) return buildSqlServerAlterPreviewSql({ ...input, dbType });
|
||||
if (dbType === 'sqlite') return buildSqliteAlterPreviewSql({ ...input, dbType });
|
||||
if (dbType === 'duckdb') return buildDuckDbAlterPreviewSql({ ...input, dbType });
|
||||
if (dbType === 'diros') return buildDorisAlterPreviewSql({ ...input, dbType }, dbType);
|
||||
if (dbType === 'clickhouse') return buildLimitedBacktickAlterPreviewSql({ ...input, dbType }, dbType, 'ClickHouse');
|
||||
if (dbType === 'tdengine') return buildLimitedBacktickAlterPreviewSql({ ...input, dbType }, dbType, 'TDengine');
|
||||
if (isMysqlFamilyDialect(dbType)) return buildMySqlAlterPreviewSql({ ...input, dbType }, dbType);
|
||||
|
||||
Reference in New Issue
Block a user