Files
MyGoNavi/frontend/src/components/tableDesignerIndexSql.ts
lixiaodong cf9b7d9d10 feat(elasticsearch): 生产级 ES 驱动 — 写入支持、分页、多版本兼容
- go-elasticsearch/v8 官方 SDK,支持 ES 6.x/7.x/8.x
- SQL → ES DSL 转换、DevTools 查询、JSON DSL
- _bulk API 批量写入(INSERT/UPDATE/DELETE)
- 别名写入、精确分页、COUNT 统计
- API Key / SSH / SSL 连接支持
- 表设计器只读适配、ES 品牌图标
- 30+ 单元测试全部通过
2026-06-03 10:15:38 +08:00

98 lines
3.7 KiB
TypeScript

import {
isMysqlFamilyDialect,
isOracleLikeDialect,
isPgLikeDialect,
isSqlServerDialect,
quoteSqlIdentifierPart,
} from '../utils/sqlDialect';
export type TableDesignerIndexKind = 'NORMAL' | 'UNIQUE' | 'PRIMARY' | 'FULLTEXT' | 'SPATIAL';
export interface BuildIndexCreateSqlInput {
dbType: string;
tableRef: string;
name: string;
columnNames: string[];
kind: TableDesignerIndexKind;
indexType?: string;
}
export interface BuildIndexCreateSqlResult {
sql: string | null;
message?: string;
severity?: 'error' | 'warning';
}
const isNonRelationalDialect = (dbType: string): boolean => dbType === 'redis' || dbType === 'mongodb' || dbType === 'elasticsearch';
export const buildIndexCreateSqlPreview = (input: BuildIndexCreateSqlInput): BuildIndexCreateSqlResult => {
const dbType = input.dbType;
const kind = input.kind || 'NORMAL';
const indexName = String(input.name || '').trim();
const cleanedCols = input.columnNames.map(col => String(col || '').trim()).filter(Boolean);
if (cleanedCols.length === 0) {
return { sql: null, message: '请至少选择一个字段', severity: 'error' };
}
const colSql = cleanedCols
.map(col => quoteSqlIdentifierPart(dbType, col))
.join(', ');
if (isMysqlFamilyDialect(dbType)) {
if (kind === 'PRIMARY') {
return { sql: `ALTER TABLE ${input.tableRef}\nADD PRIMARY KEY (${colSql});` };
}
if (!indexName) {
return { sql: null, message: '请输入索引名', severity: 'error' };
}
const indexRef = quoteSqlIdentifierPart(dbType, indexName);
if (kind === 'FULLTEXT') {
return { sql: `ALTER TABLE ${input.tableRef}\nADD FULLTEXT INDEX ${indexRef} (${colSql});` };
}
if (kind === 'SPATIAL') {
return { sql: `ALTER TABLE ${input.tableRef}\nADD SPATIAL INDEX ${indexRef} (${colSql});` };
}
const normalizedType = String(input.indexType || '').trim().toUpperCase() || 'DEFAULT';
if (normalizedType === 'FULLTEXT' || normalizedType === 'SPATIAL') {
return { sql: null, message: `请将“索引类别”切换为 ${normalizedType} 索引`, severity: 'error' };
}
const usingSql = normalizedType !== 'DEFAULT' ? ` USING ${normalizedType}` : '';
const prefix = kind === 'UNIQUE' ? 'ADD UNIQUE INDEX' : 'ADD INDEX';
return { sql: `ALTER TABLE ${input.tableRef}\n${prefix} ${indexRef}${usingSql} (${colSql});` };
}
if (kind === 'PRIMARY' || kind === 'FULLTEXT' || kind === 'SPATIAL') {
return { sql: null, message: '当前数据库仅支持普通索引与唯一索引维护', severity: 'warning' };
}
if (!indexName) {
return { sql: null, message: '请输入索引名', severity: 'error' };
}
const indexRef = quoteSqlIdentifierPart(dbType, indexName);
const normalizedType = String(input.indexType || '').trim().toUpperCase() || 'DEFAULT';
const uniquePrefix = kind === 'UNIQUE' ? 'UNIQUE ' : '';
if (isPgLikeDialect(dbType)) {
const usingSql = normalizedType !== 'DEFAULT' ? ` USING ${normalizedType}` : '';
return { sql: `CREATE ${uniquePrefix}INDEX ${indexRef} ON ${input.tableRef}${usingSql} (${colSql});` };
}
if (isSqlServerDialect(dbType)) {
const methodSql = normalizedType === 'CLUSTERED' || normalizedType === 'NONCLUSTERED'
? `${normalizedType} `
: '';
return { sql: `CREATE ${uniquePrefix}${methodSql}INDEX ${indexRef} ON ${input.tableRef} (${colSql});` };
}
if (isOracleLikeDialect(dbType) || dbType === 'sqlite') {
return { sql: `CREATE ${uniquePrefix}INDEX ${indexRef} ON ${input.tableRef} (${colSql});` };
}
if (isNonRelationalDialect(dbType)) {
return { sql: null, message: '当前数据源不支持关系型索引维护', severity: 'warning' };
}
return { sql: `CREATE ${uniquePrefix}INDEX ${indexRef} ON ${input.tableRef} (${colSql});` };
};