test(db): 添加 OR 条件处理的单元测试并修复 WHERE 子句逻辑
- 添加了 TestWhereWithORCondition 测试函数验证 OR 条件的括号包裹 - 修复了 where.go 中条件计数变量名称从 normalCondCount 改为 condCount - 实现了 OR/AND 组条件的括号包裹逻辑确保 SQL 语法正确 - 添加了空条件检查避免生成无效的 SQL 片段 - 更新了 .gitignore 文件添加日志文件忽略规则
This commit is contained in:
parent
8dac2aff66
commit
d1b905b780
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,4 +2,5 @@
|
|||||||
.idea
|
.idea
|
||||||
/example/tpt/demo/
|
/example/tpt/demo/
|
||||||
*.exe
|
*.exe
|
||||||
/example/config
|
/example/config
|
||||||
|
/.cursor/*.log
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
. "code.hoteas.com/golang/hotime/common"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -248,6 +249,170 @@ func TestHoTimeDBHelperMethods(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestWhereWithORCondition 测试 OR 条件处理是否正确添加括号
|
||||||
|
func TestWhereWithORCondition(t *testing.T) {
|
||||||
|
// 创建 MySQL 数据库实例
|
||||||
|
mysqlDB := &HoTimeDB{
|
||||||
|
Type: "mysql",
|
||||||
|
Prefix: "",
|
||||||
|
}
|
||||||
|
mysqlDB.initDialect()
|
||||||
|
|
||||||
|
// 测试 OR 与普通条件组合 (假设 A: 顺序问题)
|
||||||
|
t.Run("OR with normal condition", func(t *testing.T) {
|
||||||
|
data := Map{
|
||||||
|
"OR": Map{
|
||||||
|
"username": "test",
|
||||||
|
"phone": "123",
|
||||||
|
},
|
||||||
|
"state": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
where, params := mysqlDB.where(data)
|
||||||
|
fmt.Println("Test 1 - OR with normal condition:")
|
||||||
|
fmt.Println(" Generated WHERE:", where)
|
||||||
|
fmt.Println(" Params count:", len(params))
|
||||||
|
|
||||||
|
// 检查 OR 条件是否被括号包裹
|
||||||
|
if !strings.Contains(where, "(") || !strings.Contains(where, ")") {
|
||||||
|
t.Errorf("OR condition should be wrapped with parentheses, got: %s", where)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有 AND 连接
|
||||||
|
if !strings.Contains(where, "AND") {
|
||||||
|
t.Errorf("OR condition and normal condition should be connected with AND, got: %s", where)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 测试纯 OR 条件(无其他普通条件)
|
||||||
|
t.Run("Pure OR condition", func(t *testing.T) {
|
||||||
|
data := Map{
|
||||||
|
"OR": Map{
|
||||||
|
"username": "test",
|
||||||
|
"phone": "123",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
where, params := mysqlDB.where(data)
|
||||||
|
fmt.Println("Test 2 - Pure OR condition:")
|
||||||
|
fmt.Println(" Generated WHERE:", where)
|
||||||
|
fmt.Println(" Params count:", len(params))
|
||||||
|
|
||||||
|
// 检查 OR 条件内部应该用 OR 连接
|
||||||
|
if !strings.Contains(where, "OR") {
|
||||||
|
t.Errorf("OR condition should contain OR keyword, got: %s", where)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 测试多个普通条件与 OR 组合 (假设 A)
|
||||||
|
t.Run("OR with multiple normal conditions", func(t *testing.T) {
|
||||||
|
data := Map{
|
||||||
|
"OR": Map{
|
||||||
|
"username": "test",
|
||||||
|
"phone": "123",
|
||||||
|
},
|
||||||
|
"state": 0,
|
||||||
|
"status": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
where, params := mysqlDB.where(data)
|
||||||
|
fmt.Println("Test 3 - OR with multiple normal conditions:")
|
||||||
|
fmt.Println(" Generated WHERE:", where)
|
||||||
|
fmt.Println(" Params count:", len(params))
|
||||||
|
|
||||||
|
// 应该有括号
|
||||||
|
if !strings.Contains(where, "(") {
|
||||||
|
t.Errorf("OR condition should be wrapped with parentheses, got: %s", where)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 测试嵌套 AND/OR 条件 (假设 B, E)
|
||||||
|
t.Run("Nested AND/OR conditions", func(t *testing.T) {
|
||||||
|
data := Map{
|
||||||
|
"OR": Map{
|
||||||
|
"username": "test",
|
||||||
|
"AND": Map{
|
||||||
|
"phone": "123",
|
||||||
|
"status": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"state": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
where, params := mysqlDB.where(data)
|
||||||
|
fmt.Println("Test 4 - Nested AND/OR conditions:")
|
||||||
|
fmt.Println(" Generated WHERE:", where)
|
||||||
|
fmt.Println(" Params count:", len(params))
|
||||||
|
})
|
||||||
|
|
||||||
|
// 测试空 OR 条件 (假设 C)
|
||||||
|
t.Run("Empty OR condition", func(t *testing.T) {
|
||||||
|
data := Map{
|
||||||
|
"OR": Map{},
|
||||||
|
"state": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
where, params := mysqlDB.where(data)
|
||||||
|
fmt.Println("Test 5 - Empty OR condition:")
|
||||||
|
fmt.Println(" Generated WHERE:", where)
|
||||||
|
fmt.Println(" Params count:", len(params))
|
||||||
|
})
|
||||||
|
|
||||||
|
// 测试 OR 与 LIMIT, ORDER 组合 (假设 D)
|
||||||
|
t.Run("OR with LIMIT and ORDER", func(t *testing.T) {
|
||||||
|
data := Map{
|
||||||
|
"OR": Map{
|
||||||
|
"username": "test",
|
||||||
|
"phone": "123",
|
||||||
|
},
|
||||||
|
"state": 0,
|
||||||
|
"ORDER": "id DESC",
|
||||||
|
"LIMIT": 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
where, params := mysqlDB.where(data)
|
||||||
|
fmt.Println("Test 6 - OR with LIMIT and ORDER:")
|
||||||
|
fmt.Println(" Generated WHERE:", where)
|
||||||
|
fmt.Println(" Params count:", len(params))
|
||||||
|
})
|
||||||
|
|
||||||
|
// 测试同时有 OR 和 AND 关键字 (假设 E)
|
||||||
|
t.Run("Both OR and AND keywords", func(t *testing.T) {
|
||||||
|
data := Map{
|
||||||
|
"OR": Map{
|
||||||
|
"username": "test",
|
||||||
|
"phone": "123",
|
||||||
|
},
|
||||||
|
"AND": Map{
|
||||||
|
"type": 1,
|
||||||
|
"source": "web",
|
||||||
|
},
|
||||||
|
"state": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
where, params := mysqlDB.where(data)
|
||||||
|
fmt.Println("Test 7 - Both OR and AND keywords:")
|
||||||
|
fmt.Println(" Generated WHERE:", where)
|
||||||
|
fmt.Println(" Params count:", len(params))
|
||||||
|
})
|
||||||
|
|
||||||
|
// 测试普通条件在 OR 之前(排序后)(假设 A)
|
||||||
|
t.Run("Normal condition before OR alphabetically", func(t *testing.T) {
|
||||||
|
data := Map{
|
||||||
|
"OR": Map{
|
||||||
|
"username": "test",
|
||||||
|
"phone": "123",
|
||||||
|
},
|
||||||
|
"active": 1, // 'a' 在 'O' 之前
|
||||||
|
}
|
||||||
|
|
||||||
|
where, params := mysqlDB.where(data)
|
||||||
|
fmt.Println("Test 8 - Normal condition before OR (alphabetically):")
|
||||||
|
fmt.Println(" Generated WHERE:", where)
|
||||||
|
fmt.Println(" Params count:", len(params))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 打印测试结果(用于调试)
|
// 打印测试结果(用于调试)
|
||||||
func ExampleIdentifierProcessor() {
|
func ExampleIdentifierProcessor() {
|
||||||
// MySQL 示例
|
// MySQL 示例
|
||||||
|
|||||||
28
db/where.go
28
db/where.go
@ -70,8 +70,8 @@ func (that *HoTimeDB) where(data Map) (string, []interface{}) {
|
|||||||
}
|
}
|
||||||
sort.Strings(testQu)
|
sort.Strings(testQu)
|
||||||
|
|
||||||
// 追踪普通条件数量,用于自动添加 AND
|
// 追踪条件数量,用于自动添加 AND
|
||||||
normalCondCount := 0
|
condCount := 0
|
||||||
|
|
||||||
for _, k := range testQu {
|
for _, k := range testQu {
|
||||||
v := data[k]
|
v := data[k]
|
||||||
@ -79,8 +79,16 @@ func (that *HoTimeDB) where(data Map) (string, []interface{}) {
|
|||||||
// 检查是否是 AND/OR 条件关键字
|
// 检查是否是 AND/OR 条件关键字
|
||||||
if isConditionKey(k) {
|
if isConditionKey(k) {
|
||||||
tw, ts := that.cond(strings.ToUpper(k), v.(Map))
|
tw, ts := that.cond(strings.ToUpper(k), v.(Map))
|
||||||
where += tw
|
if tw != "" && strings.TrimSpace(tw) != "" {
|
||||||
res = append(res, ts...)
|
// 与前面的条件用 AND 连接
|
||||||
|
if condCount > 0 {
|
||||||
|
where += " AND "
|
||||||
|
}
|
||||||
|
// 用括号包裹 OR/AND 组条件
|
||||||
|
where += "(" + strings.TrimSpace(tw) + ")"
|
||||||
|
condCount++
|
||||||
|
res = append(res, ts...)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,11 +103,11 @@ func (that *HoTimeDB) where(data Map) (string, []interface{}) {
|
|||||||
// 检查是否是 NOT IN(带 [!] 后缀)- NOT IN 空数组永真,跳过即可
|
// 检查是否是 NOT IN(带 [!] 后缀)- NOT IN 空数组永真,跳过即可
|
||||||
if !strings.HasSuffix(k, "[!]") {
|
if !strings.HasSuffix(k, "[!]") {
|
||||||
// IN 空数组 -> 生成永假条件
|
// IN 空数组 -> 生成永假条件
|
||||||
if normalCondCount > 0 {
|
if condCount > 0 {
|
||||||
where += " AND "
|
where += " AND "
|
||||||
}
|
}
|
||||||
where += "1=0 "
|
where += "1=0 "
|
||||||
normalCondCount++
|
condCount++
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -107,11 +115,11 @@ func (that *HoTimeDB) where(data Map) (string, []interface{}) {
|
|||||||
// 检查是否是 NOT IN(带 [!] 后缀)- NOT IN 空数组永真,跳过即可
|
// 检查是否是 NOT IN(带 [!] 后缀)- NOT IN 空数组永真,跳过即可
|
||||||
if !strings.HasSuffix(k, "[!]") {
|
if !strings.HasSuffix(k, "[!]") {
|
||||||
// IN 空数组 -> 生成永假条件
|
// IN 空数组 -> 生成永假条件
|
||||||
if normalCondCount > 0 {
|
if condCount > 0 {
|
||||||
where += " AND "
|
where += " AND "
|
||||||
}
|
}
|
||||||
where += "1=0 "
|
where += "1=0 "
|
||||||
normalCondCount++
|
condCount++
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -119,11 +127,11 @@ func (that *HoTimeDB) where(data Map) (string, []interface{}) {
|
|||||||
tv, vv := that.varCond(k, v)
|
tv, vv := that.varCond(k, v)
|
||||||
if tv != "" {
|
if tv != "" {
|
||||||
// 自动添加 AND 连接符
|
// 自动添加 AND 连接符
|
||||||
if normalCondCount > 0 {
|
if condCount > 0 {
|
||||||
where += " AND "
|
where += " AND "
|
||||||
}
|
}
|
||||||
where += tv
|
where += tv
|
||||||
normalCondCount++
|
condCount++
|
||||||
res = append(res, vv...)
|
res = append(res, vv...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user