mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-05-06 20:03:05 +08:00
- 数据源支持:新增 OceanBase 与 OpenGauss optional driver-agent 实现 - 连接适配:复用 MySQL/PostgreSQL 兼容链路并补齐查询、DDL、同步能力 - 前端入口:补充连接表单、侧边栏、图标、SQL 方言和危险操作识别 - 驱动管理:更新 driver manifest、安装提示和 revision 自动生成链路 - 构建发布:支持多平台 driver-agent 打包并优化 release 构建失败提示
380 lines
15 KiB
Go
380 lines
15 KiB
Go
package sync
|
||
|
||
import (
|
||
"GoNavi-Wails/internal/connection"
|
||
"GoNavi-Wails/internal/db"
|
||
"fmt"
|
||
"strings"
|
||
)
|
||
|
||
type genericLegacyPlanner struct{}
|
||
|
||
type mysqlToPGLikePlanner struct{}
|
||
|
||
type mysqlToClickHousePlanner struct{}
|
||
|
||
type pgLikeToClickHousePlanner struct{}
|
||
|
||
type clickHouseToMySQLPlanner struct{}
|
||
|
||
type clickHouseToPGLikePlanner struct{}
|
||
|
||
type mysqlToMongoPlanner struct{}
|
||
|
||
type pgLikeToMongoPlanner struct{}
|
||
|
||
type clickHouseToMongoPlanner struct{}
|
||
|
||
type tdengineToMongoPlanner struct{}
|
||
|
||
type mongoToMySQLPlanner struct{}
|
||
|
||
type mongoToPGLikePlanner struct{}
|
||
|
||
type pgLikeToMySQLPlanner struct{}
|
||
|
||
type tdengineToMySQLPlanner struct{}
|
||
|
||
type tdengineToPGLikePlanner struct{}
|
||
|
||
type mongoToRelationalPlanner struct{}
|
||
|
||
func buildSchemaMigrationPlan(config SyncConfig, tableName string, sourceDB db.Database, targetDB db.Database) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
ctx := MigrationBuildContext{
|
||
Config: config,
|
||
TableName: tableName,
|
||
SourceDB: sourceDB,
|
||
TargetDB: targetDB,
|
||
}
|
||
planner := resolveMigrationPlanner(ctx)
|
||
if planner == nil {
|
||
return buildSchemaMigrationPlanLegacy(config, tableName, sourceDB, targetDB)
|
||
}
|
||
return planner.BuildPlan(ctx)
|
||
}
|
||
|
||
func resolveMigrationPlanner(ctx MigrationBuildContext) MigrationPlanner {
|
||
planners := []MigrationPlanner{
|
||
mysqlToPGLikePlanner{},
|
||
mySQLLikeToTDenginePlanner{},
|
||
pgLikeToTDenginePlanner{},
|
||
clickHouseToTDenginePlanner{},
|
||
tdengineToTDenginePlanner{},
|
||
tdengineToPGLikePlanner{},
|
||
tdengineToMySQLPlanner{},
|
||
mysqlToClickHousePlanner{},
|
||
pgLikeToClickHousePlanner{},
|
||
clickHouseToMySQLPlanner{},
|
||
clickHouseToPGLikePlanner{},
|
||
mysqlToMongoPlanner{},
|
||
pgLikeToMongoPlanner{},
|
||
clickHouseToMongoPlanner{},
|
||
tdengineToMongoPlanner{},
|
||
mongoToMySQLPlanner{},
|
||
mongoToPGLikePlanner{},
|
||
pgLikeToMySQLPlanner{},
|
||
mongoToRelationalPlanner{},
|
||
genericLegacyPlanner{},
|
||
}
|
||
bestLevel := MigrationSupportLevelUnsupported
|
||
var bestPlanner MigrationPlanner
|
||
for _, planner := range planners {
|
||
level := planner.SupportLevel(ctx)
|
||
if migrationSupportRank(level) > migrationSupportRank(bestLevel) {
|
||
bestLevel = level
|
||
bestPlanner = planner
|
||
}
|
||
}
|
||
return bestPlanner
|
||
}
|
||
|
||
func migrationSupportRank(level MigrationSupportLevel) int {
|
||
switch level {
|
||
case MigrationSupportLevelFull:
|
||
return 4
|
||
case MigrationSupportLevelPlanned:
|
||
return 3
|
||
case MigrationSupportLevelPartial:
|
||
return 2
|
||
default:
|
||
return 1
|
||
}
|
||
}
|
||
|
||
func isMySQLLikeType(dbType string) bool {
|
||
return isMySQLLikeWritableTargetType(dbType)
|
||
}
|
||
|
||
func classifyMigrationDataModel(dbType string) MigrationDataModel {
|
||
switch normalizeMigrationDBType(dbType) {
|
||
case "mysql", "mariadb", "oceanbase", "postgres", "kingbase", "highgo", "vastbase", "opengauss", "oracle", "sqlserver", "dameng", "sqlite", "duckdb":
|
||
return MigrationDataModelRelational
|
||
case "mongodb":
|
||
return MigrationDataModelDocument
|
||
case "clickhouse", "diros", "sphinx":
|
||
return MigrationDataModelColumnar
|
||
case "tdengine":
|
||
return MigrationDataModelTimeSeries
|
||
case "redis":
|
||
return MigrationDataModelKeyValue
|
||
default:
|
||
return MigrationDataModelCustom
|
||
}
|
||
}
|
||
|
||
func (genericLegacyPlanner) Name() string { return "generic-legacy-planner" }
|
||
|
||
func (genericLegacyPlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
_ = ctx
|
||
return MigrationSupportLevelPartial
|
||
}
|
||
|
||
func (genericLegacyPlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildSchemaMigrationPlanLegacy(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (mysqlToPGLikePlanner) Name() string { return "mysql-pglike-planner" }
|
||
|
||
func (mysqlToPGLikePlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if isMySQLLikeSourceType(sourceType) && isPGLikeTarget(targetType) {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (mysqlToPGLikePlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildMySQLToPGLikePlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (tdengineToMySQLPlanner) Name() string { return "tdengine-mysql-planner" }
|
||
|
||
func (tdengineToMySQLPlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if sourceType == "tdengine" && isMySQLLikeWritableTargetType(targetType) {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (tdengineToMySQLPlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildTDengineToMySQLPlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (tdengineToPGLikePlanner) Name() string { return "tdengine-pglike-planner" }
|
||
|
||
func (tdengineToPGLikePlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if sourceType == "tdengine" && isPGLikeTarget(targetType) {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (tdengineToPGLikePlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildTDengineToPGLikePlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (mysqlToClickHousePlanner) Name() string { return "mysql-clickhouse-planner" }
|
||
|
||
func (mysqlToClickHousePlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if isMySQLCoreType(sourceType) && targetType == "clickhouse" {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (mysqlToClickHousePlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildMySQLToClickHousePlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (pgLikeToClickHousePlanner) Name() string { return "pglike-clickhouse-planner" }
|
||
|
||
func (pgLikeToClickHousePlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if isPGLikeSource(sourceType) && targetType == "clickhouse" {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (pgLikeToClickHousePlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildPGLikeToClickHousePlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (clickHouseToMySQLPlanner) Name() string { return "clickhouse-mysql-planner" }
|
||
|
||
func (clickHouseToMySQLPlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if sourceType == "clickhouse" && isMySQLLikeWritableTargetType(targetType) {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (clickHouseToMySQLPlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildClickHouseToMySQLPlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (clickHouseToPGLikePlanner) Name() string { return "clickhouse-pglike-planner" }
|
||
|
||
func (clickHouseToPGLikePlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if sourceType == "clickhouse" && isPGLikeTarget(targetType) {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (clickHouseToPGLikePlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildClickHouseToPGLikePlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (mysqlToMongoPlanner) Name() string { return "mysql-mongo-planner" }
|
||
|
||
func (mysqlToMongoPlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if isMySQLCoreType(sourceType) && targetType == "mongodb" {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (mysqlToMongoPlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildMySQLToMongoPlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (pgLikeToMongoPlanner) Name() string { return "pglike-mongo-planner" }
|
||
|
||
func (pgLikeToMongoPlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if isPGLikeSource(sourceType) && targetType == "mongodb" {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (pgLikeToMongoPlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildPGLikeToMongoPlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (clickHouseToMongoPlanner) Name() string { return "clickhouse-mongo-planner" }
|
||
|
||
func (clickHouseToMongoPlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if sourceType == "clickhouse" && targetType == "mongodb" {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (clickHouseToMongoPlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildClickHouseToMongoPlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (tdengineToMongoPlanner) Name() string { return "tdengine-mongo-planner" }
|
||
|
||
func (tdengineToMongoPlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if sourceType == "tdengine" && targetType == "mongodb" {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (tdengineToMongoPlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildTDengineToMongoPlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (mongoToMySQLPlanner) Name() string { return "mongo-mysql-planner" }
|
||
|
||
func (mongoToMySQLPlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if sourceType == "mongodb" && isMySQLLikeWritableTargetType(targetType) {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (mongoToMySQLPlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildMongoToMySQLPlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (mongoToPGLikePlanner) Name() string { return "mongo-pglike-planner" }
|
||
|
||
func (mongoToPGLikePlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if sourceType == "mongodb" && isPGLikeTarget(targetType) {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (mongoToPGLikePlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildMongoToPGLikePlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (pgLikeToMySQLPlanner) Name() string { return "pglike-mysql-planner" }
|
||
|
||
func (pgLikeToMySQLPlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if isPGLikeSource(sourceType) && isMySQLLikeWritableTargetType(targetType) {
|
||
return MigrationSupportLevelFull
|
||
}
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
|
||
func (pgLikeToMySQLPlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
return buildPGLikeToMySQLPlan(ctx.Config, ctx.TableName, ctx.SourceDB, ctx.TargetDB)
|
||
}
|
||
|
||
func (mongoToRelationalPlanner) Name() string { return "mongo-relational-inference-planner" }
|
||
|
||
func (mongoToRelationalPlanner) SupportLevel(ctx MigrationBuildContext) MigrationSupportLevel {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
if !shouldUseSchemaInference(sourceType, targetType) {
|
||
return MigrationSupportLevelUnsupported
|
||
}
|
||
return MigrationSupportLevelPlanned
|
||
}
|
||
|
||
func (mongoToRelationalPlanner) BuildPlan(ctx MigrationBuildContext) (SchemaMigrationPlan, []connection.ColumnDefinition, []connection.ColumnDefinition, error) {
|
||
sourceType := resolveMigrationDBType(ctx.Config.SourceConfig)
|
||
targetType := resolveMigrationDBType(ctx.Config.TargetConfig)
|
||
inference, err := inferSchemaForPair(sourceType, targetType, ctx.TableName)
|
||
if err != nil {
|
||
return SchemaMigrationPlan{}, nil, nil, err
|
||
}
|
||
plan := SchemaMigrationPlan{}
|
||
plan.SourceSchema, plan.SourceTable = normalizeSchemaAndTable(sourceType, ctx.Config.SourceConfig.Database, ctx.TableName)
|
||
plan.TargetSchema, plan.TargetTable = normalizeSchemaAndTable(targetType, ctx.Config.TargetConfig.Database, ctx.TableName)
|
||
plan.SourceQueryTable = qualifiedNameForQuery(sourceType, plan.SourceSchema, plan.SourceTable, ctx.TableName)
|
||
plan.TargetQueryTable = qualifiedNameForQuery(targetType, plan.TargetSchema, plan.TargetTable, ctx.TableName)
|
||
plan.PlannedAction = "当前库对已进入迁移内核规划阶段,等待 schema 推断与目标方言生成器落地"
|
||
for _, issue := range inference.Issues {
|
||
msg := strings.TrimSpace(issue.Message)
|
||
if msg == "" {
|
||
continue
|
||
}
|
||
plan.Warnings = append(plan.Warnings, msg)
|
||
}
|
||
plan.Warnings = append(plan.Warnings, fmt.Sprintf("迁移对象=%s,目标类型=%s,当前仅提供规划入口,暂不执行自动建表", inference.Object.Kind, targetType))
|
||
return dedupeSchemaMigrationPlan(plan), nil, nil, nil
|
||
}
|