package drivers import ( "context" "dbview/service/internal/common/databases/meta" "fmt" "math" "regexp" "strconv" "sync" ) type Connection interface { Close() error Ping(context.Context) error } // 驱动接口 - 所有数据库驱动必须实现 type Driver interface { Open(config *meta.ConnectionConfig) (Connection, error) Version() string } // 驱动注册表 type DriverRegistry struct { drivers map[string]map[string]Driver // 格式: dbType -> version -> Driver mu sync.RWMutex } var globalRegistry = &DriverRegistry{ drivers: make(map[string]map[string]Driver), } // RegisterDriver 将指定数据库类型与版本的驱动注册进全局注册表(线程安全)。 // 参数: // - dbType: 数据库类型标识,如 mysql、postgres。 // - version: 驱动适配的版本号,如 v8、8.0。 // - driver: 实际的驱动实现实例。 // // 返回值:无;若类型+版本重复注册会直接 panic,提示冲突原因。 func RegisterDriver(dbType, version string, driver Driver) { globalRegistry.mu.Lock() defer globalRegistry.mu.Unlock() if _, ok := globalRegistry.drivers[dbType]; !ok { globalRegistry.drivers[dbType] = make(map[string]Driver) } // 防止重复注册 if _, exists := globalRegistry.drivers[dbType][version]; exists { panic(fmt.Sprintf("数据库驱动注册冲突:类型 %s 的版本 %s 已存在,请勿重复加载", dbType, version)) } globalRegistry.drivers[dbType][version] = driver } // Connect 根据数据库类型与版本规范创建连接实例。 // 参数: // - dbType: 数据库类型标识。 // - DbVersion: 版本字符串,可为精确或语义化版本描述。 // - config: 连接配置,包含Host/Port/用户名等信息。 // // 返回值: // - Connection: 成功时返回可用于执行数据库操作的连接包装。 // - error: 若无匹配驱动或打开失败则返回相应错误。 func Connect(dbType, DbVersion string, config *meta.ConnectionConfig) (Connection, error) { driver, err := GetDriver(dbType, DbVersion) if err != nil { return nil, err } return driver.Open(config) } // GetDriver 从注册表中获取指定数据库类型与版本规范的驱动。 // 参数: // - dbType: 数据库类型标识。 // - versionSpec: 版本规范,支持精确版本与语义化匹配(如 v8、8.0、8)。 // // 返回值: // - Driver: 找到时返回对应驱动实例。 // - error: 当类型或版本不存在时返回详细错误提示。 func GetDriver(dbType, versionSpec string) (Driver, error) { globalRegistry.mu.RLock() defer globalRegistry.mu.RUnlock() versions, ok := globalRegistry.drivers[dbType] if !ok { return nil, fmt.Errorf("未找到数据库类型 %s 对应的驱动实现,请确认驱动已正确注册", dbType) } // 精确匹配 if driver, ok := versions[versionSpec]; ok { return driver, nil } // 模糊化版本匹配:提取数字序列并按首个数字的距离最小化来选择最近的版本。 // 例如:传入 "8.0.27",已注册的 "v8" 或 "8" 会匹配(首个数字均为 8)。 // 优先级:完全数字匹配 -> 最小首位数字差 -> 报错。 extractNums := func(s string) []int { re := regexp.MustCompile(`\d+`) parts := re.FindAllString(s, -1) out := make([]int, 0, len(parts)) for _, p := range parts { if n, err := strconv.Atoi(p); err == nil { out = append(out, n) } } return out } specNums := extractNums(versionSpec) if len(specNums) == 0 { return nil, fmt.Errorf("未找到数据库类型 %s 对应的版本 %s 驱动实现,请确认驱动已正确注册", dbType, versionSpec) } var best Driver bestDiff := math.MaxInt32 found := false for ver, drv := range versions { vnums := extractNums(ver) if len(vnums) == 0 { continue } // 如果任何数字完全匹配(首位或任一位),优先返回 for _, vn := range vnums { if vn == specNums[0] { return drv, nil } } // 否则以首位数字差作为距离度量 diff := int(math.Abs(float64(vnums[0] - specNums[0]))) if diff < bestDiff { bestDiff = diff best = drv found = true } } if found { return best, nil } return nil, fmt.Errorf("未找到数据库类型 %s 对应的版本 %s 驱动实现,请确认驱动已正确注册", dbType, versionSpec) } // GetRegisteredDrivers 返回当前注册表中所有数据库类型及其可用版本列表。 // 返回值:map,键为数据库类型,值为该类型下已注册的版本切片,用于调试或展示。 func GetRegisteredDrivers() map[string][]string { globalRegistry.mu.RLock() defer globalRegistry.mu.RUnlock() driversCopy := make(map[string][]string) for dbType, versions := range globalRegistry.drivers { for version := range versions { driversCopy[dbType] = append(driversCopy[dbType], version) } } return driversCopy }