Skip to content

Commit 64995ae

Browse files
committed
feat: support Redis SQL workbench datasource #873
1 parent 5783501 commit 64995ae

4 files changed

Lines changed: 100 additions & 6 deletions

File tree

internal/dms/pkg/constant/const.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ func ParseDBType(s string) (DBType, error) {
258258
return DBTypePolarDBForMySQL, nil
259259
case "MongoDB":
260260
return DBTypeMongoDB, nil
261+
case "Redis":
262+
return DBTypeRedis, nil
261263
case "OceanBase For Oracle":
262264
return DBTypeOceanBaseOracle, nil
263265

@@ -284,6 +286,7 @@ const (
284286
DBTypeHANA DBType = "HANA"
285287
DBTypePolarDBForMySQL DBType = "PolarDB For MySQL"
286288
DBTypeMongoDB DBType = "MongoDB"
289+
DBTypeRedis DBType = "Redis"
287290
DBTypeOceanBaseOracle DBType = "OceanBase For Oracle"
288291
)
289292

internal/dms/pkg/constant/const_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ func TestParseDBType(t *testing.T) {
128128
// PolarDB-MySQL 新增 (Issue #826)
129129
"PolarDB For MySQL": {input: "PolarDB For MySQL", expected: DBTypePolarDBForMySQL},
130130
"MongoDB": {input: "MongoDB", expected: DBTypeMongoDB},
131+
"Redis": {input: "Redis", expected: DBTypeRedis},
131132
// "PolarDB" 单独不应匹配
132133
"PolarDB only": {input: "PolarDB", expectError: true},
133134
"invalid type": {input: "UnknownDB", expectError: true},

internal/sql_workbench/service/sql_workbench_service.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,12 @@ const (
863863
mongoTLSEnabledParam = "tls"
864864
mongoDirectConnectionParam = "direct_connection"
865865
mongoTLSSkipVerifyParam = "tls_skip_verify"
866+
redisDefaultDatabaseParam = "default_database"
867+
redisTLSEnabledParam = "tls"
868+
redisTLSInsecureParam = "tls_insecure"
869+
redisScanCountParam = "scan_count"
870+
redisKeySeparatorParam = "key_separator"
871+
redisCommandTimeoutParam = "command_timeout_ms"
866872
)
867873

868874
// buildDatasourceBaseInfo 构建数据源基础信息
@@ -898,6 +904,10 @@ func (sqlWorkbenchService *SqlWorkbenchService) fillDatasourceBaseInfo(datasourc
898904
baseInfo.DefaultSchema, baseInfo.Properties, baseInfo.JDBCParams = buildMongoDatasourceOptions(dbService)
899905
}
900906

907+
if dbService.DBType == string(pkgConst.DBTypeRedis) {
908+
baseInfo.DefaultSchema, baseInfo.Properties, baseInfo.JDBCParams = buildRedisDatasourceOptions(dbService)
909+
}
910+
901911
// DB2 特殊处理:从 AdditionalParams.database_name 取默认 schema 透传到 ODC
902912
if dbService.DBType == "DB2" {
903913
databaseNameParam := dbService.AdditionalParams.GetParam("database_name")
@@ -993,6 +1003,8 @@ func (sqlWorkbenchService *SqlWorkbenchService) convertDBType(dmsDBType string)
9931003
return "MYSQL"
9941004
case "MongoDB":
9951005
return "MONGODB"
1006+
case "Redis":
1007+
return "REDIS"
9961008
case "DB2":
9971009
return "DB2"
9981010
default:
@@ -1010,7 +1022,8 @@ func (sqlWorkbenchService *SqlWorkbenchService) SupportDBType(dbType pkgConst.DB
10101022
dbType == pkgConst.DBTypeGoldenDB ||
10111023
dbType == pkgConst.DBTypePolarDBForMySQL ||
10121024
dbType == pkgConst.DBTypeGaussDB ||
1013-
dbType == pkgConst.DBTypePostgreSQL
1025+
dbType == pkgConst.DBTypePostgreSQL ||
1026+
dbType == pkgConst.DBTypeRedis
10141027
}
10151028

10161029
func buildMongoDatasourceOptions(dbService *biz.DBService) (*string, interface{}, map[string]interface{}) {
@@ -1050,6 +1063,35 @@ func buildMongoDatasourceOptions(dbService *biz.DBService) (*string, interface{}
10501063
return defaultSchema, nil, jdbcParams
10511064
}
10521065

1066+
func buildRedisDatasourceOptions(dbService *biz.DBService) (*string, interface{}, map[string]interface{}) {
1067+
defaultDatabase := dbService.AdditionalParams.GetParam(redisDefaultDatabaseParam).String()
1068+
var defaultSchema *string
1069+
jdbcParams := map[string]interface{}{}
1070+
if defaultDatabase != "" {
1071+
defaultSchema = &defaultDatabase
1072+
jdbcParams["defaultDatabase"] = defaultDatabase
1073+
}
1074+
if tlsParam := dbService.AdditionalParams.GetParam(redisTLSEnabledParam); tlsParam != nil && tlsParam.String() != "" {
1075+
jdbcParams["tls"] = tlsParam.Bool()
1076+
}
1077+
if dbService.AdditionalParams.GetParam(redisTLSInsecureParam).Bool() {
1078+
jdbcParams["tlsInsecure"] = true
1079+
}
1080+
if scanCount := dbService.AdditionalParams.GetParam(redisScanCountParam).String(); scanCount != "" {
1081+
jdbcParams["scanCount"] = scanCount
1082+
}
1083+
if keySeparator := dbService.AdditionalParams.GetParam(redisKeySeparatorParam).String(); keySeparator != "" {
1084+
jdbcParams["keySeparator"] = keySeparator
1085+
}
1086+
if timeout := dbService.AdditionalParams.GetParam(redisCommandTimeoutParam).String(); timeout != "" {
1087+
jdbcParams["commandTimeoutMs"] = timeout
1088+
}
1089+
if len(jdbcParams) == 0 {
1090+
return defaultSchema, nil, nil
1091+
}
1092+
return defaultSchema, nil, jdbcParams
1093+
}
1094+
10531095
func interfacePtr(v interface{}) *interface{} {
10541096
if v == nil {
10551097
return nil

internal/sql_workbench/service/sql_workbench_service_test.go

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func Test_convertDBType(t *testing.T) {
2828
"PolarDB For MySQL": {input: "PolarDB For MySQL", expected: "MYSQL"},
2929
"GaussDB": {input: "GaussDB", expected: "GAUSSDB"},
3030
"MongoDB": {input: "MongoDB", expected: "MONGODB"},
31+
"Redis": {input: "Redis", expected: "REDIS"},
3132
"DB2": {input: "DB2", expected: "DB2"},
3233
"Unknown passthrough": {input: "UnknownDB", expected: "UnknownDB"},
3334
}
@@ -55,6 +56,7 @@ func Test_SupportDBType(t *testing.T) {
5556
"TDSQL supported": {input: pkgConst.DBTypeTDSQLForInnoDB, expected: true},
5657
"GoldenDB supported": {input: pkgConst.DBTypeGoldenDB, expected: true},
5758
"MongoDB unsupported": {input: pkgConst.DBTypeMongoDB, expected: false},
59+
"Redis supported": {input: pkgConst.DBTypeRedis, expected: true},
5860
"PostgreSQL supported": {input: pkgConst.DBTypePostgreSQL, expected: true},
5961
"SQL Server unsupported": {input: pkgConst.DBTypeSQLServer, expected: false},
6062
"PolarDB For MySQL supported": {input: pkgConst.DBTypePolarDBForMySQL, expected: true},
@@ -140,6 +142,52 @@ func Test_buildMongoDatasourceOptions_tlsOnly(t *testing.T) {
140142
}
141143
}
142144

145+
func Test_buildRedisDatasourceOptions(t *testing.T) {
146+
defaultDB := "2"
147+
defaultSchema, propertiesValue, jdbcParams := buildRedisDatasourceOptions(&biz.DBService{
148+
DBType: string(pkgConst.DBTypeRedis),
149+
Host: "127.0.0.1",
150+
Port: "6379",
151+
AdditionalParams: pkgParams.Params{
152+
&pkgParams.Param{Key: redisDefaultDatabaseParam, Value: defaultDB, Type: pkgParams.ParamTypeString},
153+
&pkgParams.Param{Key: redisTLSEnabledParam, Value: "true", Type: pkgParams.ParamTypeBool},
154+
&pkgParams.Param{Key: redisTLSInsecureParam, Value: "true", Type: pkgParams.ParamTypeBool},
155+
&pkgParams.Param{Key: redisScanCountParam, Value: "200", Type: pkgParams.ParamTypeString},
156+
&pkgParams.Param{Key: redisKeySeparatorParam, Value: ":", Type: pkgParams.ParamTypeString},
157+
&pkgParams.Param{Key: redisCommandTimeoutParam, Value: "3000", Type: pkgParams.ParamTypeString},
158+
},
159+
})
160+
if defaultSchema == nil || *defaultSchema != defaultDB {
161+
t.Fatalf("unexpected default schema: %#v", defaultSchema)
162+
}
163+
if propertiesValue != nil {
164+
t.Fatalf("expected nil properties, got %#v", propertiesValue)
165+
}
166+
if jdbcParams["defaultDatabase"] != defaultDB || jdbcParams["tls"] != true || jdbcParams["tlsInsecure"] != true {
167+
t.Fatalf("unexpected redis base params: %#v", jdbcParams)
168+
}
169+
if jdbcParams["scanCount"] != "200" || jdbcParams["keySeparator"] != ":" || jdbcParams["commandTimeoutMs"] != "3000" {
170+
t.Fatalf("unexpected redis tuning params: %#v", jdbcParams)
171+
}
172+
}
173+
174+
func Test_buildRedisDatasourceOptions_noSensitiveProperties(t *testing.T) {
175+
_, propertiesValue, jdbcParams := buildRedisDatasourceOptions(&biz.DBService{
176+
DBType: string(pkgConst.DBTypeRedis),
177+
User: "default",
178+
Password: "secret",
179+
AdditionalParams: pkgParams.Params{
180+
&pkgParams.Param{Key: redisTLSEnabledParam, Value: "false", Type: pkgParams.ParamTypeBool},
181+
},
182+
})
183+
if propertiesValue != nil {
184+
t.Fatalf("expected redis properties to stay nil, got %#v", propertiesValue)
185+
}
186+
if _, ok := jdbcParams["password"]; ok {
187+
t.Fatalf("redis password leaked into jdbc params: %#v", jdbcParams)
188+
}
189+
}
190+
143191
// Test_buildDatasourceBaseInfo_DB2 覆盖 buildDatasourceBaseInfo 中 DB2 / 回归 4 组 case:
144192
//
145193
// (a) DB2 正例:AdditionalParam database_name=testdb → baseInfo.DefaultSchema=="testdb"
@@ -154,11 +202,11 @@ func Test_buildDatasourceBaseInfo_DB2(t *testing.T) {
154202
const datasourceName = "proj:ds"
155203

156204
cases := map[string]struct {
157-
dbService *biz.DBService
158-
expectErr bool
159-
expectErrSubstr string
160-
expectDefaultSchema *string
161-
expectServiceName *string
205+
dbService *biz.DBService
206+
expectErr bool
207+
expectErrSubstr string
208+
expectDefaultSchema *string
209+
expectServiceName *string
162210
}{
163211
"DB2 happy path": {
164212
dbService: &biz.DBService{

0 commit comments

Comments
 (0)