refactor(db): 重构数据库查询构建器以支持多数据库方言和标识符处理

- 实现了标识符处理器,统一处理表名、字段名的前缀添加和引号转换
- 添加对 MySQL、PostgreSQL、SQLite 三种数据库方言的支持
- 引入 ProcessTableName、ProcessColumn、ProcessConditionString 等方法处理标识符
- 为 HoTimeDB 添加 T() 和 C() 辅助方法用于手动构建 SQL 查询
- 重构 CRUD 操作中的表名和字段名处理逻辑,统一使用标识符处理器
- 添加完整的单元测试验证不同数据库方言下的标识符处理功能
- 优化 JOIN 操作中表名和条件字符串的处理方式
This commit is contained in:
2026-01-22 09:32:01 +08:00
parent c4d0e16f2c
commit c3b8d15b54
7 changed files with 688 additions and 98 deletions
+66 -48
View File
@@ -87,17 +87,26 @@ func (that *HoTimeDB) Select(table string, qu ...interface{}) []Map {
join = true
}
processor := that.GetProcessor()
if len(qu) > 0 {
if reflect.ValueOf(qu[intQs]).Type().String() == "string" {
query += " " + qu[intQs].(string)
// 字段列表字符串,使用处理器处理 table.column 格式
fieldStr := qu[intQs].(string)
if fieldStr != "*" {
fieldStr = processor.ProcessFieldList(fieldStr)
}
query += " " + fieldStr
} else {
data := ObjToSlice(qu[intQs])
for i := 0; i < len(data); i++ {
k := data.GetString(i)
if strings.Contains(k, " AS ") || strings.Contains(k, ".") {
query += " " + k + " "
// 处理 table.column 格式
query += " " + processor.ProcessFieldList(k) + " "
} else {
query += " `" + k + "` "
// 单独的列名
query += " " + processor.ProcessColumnNoPrefix(k) + " "
}
if i+1 != len(data) {
@@ -109,11 +118,8 @@ func (that *HoTimeDB) Select(table string, qu ...interface{}) []Map {
query += " *"
}
if !strings.Contains(table, ".") && !strings.Contains(table, " AS ") {
query += " FROM `" + that.Prefix + table + "` "
} else {
query += " FROM " + that.Prefix + table + " "
}
// 处理表名(添加前缀和正确的引号)
query += " FROM " + processor.ProcessTableName(table) + " "
if join {
query += that.buildJoin(qu[0])
@@ -157,6 +163,7 @@ func (that *HoTimeDB) buildJoin(joinData interface{}) string {
query := ""
var testQu = []string{}
testQuData := Map{}
processor := that.GetProcessor()
if reflect.ValueOf(joinData).Type().String() == "common.Map" {
testQuData = joinData.(Map)
@@ -184,36 +191,34 @@ func (that *HoTimeDB) buildJoin(joinData interface{}) string {
case "[>]":
func() {
table := Substr(k, 3, len(k)-3)
if !strings.Contains(table, " ") {
table = "`" + table + "`"
}
query += " LEFT JOIN " + table + " ON " + v.(string) + " "
// 处理表名(添加前缀和正确的引号)
table = processor.ProcessTableName(table)
// 处理 ON 条件中的 table.column
onCondition := processor.ProcessConditionString(v.(string))
query += " LEFT JOIN " + table + " ON " + onCondition + " "
}()
case "[<]":
func() {
table := Substr(k, 3, len(k)-3)
if !strings.Contains(table, " ") {
table = "`" + table + "`"
}
query += " RIGHT JOIN " + table + " ON " + v.(string) + " "
table = processor.ProcessTableName(table)
onCondition := processor.ProcessConditionString(v.(string))
query += " RIGHT JOIN " + table + " ON " + onCondition + " "
}()
}
switch Substr(k, 0, 4) {
case "[<>]":
func() {
table := Substr(k, 4, len(k)-4)
if !strings.Contains(table, " ") {
table = "`" + table + "`"
}
query += " FULL JOIN " + table + " ON " + v.(string) + " "
table = processor.ProcessTableName(table)
onCondition := processor.ProcessConditionString(v.(string))
query += " FULL JOIN " + table + " ON " + onCondition + " "
}()
case "[><]":
func() {
table := Substr(k, 4, len(k)-4)
if !strings.Contains(table, " ") {
table = "`" + table + "`"
}
query += " INNER JOIN " + table + " ON " + v.(string) + " "
table = processor.ProcessTableName(table)
onCondition := processor.ProcessConditionString(v.(string))
query += " INNER JOIN " + table + " ON " + onCondition + " "
}()
}
}
@@ -250,6 +255,7 @@ func (that *HoTimeDB) Insert(table string, data map[string]interface{}) int64 {
values := make([]interface{}, 0)
queryString := " ("
valueString := " ("
processor := that.GetProcessor()
lens := len(data)
tempLen := 0
@@ -262,25 +268,25 @@ func (that *HoTimeDB) Insert(table string, data map[string]interface{}) int64 {
k = strings.Replace(k, "[#]", "", -1)
vstr = ObjToStr(v)
if tempLen < lens {
queryString += "`" + k + "`,"
queryString += processor.ProcessColumnNoPrefix(k) + ","
valueString += vstr + ","
} else {
queryString += "`" + k + "`) "
queryString += processor.ProcessColumnNoPrefix(k) + ") "
valueString += vstr + ");"
}
} else {
values = append(values, v)
if tempLen < lens {
queryString += "`" + k + "`,"
queryString += processor.ProcessColumnNoPrefix(k) + ","
valueString += "?,"
} else {
queryString += "`" + k + "`) "
queryString += processor.ProcessColumnNoPrefix(k) + ") "
valueString += "?);"
}
}
}
query := "INSERT INTO `" + that.Prefix + table + "` " + queryString + "VALUES" + valueString
query := "INSERT INTO " + processor.ProcessTableName(table) + " " + queryString + "VALUES" + valueString
res, err := that.Exec(query, values...)
@@ -334,10 +340,12 @@ func (that *HoTimeDB) BatchInsert(table string, dataList []Map) int64 {
// 排序列名以确保一致性
sort.Strings(columns)
processor := that.GetProcessor()
// 构建列名部分
quotedCols := make([]string, len(columns))
for i, col := range columns {
quotedCols[i] = "`" + col + "`"
quotedCols[i] = processor.ProcessColumnNoPrefix(col)
}
colStr := strings.Join(quotedCols, ", ")
@@ -368,7 +376,7 @@ func (that *HoTimeDB) BatchInsert(table string, dataList []Map) int64 {
placeholders[i] = "(" + strings.Join(rowPlaceholders, ", ") + ")"
}
query := "INSERT INTO `" + that.Prefix + table + "` (" + colStr + ") VALUES " + strings.Join(placeholders, ", ")
query := "INSERT INTO " + processor.ProcessTableName(table) + " (" + colStr + ") VALUES " + strings.Join(placeholders, ", ")
res, err := that.Exec(query, values...)
@@ -495,11 +503,12 @@ func (that *HoTimeDB) Upsert(table string, data Map, uniqueKeys Slice, updateCol
func (that *HoTimeDB) buildMySQLUpsert(table string, columns []string, uniqueKeys []string, updateColumns []string, rawValues map[string]string) string {
// INSERT INTO table (col1, col2) VALUES (?, ?)
// ON DUPLICATE KEY UPDATE col1 = VALUES(col1), col2 = VALUES(col2)
processor := that.GetProcessor()
quotedCols := make([]string, len(columns))
valueParts := make([]string, len(columns))
for i, col := range columns {
quotedCols[i] = "`" + col + "`"
quotedCols[i] = processor.ProcessColumnNoPrefix(col)
if raw, ok := rawValues[col]; ok {
valueParts[i] = raw
} else {
@@ -509,14 +518,15 @@ func (that *HoTimeDB) buildMySQLUpsert(table string, columns []string, uniqueKey
updateParts := make([]string, len(updateColumns))
for i, col := range updateColumns {
quotedCol := processor.ProcessColumnNoPrefix(col)
if raw, ok := rawValues[col]; ok {
updateParts[i] = "`" + col + "` = " + raw
updateParts[i] = quotedCol + " = " + raw
} else {
updateParts[i] = "`" + col + "` = VALUES(`" + col + "`)"
updateParts[i] = quotedCol + " = VALUES(" + quotedCol + ")"
}
}
return "INSERT INTO `" + that.Prefix + table + "` (" + strings.Join(quotedCols, ", ") +
return "INSERT INTO " + processor.ProcessTableName(table) + " (" + strings.Join(quotedCols, ", ") +
") VALUES (" + strings.Join(valueParts, ", ") +
") ON DUPLICATE KEY UPDATE " + strings.Join(updateParts, ", ")
}
@@ -525,12 +535,14 @@ func (that *HoTimeDB) buildMySQLUpsert(table string, columns []string, uniqueKey
func (that *HoTimeDB) buildPostgresUpsert(table string, columns []string, uniqueKeys []string, updateColumns []string, rawValues map[string]string) string {
// INSERT INTO table (col1, col2) VALUES ($1, $2)
// ON CONFLICT (unique_key) DO UPDATE SET col1 = EXCLUDED.col1
processor := that.GetProcessor()
dialect := that.GetDialect()
quotedCols := make([]string, len(columns))
valueParts := make([]string, len(columns))
paramIndex := 1
for i, col := range columns {
quotedCols[i] = "\"" + col + "\""
quotedCols[i] = dialect.QuoteIdentifier(col)
if raw, ok := rawValues[col]; ok {
valueParts[i] = raw
} else {
@@ -541,19 +553,20 @@ func (that *HoTimeDB) buildPostgresUpsert(table string, columns []string, unique
quotedUniqueKeys := make([]string, len(uniqueKeys))
for i, key := range uniqueKeys {
quotedUniqueKeys[i] = "\"" + key + "\""
quotedUniqueKeys[i] = dialect.QuoteIdentifier(key)
}
updateParts := make([]string, len(updateColumns))
for i, col := range updateColumns {
quotedCol := dialect.QuoteIdentifier(col)
if raw, ok := rawValues[col]; ok {
updateParts[i] = "\"" + col + "\" = " + raw
updateParts[i] = quotedCol + " = " + raw
} else {
updateParts[i] = "\"" + col + "\" = EXCLUDED.\"" + col + "\""
updateParts[i] = quotedCol + " = EXCLUDED." + quotedCol
}
}
return "INSERT INTO \"" + that.Prefix + table + "\" (" + strings.Join(quotedCols, ", ") +
return "INSERT INTO " + processor.ProcessTableName(table) + " (" + strings.Join(quotedCols, ", ") +
") VALUES (" + strings.Join(valueParts, ", ") +
") ON CONFLICT (" + strings.Join(quotedUniqueKeys, ", ") +
") DO UPDATE SET " + strings.Join(updateParts, ", ")
@@ -563,11 +576,13 @@ func (that *HoTimeDB) buildPostgresUpsert(table string, columns []string, unique
func (that *HoTimeDB) buildSQLiteUpsert(table string, columns []string, uniqueKeys []string, updateColumns []string, rawValues map[string]string) string {
// INSERT INTO table (col1, col2) VALUES (?, ?)
// ON CONFLICT (unique_key) DO UPDATE SET col1 = excluded.col1
processor := that.GetProcessor()
dialect := that.GetDialect()
quotedCols := make([]string, len(columns))
valueParts := make([]string, len(columns))
for i, col := range columns {
quotedCols[i] = "\"" + col + "\""
quotedCols[i] = dialect.QuoteIdentifier(col)
if raw, ok := rawValues[col]; ok {
valueParts[i] = raw
} else {
@@ -577,19 +592,20 @@ func (that *HoTimeDB) buildSQLiteUpsert(table string, columns []string, uniqueKe
quotedUniqueKeys := make([]string, len(uniqueKeys))
for i, key := range uniqueKeys {
quotedUniqueKeys[i] = "\"" + key + "\""
quotedUniqueKeys[i] = dialect.QuoteIdentifier(key)
}
updateParts := make([]string, len(updateColumns))
for i, col := range updateColumns {
quotedCol := dialect.QuoteIdentifier(col)
if raw, ok := rawValues[col]; ok {
updateParts[i] = "\"" + col + "\" = " + raw
updateParts[i] = quotedCol + " = " + raw
} else {
updateParts[i] = "\"" + col + "\" = excluded.\"" + col + "\""
updateParts[i] = quotedCol + " = excluded." + quotedCol
}
}
return "INSERT INTO \"" + that.Prefix + table + "\" (" + strings.Join(quotedCols, ", ") +
return "INSERT INTO " + processor.ProcessTableName(table) + " (" + strings.Join(quotedCols, ", ") +
") VALUES (" + strings.Join(valueParts, ", ") +
") ON CONFLICT (" + strings.Join(quotedUniqueKeys, ", ") +
") DO UPDATE SET " + strings.Join(updateParts, ", ")
@@ -597,7 +613,8 @@ func (that *HoTimeDB) buildSQLiteUpsert(table string, columns []string, uniqueKe
// Update 更新数据
func (that *HoTimeDB) Update(table string, data Map, where Map) int64 {
query := "UPDATE `" + that.Prefix + table + "` SET "
processor := that.GetProcessor()
query := "UPDATE " + processor.ProcessTableName(table) + " SET "
qs := make([]interface{}, 0)
tp := len(data)
@@ -609,7 +626,7 @@ func (that *HoTimeDB) Update(table string, data Map, where Map) int64 {
} else {
qs = append(qs, v)
}
query += "`" + k + "`=" + vstr + " "
query += processor.ProcessColumnNoPrefix(k) + "=" + vstr + " "
if tp--; tp != 0 {
query += ", "
}
@@ -639,7 +656,8 @@ func (that *HoTimeDB) Update(table string, data Map, where Map) int64 {
// Delete 删除数据
func (that *HoTimeDB) Delete(table string, data map[string]interface{}) int64 {
query := "DELETE FROM `" + that.Prefix + table + "` "
processor := that.GetProcessor()
query := "DELETE FROM " + processor.ProcessTableName(table) + " "
temp, resWhere := that.where(data)
query += temp + ";"