refactor(db): 重构数据库查询构建器以支持多数据库方言和标识符处理
- 实现了标识符处理器,统一处理表名、字段名的前缀添加和引号转换 - 添加对 MySQL、PostgreSQL、SQLite 三种数据库方言的支持 - 引入 ProcessTableName、ProcessColumn、ProcessConditionString 等方法处理标识符 - 为 HoTimeDB 添加 T() 和 C() 辅助方法用于手动构建 SQL 查询 - 重构 CRUD 操作中的表名和字段名处理逻辑,统一使用标识符处理器 - 添加完整的单元测试验证不同数据库方言下的标识符处理功能 - 优化 JOIN 操作中表名和条件字符串的处理方式
This commit is contained in:
+66
-48
@@ -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 + ";"
|
||||
|
||||
Reference in New Issue
Block a user