mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-09 06:23:29 +08:00
✨ feat(driver): 新增 OceanBase 与 OpenGauss Agent 数据源
- 数据源支持:新增 OceanBase 与 OpenGauss optional driver-agent 实现 - 连接适配:复用 MySQL/PostgreSQL 兼容链路并补齐查询、DDL、同步能力 - 前端入口:补充连接表单、侧边栏、图标、SQL 方言和危险操作识别 - 驱动管理:更新 driver manifest、安装提示和 revision 自动生成链路 - 构建发布:支持多平台 driver-agent 打包并优化 release 构建失败提示
This commit is contained in:
@@ -68,6 +68,7 @@ describe('connectionModalPresentation', () => {
|
||||
const allTypes = [
|
||||
'mysql',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'doris',
|
||||
'diros',
|
||||
'sphinx',
|
||||
@@ -81,6 +82,7 @@ describe('connectionModalPresentation', () => {
|
||||
'kingbase',
|
||||
'highgo',
|
||||
'vastbase',
|
||||
'opengauss',
|
||||
'mongodb',
|
||||
'redis',
|
||||
'tdengine',
|
||||
|
||||
@@ -55,6 +55,7 @@ type ConnectionConfigSectionCopy = {
|
||||
const mysqlCompatibleTypes = new Set([
|
||||
'mysql',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'doris',
|
||||
'diros',
|
||||
'sphinx',
|
||||
@@ -64,6 +65,7 @@ const postgresCompatibleTypes = new Set([
|
||||
'kingbase',
|
||||
'highgo',
|
||||
'vastbase',
|
||||
'opengauss',
|
||||
]);
|
||||
const fileDatabaseTypes = new Set(['sqlite', 'duckdb']);
|
||||
|
||||
|
||||
@@ -9,6 +9,10 @@ const normalizeDataSourceToken = (raw: string): string => {
|
||||
return 'diros';
|
||||
case 'postgresql':
|
||||
return 'postgres';
|
||||
case 'opengauss':
|
||||
case 'open_gauss':
|
||||
case 'open-gauss':
|
||||
return 'opengauss';
|
||||
case 'dm':
|
||||
return 'dameng';
|
||||
default:
|
||||
@@ -29,12 +33,14 @@ export const resolveDataSourceType = (config: ConnectionLike): string => {
|
||||
const SQL_QUERY_EXPORT_TYPES = new Set([
|
||||
'mysql',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'diros',
|
||||
'sphinx',
|
||||
'postgres',
|
||||
'kingbase',
|
||||
'highgo',
|
||||
'vastbase',
|
||||
'opengauss',
|
||||
'sqlserver',
|
||||
'sqlite',
|
||||
'duckdb',
|
||||
@@ -47,12 +53,14 @@ const SQL_QUERY_EXPORT_TYPES = new Set([
|
||||
const COPY_INSERT_TYPES = new Set([
|
||||
'mysql',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'diros',
|
||||
'sphinx',
|
||||
'postgres',
|
||||
'kingbase',
|
||||
'highgo',
|
||||
'vastbase',
|
||||
'opengauss',
|
||||
'sqlserver',
|
||||
'sqlite',
|
||||
'duckdb',
|
||||
|
||||
@@ -17,6 +17,8 @@ describe('driver import guidance', () => {
|
||||
it('documents custom driver aliases for kingbase and related fallbacks', () => {
|
||||
expect(CUSTOM_CONNECTION_DRIVER_HELP).toContain('kingbase8');
|
||||
expect(CUSTOM_CONNECTION_DRIVER_HELP).toContain('pgx');
|
||||
expect(CUSTOM_CONNECTION_DRIVER_HELP).toContain('open_gauss');
|
||||
expect(CUSTOM_CONNECTION_DRIVER_HELP).toContain('oceanbase');
|
||||
expect(CUSTOM_CONNECTION_DRIVER_HELP).toContain('JDBC Jar');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,4 +7,4 @@ export const DRIVER_LOCAL_IMPORT_SINGLE_FILE_HELP =
|
||||
'行内“导入驱动包”仅用于单个驱动文件/总包(如 `mariadb-driver-agent`、`mariadb-driver-agent.exe`、`GoNavi-DriverAgents.zip`),不支持直接导入 JDBC Jar;批量导入请使用上方“导入驱动目录”。';
|
||||
|
||||
export const CUSTOM_CONNECTION_DRIVER_HELP =
|
||||
'已支持: mysql, postgres, sqlite, oracle, dm, kingbase;别名支持 postgresql/pgx、dm8、kingbase8/kingbasees/kingbasev8。当前不支持通过 JDBC Jar 扩展驱动。';
|
||||
'已支持: mysql, oceanbase, postgres, opengauss, sqlite, oracle, dm, kingbase;别名支持 postgresql/pgx、open_gauss/open-gauss、dm8、kingbase8/kingbasees/kingbasev8。当前不支持通过 JDBC Jar 扩展驱动。';
|
||||
|
||||
@@ -6,6 +6,7 @@ describe('applyQueryAutoLimit', () => {
|
||||
const limitDialects = [
|
||||
'mysql',
|
||||
'mariadb',
|
||||
'oceanbase',
|
||||
'diros',
|
||||
'doris',
|
||||
'sphinx',
|
||||
@@ -15,6 +16,7 @@ describe('applyQueryAutoLimit', () => {
|
||||
'kingbase8',
|
||||
'highgo',
|
||||
'vastbase',
|
||||
'opengauss',
|
||||
'sqlite',
|
||||
'sqlite3',
|
||||
'duckdb',
|
||||
|
||||
@@ -16,10 +16,14 @@ const normalizeSidebarConnectionDialect = (type: string, driver: string): string
|
||||
if (normalizedType === 'custom') {
|
||||
const normalizedDriver = String(driver || '').trim().toLowerCase();
|
||||
if (normalizedDriver === 'postgresql' || normalizedDriver === 'postgres' || normalizedDriver === 'pg') return 'postgres';
|
||||
if (normalizedDriver === 'opengauss' || normalizedDriver === 'open_gauss' || normalizedDriver === 'open-gauss') return 'opengauss';
|
||||
if (normalizedDriver === 'dameng' || normalizedDriver === 'dm' || normalizedDriver === 'dm8') return 'dm';
|
||||
if (normalizedDriver === 'oceanbase') return 'mysql';
|
||||
if (normalizedDriver.includes('oracle')) return 'oracle';
|
||||
return normalizedDriver;
|
||||
}
|
||||
if (normalizedType === 'oceanbase') return 'mysql';
|
||||
if (normalizedType === 'open_gauss' || normalizedType === 'open-gauss') return 'opengauss';
|
||||
if (normalizedType === 'dameng') return 'dm';
|
||||
return normalizedType;
|
||||
};
|
||||
|
||||
@@ -37,12 +37,12 @@ export const quoteIdentPart = (dbType: string, ident: string) => {
|
||||
if (!raw) return raw;
|
||||
const dbTypeLower = (dbType || '').toLowerCase();
|
||||
|
||||
if (dbTypeLower === 'mysql' || dbTypeLower === 'mariadb' || dbTypeLower === 'diros' || dbTypeLower === 'sphinx' || dbTypeLower === 'tdengine' || dbTypeLower === 'clickhouse') {
|
||||
if (dbTypeLower === 'mysql' || dbTypeLower === 'mariadb' || dbTypeLower === 'oceanbase' || dbTypeLower === 'diros' || dbTypeLower === 'sphinx' || dbTypeLower === 'tdengine' || dbTypeLower === 'clickhouse') {
|
||||
return `\`${raw.replace(/`/g, '``')}\``;
|
||||
}
|
||||
|
||||
// 对于 KingBase/PostgreSQL,只在必要时加引号
|
||||
if (dbTypeLower === 'kingbase' || dbTypeLower === 'postgres') {
|
||||
if (dbTypeLower === 'kingbase' || dbTypeLower === 'postgres' || dbTypeLower === 'opengauss') {
|
||||
if (needsQuote(raw)) {
|
||||
return `"${raw.replace(/"/g, '""')}"`;
|
||||
}
|
||||
@@ -153,7 +153,7 @@ export const buildOrderBySQL = (
|
||||
// MySQL/MariaDB 大表在无显式排序需求时强制 ORDER BY(即使按主键)可能触发 filesort,
|
||||
// 导致 `Error 1038 (HY001): Out of sort memory`。
|
||||
// 因此仅在用户主动点击排序时下发 ORDER BY,默认分页查询不加兜底排序。
|
||||
if (dbTypeLower === 'mysql' || dbTypeLower === 'mariadb' || dbTypeLower === 'diros') {
|
||||
if (dbTypeLower === 'mysql' || dbTypeLower === 'mariadb' || dbTypeLower === 'oceanbase' || dbTypeLower === 'diros') {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
@@ -14,12 +14,16 @@ const names = (items: Array<{ name: string }>) => items.map((item) => item.name)
|
||||
describe('sqlDialect', () => {
|
||||
it('normalizes datasource aliases without collapsing all dialects to mysql', () => {
|
||||
expect(resolveSqlDialect('postgresql')).toBe('postgres');
|
||||
expect(resolveSqlDialect('OpenGauss')).toBe('opengauss');
|
||||
expect(resolveSqlDialect('OceanBase')).toBe('oceanbase');
|
||||
expect(resolveSqlDialect('doris')).toBe('diros');
|
||||
expect(resolveSqlDialect('dameng')).toBe('dameng');
|
||||
expect(resolveSqlDialect('custom', 'kingbase8')).toBe('kingbase');
|
||||
expect(resolveSqlDialect('custom', 'dm8')).toBe('dameng');
|
||||
expect(resolveSqlDialect('custom', 'mariadb')).toBe('mariadb');
|
||||
expect(resolveSqlDialect('custom', 'open_gauss')).toBe('opengauss');
|
||||
expect(isMysqlFamilyDialect('mariadb')).toBe(true);
|
||||
expect(isMysqlFamilyDialect('oceanbase')).toBe(true);
|
||||
expect(isMysqlFamilyDialect('oracle')).toBe(false);
|
||||
});
|
||||
|
||||
@@ -28,6 +32,8 @@ describe('sqlDialect', () => {
|
||||
expect(values(resolveColumnTypeOptions('oracle'))).not.toContain('tinyint(1)');
|
||||
expect(values(resolveColumnTypeOptions('dameng'))).toContain('VARCHAR2(255)');
|
||||
expect(values(resolveColumnTypeOptions('kingbase'))).toContain('integer');
|
||||
expect(values(resolveColumnTypeOptions('opengauss'))).toContain('integer');
|
||||
expect(values(resolveColumnTypeOptions('oceanbase'))).toContain('varchar(255)');
|
||||
expect(values(resolveColumnTypeOptions('kingbase'))).not.toContain('tinyint(1)');
|
||||
expect(values(resolveColumnTypeOptions('diros'))).toContain('LARGEINT');
|
||||
expect(values(resolveColumnTypeOptions('sphinx'))).toContain('text');
|
||||
|
||||
@@ -8,12 +8,14 @@ export type SqlFunctionCompletion = {
|
||||
export type SqlDialect =
|
||||
| 'mysql'
|
||||
| 'mariadb'
|
||||
| 'oceanbase'
|
||||
| 'diros'
|
||||
| 'sphinx'
|
||||
| 'postgres'
|
||||
| 'kingbase'
|
||||
| 'highgo'
|
||||
| 'vastbase'
|
||||
| 'opengauss'
|
||||
| 'oracle'
|
||||
| 'dameng'
|
||||
| 'sqlserver'
|
||||
@@ -46,6 +48,10 @@ export const resolveSqlDialect = (rawType: string, rawDriver = ''): SqlDialect =
|
||||
case 'pq':
|
||||
case 'pgx':
|
||||
return 'postgres';
|
||||
case 'opengauss':
|
||||
case 'open_gauss':
|
||||
case 'open-gauss':
|
||||
return 'opengauss';
|
||||
case 'mssql':
|
||||
case 'sql_server':
|
||||
case 'sql-server':
|
||||
@@ -67,6 +73,7 @@ export const resolveSqlDialect = (rawType: string, rawDriver = ''): SqlDialect =
|
||||
case 'kingbasev8':
|
||||
return 'kingbase';
|
||||
case 'mariadb':
|
||||
case 'oceanbase':
|
||||
case 'mysql':
|
||||
case 'sphinx':
|
||||
case 'kingbase':
|
||||
@@ -83,7 +90,9 @@ export const resolveSqlDialect = (rawType: string, rawDriver = ''): SqlDialect =
|
||||
break;
|
||||
}
|
||||
|
||||
if (source.includes('opengauss') || source.includes('open_gauss') || source.includes('open-gauss')) return 'opengauss';
|
||||
if (source.includes('postgres')) return 'postgres';
|
||||
if (source.includes('oceanbase')) return 'oceanbase';
|
||||
if (source.includes('mariadb')) return 'mariadb';
|
||||
if (source.includes('mysql')) return 'mysql';
|
||||
if (source.includes('doris') || source.includes('diros')) return 'diros';
|
||||
@@ -103,11 +112,11 @@ export const resolveSqlDialect = (rawType: string, rawDriver = ''): SqlDialect =
|
||||
};
|
||||
|
||||
export const isMysqlFamilyDialect = (dbType: string): boolean => (
|
||||
['mysql', 'mariadb', 'diros', 'sphinx', 'tidb', 'oceanbase', 'starrocks'].includes(resolveSqlDialect(dbType))
|
||||
['mysql', 'mariadb', 'oceanbase', 'diros', 'sphinx', 'tidb', 'starrocks'].includes(resolveSqlDialect(dbType))
|
||||
);
|
||||
|
||||
export const isPgLikeDialect = (dbType: string): boolean => (
|
||||
['postgres', 'kingbase', 'highgo', 'vastbase'].includes(resolveSqlDialect(dbType))
|
||||
['postgres', 'kingbase', 'highgo', 'vastbase', 'opengauss'].includes(resolveSqlDialect(dbType))
|
||||
);
|
||||
|
||||
export const isOracleLikeDialect = (dbType: string): boolean => (
|
||||
@@ -423,9 +432,9 @@ const COMMON_TYPES = optionValues(['int', 'varchar(255)', 'text', 'datetime', 'd
|
||||
|
||||
export const resolveColumnTypeOptions = (dbType: string): ColumnTypeOption[] => {
|
||||
const dialect = resolveSqlDialect(dbType);
|
||||
if (dialect === 'mariadb' || dialect === 'mysql') return MYSQL_TYPES;
|
||||
if (dialect === 'diros') return DORIS_TYPES;
|
||||
if (dialect === 'sphinx') return SPHINX_TYPES;
|
||||
if (isMysqlFamilyDialect(dialect)) return MYSQL_TYPES;
|
||||
if (isPgLikeDialect(dialect)) return PG_TYPES;
|
||||
if (dialect === 'oracle') return ORACLE_TYPES;
|
||||
if (dialect === 'dameng') return DAMENG_TYPES;
|
||||
|
||||
Reference in New Issue
Block a user