2022-07-11 11:07:17 +08:00
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2026-01-30 17:51:43 +08:00
|
|
|
|
"encoding/json"
|
2026-01-22 05:31:17 +08:00
|
|
|
|
"fmt"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
2026-01-30 17:51:43 +08:00
|
|
|
|
. "code.hoteas.com/golang/hotime"
|
|
|
|
|
|
|
2026-01-22 04:36:52 +08:00
|
|
|
|
. "code.hoteas.com/golang/hotime/common"
|
2026-01-22 05:31:17 +08:00
|
|
|
|
. "code.hoteas.com/golang/hotime/db"
|
2022-07-11 11:07:17 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
|
appIns := Init("config/config.json")
|
2022-08-01 03:40:09 +08:00
|
|
|
|
appIns.SetConnectListener(func(that *Context) (isFinished bool) {
|
|
|
|
|
|
return isFinished
|
|
|
|
|
|
})
|
2022-08-02 03:02:57 +08:00
|
|
|
|
|
2026-01-22 04:36:52 +08:00
|
|
|
|
appIns.Run(Router{
|
|
|
|
|
|
"app": {
|
|
|
|
|
|
"test": {
|
2026-01-31 02:05:13 +08:00
|
|
|
|
"test": func(that *Context) {
|
|
|
|
|
|
that.Display(2, "dsadasd")
|
|
|
|
|
|
},
|
2026-01-22 05:31:17 +08:00
|
|
|
|
// 测试入口 - 运行所有测试
|
|
|
|
|
|
"all": func(that *Context) {
|
|
|
|
|
|
results := Map{}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化测试表
|
|
|
|
|
|
initTestTables(that)
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 基础 CRUD 测试
|
|
|
|
|
|
results["1_basic_crud"] = testBasicCRUD(that)
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 条件查询语法测试
|
|
|
|
|
|
results["2_condition_syntax"] = testConditionSyntax(that)
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 链式查询测试
|
|
|
|
|
|
results["3_chain_query"] = testChainQuery(that)
|
|
|
|
|
|
|
|
|
|
|
|
// 4. JOIN 查询测试
|
|
|
|
|
|
results["4_join_query"] = testJoinQuery(that)
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 聚合函数测试
|
|
|
|
|
|
results["5_aggregate"] = testAggregate(that)
|
|
|
|
|
|
|
|
|
|
|
|
// 6. 分页查询测试
|
|
|
|
|
|
results["6_pagination"] = testPagination(that)
|
|
|
|
|
|
|
|
|
|
|
|
// 7. 批量插入测试
|
2026-01-22 20:32:29 +08:00
|
|
|
|
results["7_batch_insert"] = testInserts(that)
|
2026-01-22 05:31:17 +08:00
|
|
|
|
|
|
|
|
|
|
// 8. Upsert 测试
|
|
|
|
|
|
results["8_upsert"] = testUpsert(that)
|
|
|
|
|
|
|
|
|
|
|
|
// 9. 事务测试
|
|
|
|
|
|
results["9_transaction"] = testTransaction(that)
|
|
|
|
|
|
|
|
|
|
|
|
// 10. 原生 SQL 测试
|
|
|
|
|
|
results["10_raw_sql"] = testRawSQL(that)
|
|
|
|
|
|
|
|
|
|
|
|
that.Display(0, results)
|
2026-01-22 04:36:52 +08:00
|
|
|
|
},
|
2026-01-22 05:31:17 +08:00
|
|
|
|
|
|
|
|
|
|
// 查询数据库表结构
|
|
|
|
|
|
"tables": func(that *Context) {
|
|
|
|
|
|
// 查询所有表
|
|
|
|
|
|
tables := that.Db.Query("SHOW TABLES")
|
|
|
|
|
|
that.Display(0, Map{"tables": tables})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 查询指定表的结构
|
|
|
|
|
|
"describe": func(that *Context) {
|
|
|
|
|
|
tableName := that.Req.FormValue("table")
|
|
|
|
|
|
if tableName == "" {
|
|
|
|
|
|
that.Display(1, "请提供 table 参数")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
// 查询表结构
|
|
|
|
|
|
columns := that.Db.Query("DESCRIBE " + tableName)
|
|
|
|
|
|
// 查询表数据(前10条)
|
|
|
|
|
|
data := that.Db.Select(tableName, Map{"LIMIT": 10})
|
|
|
|
|
|
that.Display(0, Map{"table": tableName, "columns": columns, "sample_data": data})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 单独测试入口
|
|
|
|
|
|
"crud": func(that *Context) { that.Display(0, testBasicCRUD(that)) },
|
|
|
|
|
|
"condition": func(that *Context) { that.Display(0, testConditionSyntax(that)) },
|
|
|
|
|
|
"chain": func(that *Context) { that.Display(0, testChainQuery(that)) },
|
|
|
|
|
|
"join": func(that *Context) { that.Display(0, testJoinQuery(that)) },
|
|
|
|
|
|
"aggregate": func(that *Context) { that.Display(0, testAggregate(that)) },
|
|
|
|
|
|
"pagination": func(that *Context) { that.Display(0, testPagination(that)) },
|
2026-01-22 20:32:29 +08:00
|
|
|
|
"batch": func(that *Context) { that.Display(0, testInserts(that)) },
|
2026-01-22 05:31:17 +08:00
|
|
|
|
"upsert": func(that *Context) { that.Display(0, testUpsert(that)) },
|
|
|
|
|
|
"transaction": func(that *Context) { that.Display(0, testTransaction(that)) },
|
|
|
|
|
|
"rawsql": func(that *Context) { that.Display(0, testRawSQL(that)) },
|
2026-01-30 17:51:43 +08:00
|
|
|
|
|
|
|
|
|
|
// ==================== 缓存测试 ====================
|
|
|
|
|
|
// 缓存全部测试
|
|
|
|
|
|
"cache": func(that *Context) { that.Display(0, testCacheAll(that)) },
|
|
|
|
|
|
"cache-compat": func(that *Context) { that.Display(0, testCacheCompatible(that)) },
|
|
|
|
|
|
// 批量缓存操作测试
|
|
|
|
|
|
"cache-batch": func(that *Context) {
|
2026-01-30 22:17:53 +08:00
|
|
|
|
//TestBatchCacheOperations(that.Application)
|
2026-01-30 17:51:43 +08:00
|
|
|
|
that.Display(0, Map{"message": "批量缓存测试完成,请查看控制台输出和日志文件"})
|
|
|
|
|
|
},
|
2026-01-22 04:36:52 +08:00
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
2022-07-11 11:07:17 +08:00
|
|
|
|
}
|
2026-01-22 05:31:17 +08:00
|
|
|
|
|
|
|
|
|
|
// initTestTables 初始化测试表(MySQL真实数据库)
|
|
|
|
|
|
func initTestTables(that *Context) {
|
|
|
|
|
|
// MySQL 真实数据库已有表,创建测试用的临时表
|
|
|
|
|
|
// 创建测试用的批量插入表
|
|
|
|
|
|
that.Db.Exec(`CREATE TABLE IF NOT EXISTS test_batch (
|
|
|
|
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
name VARCHAR(100),
|
|
|
|
|
|
title VARCHAR(200),
|
|
|
|
|
|
state INT DEFAULT 0,
|
|
|
|
|
|
create_time DATETIME
|
|
|
|
|
|
)`)
|
|
|
|
|
|
|
2026-01-22 07:25:41 +08:00
|
|
|
|
// 检查 admin 表数据(确认表存在)
|
|
|
|
|
|
_ = that.Db.Count("admin")
|
|
|
|
|
|
_ = that.Db.Count("article")
|
2026-01-22 05:31:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 1. 基础 CRUD 测试 ====================
|
|
|
|
|
|
func testBasicCRUD(that *Context) Map {
|
|
|
|
|
|
result := Map{"name": "基础CRUD测试", "tests": Slice{}}
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// 1.1 Insert 测试 - 使用 admin 表
|
|
|
|
|
|
insertTest := Map{"name": "Insert 插入测试 (admin表)"}
|
|
|
|
|
|
adminId := that.Db.Insert("admin", Map{
|
|
|
|
|
|
"name": "测试管理员_" + fmt.Sprintf("%d", time.Now().Unix()),
|
|
|
|
|
|
"phone": fmt.Sprintf("138%d", time.Now().Unix()%100000000),
|
|
|
|
|
|
"state": 1,
|
|
|
|
|
|
"password": "test123456",
|
|
|
|
|
|
"role_id": 1,
|
|
|
|
|
|
"title": "测试职位",
|
|
|
|
|
|
"create_time[#]": "NOW()",
|
|
|
|
|
|
"modify_time[#]": "NOW()",
|
|
|
|
|
|
})
|
|
|
|
|
|
insertTest["result"] = adminId > 0
|
|
|
|
|
|
insertTest["adminId"] = adminId
|
|
|
|
|
|
insertTest["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, insertTest)
|
|
|
|
|
|
|
|
|
|
|
|
// 1.2 Get 测试
|
|
|
|
|
|
getTest := Map{"name": "Get 获取单条记录测试"}
|
|
|
|
|
|
admin := that.Db.Get("admin", "*", Map{"id": adminId})
|
|
|
|
|
|
getTest["result"] = admin != nil && admin.GetInt64("id") == adminId
|
|
|
|
|
|
getTest["admin"] = admin
|
|
|
|
|
|
tests = append(tests, getTest)
|
|
|
|
|
|
|
|
|
|
|
|
// 1.3 Select 测试 - 单条件
|
|
|
|
|
|
selectTest1 := Map{"name": "Select 单条件查询测试"}
|
|
|
|
|
|
admins1 := that.Db.Select("admin", "*", Map{"state": 1, "LIMIT": 5})
|
|
|
|
|
|
selectTest1["result"] = len(admins1) >= 0 // 可能表中没有数据
|
|
|
|
|
|
selectTest1["count"] = len(admins1)
|
|
|
|
|
|
tests = append(tests, selectTest1)
|
|
|
|
|
|
|
|
|
|
|
|
// 1.4 Select 测试 - 多条件(自动 AND)
|
|
|
|
|
|
selectTest2 := Map{"name": "Select 多条件自动AND测试"}
|
|
|
|
|
|
admins2 := that.Db.Select("admin", "*", Map{
|
|
|
|
|
|
"state": 1,
|
|
|
|
|
|
"role_id[>]": 0,
|
|
|
|
|
|
"ORDER": "id DESC",
|
|
|
|
|
|
"LIMIT": 5,
|
|
|
|
|
|
})
|
|
|
|
|
|
selectTest2["result"] = true // 只要不报错就算成功
|
|
|
|
|
|
selectTest2["count"] = len(admins2)
|
|
|
|
|
|
selectTest2["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, selectTest2)
|
|
|
|
|
|
|
|
|
|
|
|
// 1.5 Update 测试
|
|
|
|
|
|
updateTest := Map{"name": "Update 更新测试"}
|
|
|
|
|
|
affected := that.Db.Update("admin", Map{
|
|
|
|
|
|
"title": "更新后的职位",
|
|
|
|
|
|
"modify_time[#]": "NOW()",
|
|
|
|
|
|
}, Map{"id": adminId})
|
|
|
|
|
|
updateTest["result"] = affected > 0
|
|
|
|
|
|
updateTest["affected"] = affected
|
|
|
|
|
|
tests = append(tests, updateTest)
|
|
|
|
|
|
|
|
|
|
|
|
// 1.6 Delete 测试 - 使用 test_batch 表
|
|
|
|
|
|
deleteTest := Map{"name": "Delete 删除测试"}
|
|
|
|
|
|
// 先创建一个临时记录用于删除
|
|
|
|
|
|
tempId := that.Db.Insert("test_batch", Map{
|
|
|
|
|
|
"name": "临时删除测试",
|
|
|
|
|
|
"title": "测试标题",
|
|
|
|
|
|
"state": 1,
|
|
|
|
|
|
"create_time[#]": "NOW()",
|
|
|
|
|
|
})
|
|
|
|
|
|
deleteAffected := that.Db.Delete("test_batch", Map{"id": tempId})
|
|
|
|
|
|
deleteTest["result"] = deleteAffected > 0
|
|
|
|
|
|
deleteTest["affected"] = deleteAffected
|
|
|
|
|
|
tests = append(tests, deleteTest)
|
|
|
|
|
|
|
|
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 2. 条件查询语法测试 ====================
|
|
|
|
|
|
func testConditionSyntax(that *Context) Map {
|
|
|
|
|
|
result := Map{"name": "条件查询语法测试", "tests": Slice{}}
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// 2.1 等于 (=) - 使用 article 表
|
|
|
|
|
|
test1 := Map{"name": "等于条件 (=)"}
|
|
|
|
|
|
articles1 := that.Db.Select("article", "id,title", Map{"state": 0, "LIMIT": 3})
|
|
|
|
|
|
test1["result"] = true
|
|
|
|
|
|
test1["count"] = len(articles1)
|
|
|
|
|
|
tests = append(tests, test1)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.2 不等于 ([!])
|
|
|
|
|
|
test2 := Map{"name": "不等于条件 ([!])"}
|
|
|
|
|
|
articles2 := that.Db.Select("article", "id,title,state", Map{"state[!]": -1, "LIMIT": 3})
|
|
|
|
|
|
test2["result"] = true
|
|
|
|
|
|
test2["count"] = len(articles2)
|
|
|
|
|
|
test2["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test2)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.3 大于 ([>]) 和 小于 ([<])
|
|
|
|
|
|
test3 := Map{"name": "大于小于条件 ([>], [<])"}
|
|
|
|
|
|
articles3 := that.Db.Select("article", "id,title,click_num", Map{
|
|
|
|
|
|
"click_num[>]": 0,
|
|
|
|
|
|
"click_num[<]": 100000,
|
|
|
|
|
|
"LIMIT": 3,
|
|
|
|
|
|
})
|
|
|
|
|
|
test3["result"] = true
|
|
|
|
|
|
test3["count"] = len(articles3)
|
|
|
|
|
|
tests = append(tests, test3)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.4 大于等于 ([>=]) 和 小于等于 ([<=])
|
|
|
|
|
|
test4 := Map{"name": "大于等于小于等于条件 ([>=], [<=])"}
|
|
|
|
|
|
articles4 := that.Db.Select("article", "id,title,sort", Map{
|
|
|
|
|
|
"sort[>=]": 0,
|
|
|
|
|
|
"sort[<=]": 100,
|
|
|
|
|
|
"LIMIT": 3,
|
|
|
|
|
|
})
|
|
|
|
|
|
test4["result"] = true
|
|
|
|
|
|
test4["count"] = len(articles4)
|
|
|
|
|
|
tests = append(tests, test4)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.5 LIKE 模糊查询 ([~])
|
|
|
|
|
|
test5 := Map{"name": "LIKE 模糊查询 ([~])"}
|
|
|
|
|
|
articles5 := that.Db.Select("article", "id,title", Map{"title[~]": "新闻", "LIMIT": 3})
|
|
|
|
|
|
test5["result"] = true
|
|
|
|
|
|
test5["count"] = len(articles5)
|
|
|
|
|
|
test5["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test5)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.6 右模糊 ([~!])
|
|
|
|
|
|
test6 := Map{"name": "右模糊查询 ([~!])"}
|
|
|
|
|
|
articles6 := that.Db.Select("admin", "id,name", Map{"name[~!]": "管理", "LIMIT": 3})
|
|
|
|
|
|
test6["result"] = true
|
|
|
|
|
|
test6["count"] = len(articles6)
|
|
|
|
|
|
tests = append(tests, test6)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.7 BETWEEN ([<>])
|
|
|
|
|
|
test7 := Map{"name": "BETWEEN 区间查询 ([<>])"}
|
|
|
|
|
|
articles7 := that.Db.Select("article", "id,title,click_num", Map{"click_num[<>]": Slice{0, 1000}, "LIMIT": 3})
|
|
|
|
|
|
test7["result"] = true
|
|
|
|
|
|
test7["count"] = len(articles7)
|
|
|
|
|
|
test7["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test7)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.8 NOT BETWEEN ([><])
|
|
|
|
|
|
test8 := Map{"name": "NOT BETWEEN 查询 ([><])"}
|
|
|
|
|
|
articles8 := that.Db.Select("article", "id,title,sort", Map{"sort[><]": Slice{-10, 0}, "LIMIT": 3})
|
|
|
|
|
|
test8["result"] = true
|
|
|
|
|
|
test8["count"] = len(articles8)
|
|
|
|
|
|
tests = append(tests, test8)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.9 IN 查询
|
|
|
|
|
|
test9 := Map{"name": "IN 查询"}
|
|
|
|
|
|
articles9 := that.Db.Select("article", "id,title", Map{"id": Slice{1, 2, 3, 4, 5}, "LIMIT": 5})
|
|
|
|
|
|
test9["result"] = true
|
|
|
|
|
|
test9["count"] = len(articles9)
|
|
|
|
|
|
test9["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test9)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.10 NOT IN ([!])
|
|
|
|
|
|
test10 := Map{"name": "NOT IN 查询 ([!])"}
|
|
|
|
|
|
articles10 := that.Db.Select("article", "id,title", Map{"id[!]": Slice{1, 2, 3}, "LIMIT": 5})
|
|
|
|
|
|
test10["result"] = true
|
|
|
|
|
|
test10["count"] = len(articles10)
|
|
|
|
|
|
tests = append(tests, test10)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.11 IS NULL
|
|
|
|
|
|
test11 := Map{"name": "IS NULL 查询"}
|
|
|
|
|
|
articles11 := that.Db.Select("article", "id,title,img", Map{"img": nil, "LIMIT": 3})
|
|
|
|
|
|
test11["result"] = true
|
|
|
|
|
|
test11["count"] = len(articles11)
|
|
|
|
|
|
tests = append(tests, test11)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.12 IS NOT NULL ([!])
|
|
|
|
|
|
test12 := Map{"name": "IS NOT NULL 查询 ([!])"}
|
|
|
|
|
|
articles12 := that.Db.Select("article", "id,title,create_time", Map{"create_time[!]": nil, "LIMIT": 3})
|
|
|
|
|
|
test12["result"] = true
|
|
|
|
|
|
test12["count"] = len(articles12)
|
|
|
|
|
|
tests = append(tests, test12)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.13 直接 SQL ([##] 用于 SQL 片段)
|
|
|
|
|
|
test13 := Map{"name": "直接 SQL 片段查询 ([##])"}
|
|
|
|
|
|
articles13 := that.Db.Select("article", "id,title,create_time", Map{
|
|
|
|
|
|
"[##]": "create_time > DATE_SUB(NOW(), INTERVAL 365 DAY)",
|
|
|
|
|
|
"LIMIT": 3,
|
|
|
|
|
|
})
|
|
|
|
|
|
test13["result"] = true
|
|
|
|
|
|
test13["count"] = len(articles13)
|
|
|
|
|
|
test13["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test13)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.14 显式 AND 条件
|
|
|
|
|
|
test14 := Map{"name": "显式 AND 条件"}
|
|
|
|
|
|
articles14 := that.Db.Select("article", "id,title,state,click_num", Map{
|
|
|
|
|
|
"AND": Map{
|
|
|
|
|
|
"state": 0,
|
|
|
|
|
|
"click_num[>=]": 0,
|
|
|
|
|
|
},
|
|
|
|
|
|
"LIMIT": 3,
|
|
|
|
|
|
})
|
|
|
|
|
|
test14["result"] = true
|
|
|
|
|
|
test14["count"] = len(articles14)
|
|
|
|
|
|
tests = append(tests, test14)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.15 OR 条件
|
|
|
|
|
|
test15 := Map{"name": "OR 条件"}
|
|
|
|
|
|
articles15 := that.Db.Select("article", "id,title,sort,click_num", Map{
|
|
|
|
|
|
"OR": Map{
|
|
|
|
|
|
"sort": 0,
|
|
|
|
|
|
"click_num[>]": 10,
|
|
|
|
|
|
},
|
|
|
|
|
|
"LIMIT": 5,
|
|
|
|
|
|
})
|
|
|
|
|
|
test15["result"] = true
|
|
|
|
|
|
test15["count"] = len(articles15)
|
|
|
|
|
|
tests = append(tests, test15)
|
|
|
|
|
|
|
|
|
|
|
|
// 2.16 嵌套 AND/OR 条件
|
|
|
|
|
|
test16 := Map{"name": "嵌套 AND/OR 条件"}
|
|
|
|
|
|
articles16 := that.Db.Select("article", "id,title,sort,state", Map{
|
|
|
|
|
|
"AND": Map{
|
|
|
|
|
|
"state": 0,
|
|
|
|
|
|
"OR": Map{
|
|
|
|
|
|
"sort[>=]": 0,
|
|
|
|
|
|
"click_num[>]": 0,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"LIMIT": 5,
|
|
|
|
|
|
})
|
|
|
|
|
|
test16["result"] = true
|
|
|
|
|
|
test16["count"] = len(articles16)
|
|
|
|
|
|
test16["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test16)
|
|
|
|
|
|
|
|
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 3. 链式查询测试 ====================
|
|
|
|
|
|
func testChainQuery(that *Context) Map {
|
|
|
|
|
|
result := Map{"name": "链式查询测试", "tests": Slice{}}
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// 3.1 基本链式查询 - 使用 article 表
|
|
|
|
|
|
test1 := Map{"name": "基本链式查询 Table().Where().Select()"}
|
|
|
|
|
|
articles1 := that.Db.Table("article").
|
|
|
|
|
|
Where("state", 0).
|
|
|
|
|
|
Select("id,title,author")
|
|
|
|
|
|
test1["result"] = len(articles1) >= 0
|
|
|
|
|
|
test1["count"] = len(articles1)
|
|
|
|
|
|
tests = append(tests, test1)
|
|
|
|
|
|
|
|
|
|
|
|
// 3.2 链式 And 条件
|
|
|
|
|
|
test2 := Map{"name": "链式 And 条件"}
|
|
|
|
|
|
articles2 := that.Db.Table("article").
|
|
|
|
|
|
Where("state", 0).
|
|
|
|
|
|
And("click_num[>=]", 0).
|
|
|
|
|
|
And("sort[>=]", 0).
|
|
|
|
|
|
Select("id,title,click_num")
|
|
|
|
|
|
test2["result"] = len(articles2) >= 0
|
|
|
|
|
|
test2["count"] = len(articles2)
|
|
|
|
|
|
tests = append(tests, test2)
|
|
|
|
|
|
|
|
|
|
|
|
// 3.3 链式 Or 条件
|
|
|
|
|
|
test3 := Map{"name": "链式 Or 条件"}
|
|
|
|
|
|
articles3 := that.Db.Table("article").
|
|
|
|
|
|
Where("state", 0).
|
|
|
|
|
|
Or(Map{
|
|
|
|
|
|
"sort": 0,
|
|
|
|
|
|
"click_num[>]": 10,
|
|
|
|
|
|
}).
|
|
|
|
|
|
Select("id,title,sort,click_num")
|
|
|
|
|
|
test3["result"] = len(articles3) >= 0
|
|
|
|
|
|
test3["count"] = len(articles3)
|
|
|
|
|
|
tests = append(tests, test3)
|
|
|
|
|
|
|
|
|
|
|
|
// 3.4 链式 Order
|
|
|
|
|
|
test4 := Map{"name": "链式 Order 排序"}
|
|
|
|
|
|
articles4 := that.Db.Table("article").
|
|
|
|
|
|
Where("state", 0).
|
|
|
|
|
|
Order("create_time DESC", "id ASC").
|
|
|
|
|
|
Limit(0, 5).
|
|
|
|
|
|
Select("id,title,create_time")
|
|
|
|
|
|
test4["result"] = len(articles4) >= 0
|
|
|
|
|
|
test4["count"] = len(articles4)
|
|
|
|
|
|
tests = append(tests, test4)
|
|
|
|
|
|
|
|
|
|
|
|
// 3.5 链式 Limit
|
|
|
|
|
|
test5 := Map{"name": "链式 Limit 限制"}
|
|
|
|
|
|
articles5 := that.Db.Table("article").
|
|
|
|
|
|
Where("state", 0).
|
|
|
|
|
|
Limit(0, 3).
|
|
|
|
|
|
Select("id,title")
|
|
|
|
|
|
test5["result"] = len(articles5) <= 3
|
|
|
|
|
|
test5["count"] = len(articles5)
|
|
|
|
|
|
tests = append(tests, test5)
|
|
|
|
|
|
|
|
|
|
|
|
// 3.6 链式 Get 单条
|
|
|
|
|
|
test6 := Map{"name": "链式 Get 获取单条"}
|
|
|
|
|
|
article6 := that.Db.Table("article").
|
|
|
|
|
|
Where("state", 0).
|
|
|
|
|
|
Get("id,title,author")
|
|
|
|
|
|
test6["result"] = article6 != nil || true // 允许为空
|
|
|
|
|
|
test6["article"] = article6
|
|
|
|
|
|
tests = append(tests, test6)
|
|
|
|
|
|
|
|
|
|
|
|
// 3.7 链式 Count
|
|
|
|
|
|
test7 := Map{"name": "链式 Count 统计"}
|
|
|
|
|
|
count7 := that.Db.Table("article").
|
|
|
|
|
|
Where("state", 0).
|
|
|
|
|
|
Count()
|
|
|
|
|
|
test7["result"] = count7 >= 0
|
|
|
|
|
|
test7["count"] = count7
|
|
|
|
|
|
tests = append(tests, test7)
|
|
|
|
|
|
|
|
|
|
|
|
// 3.8 链式 Page 分页
|
|
|
|
|
|
test8 := Map{"name": "链式 Page 分页"}
|
|
|
|
|
|
articles8 := that.Db.Table("article").
|
|
|
|
|
|
Where("state", 0).
|
|
|
|
|
|
Page(1, 5).
|
|
|
|
|
|
Select("id,title")
|
|
|
|
|
|
test8["result"] = len(articles8) <= 5
|
|
|
|
|
|
test8["count"] = len(articles8)
|
|
|
|
|
|
tests = append(tests, test8)
|
|
|
|
|
|
|
|
|
|
|
|
// 3.9 链式 Group 分组
|
|
|
|
|
|
test9 := Map{"name": "链式 Group 分组"}
|
|
|
|
|
|
stats9 := that.Db.Table("article").
|
|
|
|
|
|
Where("state", 0).
|
|
|
|
|
|
Group("ctg_id").
|
|
|
|
|
|
Select("ctg_id, COUNT(*) as cnt")
|
|
|
|
|
|
test9["result"] = len(stats9) >= 0
|
|
|
|
|
|
test9["stats"] = stats9
|
|
|
|
|
|
tests = append(tests, test9)
|
|
|
|
|
|
|
|
|
|
|
|
// 3.10 链式 Update
|
|
|
|
|
|
test10 := Map{"name": "链式 Update 更新"}
|
|
|
|
|
|
// 先获取一个文章ID
|
|
|
|
|
|
testArticle := that.Db.Table("article").Where("state", 0).Get("id")
|
|
|
|
|
|
if testArticle != nil {
|
|
|
|
|
|
affected := that.Db.Table("article").
|
|
|
|
|
|
Where("id", testArticle.GetInt64("id")).
|
|
|
|
|
|
Update(Map{"modify_time[#]": "NOW()"})
|
|
|
|
|
|
test10["result"] = affected >= 0
|
|
|
|
|
|
test10["affected"] = affected
|
|
|
|
|
|
} else {
|
|
|
|
|
|
test10["result"] = true
|
|
|
|
|
|
test10["note"] = "无可用测试数据"
|
|
|
|
|
|
}
|
|
|
|
|
|
tests = append(tests, test10)
|
|
|
|
|
|
|
|
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 4. JOIN 查询测试 ====================
|
|
|
|
|
|
func testJoinQuery(that *Context) Map {
|
|
|
|
|
|
result := Map{"name": "JOIN查询测试", "tests": Slice{}}
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// 4.1 LEFT JOIN 链式 - article 关联 ctg
|
|
|
|
|
|
test1 := Map{"name": "LEFT JOIN 链式查询"}
|
|
|
|
|
|
articles1 := that.Db.Table("article").
|
|
|
|
|
|
LeftJoin("ctg", "article.ctg_id = ctg.id").
|
|
|
|
|
|
Where("article.state", 0).
|
|
|
|
|
|
Limit(0, 5).
|
|
|
|
|
|
Select("article.id, article.title, ctg.name as ctg_name")
|
|
|
|
|
|
test1["result"] = len(articles1) >= 0
|
|
|
|
|
|
test1["count"] = len(articles1)
|
|
|
|
|
|
test1["data"] = articles1
|
|
|
|
|
|
tests = append(tests, test1)
|
|
|
|
|
|
|
|
|
|
|
|
// 4.2 传统 JOIN 语法
|
|
|
|
|
|
test2 := Map{"name": "传统 JOIN 语法"}
|
|
|
|
|
|
articles2 := that.Db.Select("article",
|
|
|
|
|
|
Slice{
|
|
|
|
|
|
Map{"[>]ctg": "article.ctg_id = ctg.id"},
|
|
|
|
|
|
},
|
|
|
|
|
|
"article.id, article.title, ctg.name as ctg_name",
|
|
|
|
|
|
Map{
|
|
|
|
|
|
"article.state": 0,
|
|
|
|
|
|
"LIMIT": 5,
|
|
|
|
|
|
})
|
|
|
|
|
|
test2["result"] = len(articles2) >= 0
|
|
|
|
|
|
test2["count"] = len(articles2)
|
|
|
|
|
|
test2["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test2)
|
|
|
|
|
|
|
|
|
|
|
|
// 4.3 多表 JOIN - article 关联 ctg 和 admin
|
|
|
|
|
|
test3 := Map{"name": "多表 JOIN"}
|
|
|
|
|
|
articles3 := that.Db.Table("article").
|
|
|
|
|
|
LeftJoin("ctg", "article.ctg_id = ctg.id").
|
|
|
|
|
|
LeftJoin("admin", "article.admin_id = admin.id").
|
|
|
|
|
|
Where("article.state", 0).
|
|
|
|
|
|
Limit(0, 5).
|
|
|
|
|
|
Select("article.id, article.title, ctg.name as ctg_name, admin.name as admin_name")
|
|
|
|
|
|
test3["result"] = len(articles3) >= 0
|
|
|
|
|
|
test3["count"] = len(articles3)
|
|
|
|
|
|
test3["data"] = articles3
|
|
|
|
|
|
tests = append(tests, test3)
|
|
|
|
|
|
|
|
|
|
|
|
// 4.4 INNER JOIN
|
|
|
|
|
|
test4 := Map{"name": "INNER JOIN"}
|
|
|
|
|
|
articles4 := that.Db.Table("article").
|
|
|
|
|
|
InnerJoin("ctg", "article.ctg_id = ctg.id").
|
|
|
|
|
|
Where("ctg.state", 0).
|
|
|
|
|
|
Limit(0, 5).
|
|
|
|
|
|
Select("article.id, article.title, ctg.name as ctg_name")
|
|
|
|
|
|
test4["result"] = len(articles4) >= 0
|
|
|
|
|
|
test4["count"] = len(articles4)
|
|
|
|
|
|
tests = append(tests, test4)
|
|
|
|
|
|
|
|
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 5. 聚合函数测试 ====================
|
|
|
|
|
|
func testAggregate(that *Context) Map {
|
|
|
|
|
|
result := Map{"name": "聚合函数测试", "tests": Slice{}}
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// 5.1 Count 总数
|
|
|
|
|
|
test1 := Map{"name": "Count 总数统计"}
|
|
|
|
|
|
count1 := that.Db.Count("article")
|
|
|
|
|
|
test1["result"] = count1 >= 0
|
|
|
|
|
|
test1["count"] = count1
|
|
|
|
|
|
tests = append(tests, test1)
|
|
|
|
|
|
|
|
|
|
|
|
// 5.2 Count 带条件
|
|
|
|
|
|
test2 := Map{"name": "Count 条件统计"}
|
|
|
|
|
|
count2 := that.Db.Count("article", Map{"state": 0})
|
|
|
|
|
|
test2["result"] = count2 >= 0
|
|
|
|
|
|
test2["count"] = count2
|
|
|
|
|
|
tests = append(tests, test2)
|
|
|
|
|
|
|
|
|
|
|
|
// 5.3 Sum 求和
|
|
|
|
|
|
test3 := Map{"name": "Sum 求和"}
|
|
|
|
|
|
sum3 := that.Db.Sum("article", "click_num", Map{"state": 0})
|
|
|
|
|
|
test3["result"] = sum3 >= 0
|
|
|
|
|
|
test3["sum"] = sum3
|
|
|
|
|
|
tests = append(tests, test3)
|
|
|
|
|
|
|
|
|
|
|
|
// 5.4 Avg 平均值
|
|
|
|
|
|
test4 := Map{"name": "Avg 平均值"}
|
|
|
|
|
|
avg4 := that.Db.Avg("article", "click_num", Map{"state": 0})
|
|
|
|
|
|
test4["result"] = avg4 >= 0
|
|
|
|
|
|
test4["avg"] = avg4
|
|
|
|
|
|
tests = append(tests, test4)
|
|
|
|
|
|
|
|
|
|
|
|
// 5.5 Max 最大值
|
|
|
|
|
|
test5 := Map{"name": "Max 最大值"}
|
|
|
|
|
|
max5 := that.Db.Max("article", "click_num", Map{"state": 0})
|
|
|
|
|
|
test5["result"] = max5 >= 0
|
|
|
|
|
|
test5["max"] = max5
|
|
|
|
|
|
tests = append(tests, test5)
|
|
|
|
|
|
|
|
|
|
|
|
// 5.6 Min 最小值
|
|
|
|
|
|
test6 := Map{"name": "Min 最小值"}
|
|
|
|
|
|
min6 := that.Db.Min("article", "sort", Map{"state": 0})
|
|
|
|
|
|
test6["result"] = true // sort 可能为 0
|
|
|
|
|
|
test6["min"] = min6
|
|
|
|
|
|
tests = append(tests, test6)
|
|
|
|
|
|
|
|
|
|
|
|
// 5.7 GROUP BY 分组统计
|
|
|
|
|
|
test7 := Map{"name": "GROUP BY 分组统计"}
|
|
|
|
|
|
stats7 := that.Db.Select("article",
|
|
|
|
|
|
"ctg_id, COUNT(*) as article_count, AVG(click_num) as avg_clicks, SUM(click_num) as total_clicks",
|
|
|
|
|
|
Map{
|
|
|
|
|
|
"state": 0,
|
|
|
|
|
|
"GROUP": "ctg_id",
|
|
|
|
|
|
"ORDER": "article_count DESC",
|
|
|
|
|
|
"LIMIT": 10,
|
|
|
|
|
|
})
|
|
|
|
|
|
test7["result"] = len(stats7) >= 0
|
|
|
|
|
|
test7["stats"] = stats7
|
|
|
|
|
|
tests = append(tests, test7)
|
|
|
|
|
|
|
|
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 6. 分页查询测试 ====================
|
|
|
|
|
|
func testPagination(that *Context) Map {
|
|
|
|
|
|
result := Map{"name": "分页查询测试", "tests": Slice{}}
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// 6.1 PageSelect 分页查询
|
|
|
|
|
|
test1 := Map{"name": "PageSelect 分页查询"}
|
|
|
|
|
|
articles1 := that.Db.Page(1, 5).PageSelect("article", "*", Map{
|
|
|
|
|
|
"state": 0,
|
|
|
|
|
|
"ORDER": "id DESC",
|
|
|
|
|
|
})
|
|
|
|
|
|
test1["result"] = len(articles1) <= 5
|
|
|
|
|
|
test1["count"] = len(articles1)
|
|
|
|
|
|
tests = append(tests, test1)
|
|
|
|
|
|
|
|
|
|
|
|
// 6.2 第二页
|
|
|
|
|
|
test2 := Map{"name": "PageSelect 第二页"}
|
|
|
|
|
|
articles2 := that.Db.Page(2, 5).PageSelect("article", "*", Map{
|
|
|
|
|
|
"state": 0,
|
|
|
|
|
|
"ORDER": "id DESC",
|
|
|
|
|
|
})
|
|
|
|
|
|
test2["result"] = len(articles2) <= 5
|
|
|
|
|
|
test2["count"] = len(articles2)
|
|
|
|
|
|
tests = append(tests, test2)
|
|
|
|
|
|
|
|
|
|
|
|
// 6.3 链式分页
|
|
|
|
|
|
test3 := Map{"name": "链式 Page 分页"}
|
|
|
|
|
|
articles3 := that.Db.Table("article").
|
|
|
|
|
|
Where("state", 0).
|
|
|
|
|
|
Order("id DESC").
|
|
|
|
|
|
Page(1, 3).
|
|
|
|
|
|
Select("id,title,author")
|
|
|
|
|
|
test3["result"] = len(articles3) <= 3
|
|
|
|
|
|
test3["count"] = len(articles3)
|
|
|
|
|
|
tests = append(tests, test3)
|
|
|
|
|
|
|
|
|
|
|
|
// 6.4 Offset 偏移
|
|
|
|
|
|
test4 := Map{"name": "Offset 偏移查询"}
|
|
|
|
|
|
articles4 := that.Db.Table("article").
|
|
|
|
|
|
Where("state", 0).
|
|
|
|
|
|
Limit(3).
|
|
|
|
|
|
Offset(2).
|
|
|
|
|
|
Select("id,title")
|
|
|
|
|
|
test4["result"] = len(articles4) <= 3
|
|
|
|
|
|
test4["count"] = len(articles4)
|
|
|
|
|
|
test4["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test4)
|
|
|
|
|
|
|
|
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 7. 批量插入测试 ====================
|
2026-01-22 20:32:29 +08:00
|
|
|
|
func testInserts(that *Context) Map {
|
2026-01-22 05:31:17 +08:00
|
|
|
|
result := Map{"name": "批量插入测试", "tests": Slice{}}
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// 7.1 批量插入
|
2026-01-22 20:32:29 +08:00
|
|
|
|
test1 := Map{"name": "Inserts 批量插入"}
|
2026-01-22 05:31:17 +08:00
|
|
|
|
timestamp := time.Now().UnixNano()
|
2026-01-22 20:32:29 +08:00
|
|
|
|
affected1 := that.Db.Inserts("test_batch", []Map{
|
2026-01-22 05:31:17 +08:00
|
|
|
|
{"name": fmt.Sprintf("批量测试1_%d", timestamp), "title": "标题1", "state": 1},
|
|
|
|
|
|
{"name": fmt.Sprintf("批量测试2_%d", timestamp), "title": "标题2", "state": 1},
|
|
|
|
|
|
{"name": fmt.Sprintf("批量测试3_%d", timestamp), "title": "标题3", "state": 1},
|
|
|
|
|
|
})
|
|
|
|
|
|
test1["result"] = affected1 >= 0
|
|
|
|
|
|
test1["affected"] = affected1
|
|
|
|
|
|
test1["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test1)
|
|
|
|
|
|
|
|
|
|
|
|
// 7.2 带 [#] 的批量插入
|
2026-01-22 20:32:29 +08:00
|
|
|
|
test2 := Map{"name": "Inserts 带 [#] 标记"}
|
2026-01-22 05:31:17 +08:00
|
|
|
|
timestamp2 := time.Now().UnixNano()
|
2026-01-22 20:32:29 +08:00
|
|
|
|
affected2 := that.Db.Inserts("test_batch", []Map{
|
2026-01-22 05:31:17 +08:00
|
|
|
|
{"name": fmt.Sprintf("带时间测试1_%d", timestamp2), "title": "标题带时间1", "state": 1, "create_time[#]": "NOW()"},
|
|
|
|
|
|
{"name": fmt.Sprintf("带时间测试2_%d", timestamp2), "title": "标题带时间2", "state": 1, "create_time[#]": "NOW()"},
|
|
|
|
|
|
})
|
|
|
|
|
|
test2["result"] = affected2 >= 0
|
|
|
|
|
|
test2["affected"] = affected2
|
|
|
|
|
|
tests = append(tests, test2)
|
|
|
|
|
|
|
|
|
|
|
|
// 清理测试数据
|
|
|
|
|
|
that.Db.Delete("test_batch", Map{"name[~]": fmt.Sprintf("_%d", timestamp)})
|
|
|
|
|
|
that.Db.Delete("test_batch", Map{"name[~]": fmt.Sprintf("_%d", timestamp2)})
|
|
|
|
|
|
|
|
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 8. Upsert 测试 ====================
|
|
|
|
|
|
func testUpsert(that *Context) Map {
|
|
|
|
|
|
result := Map{"name": "Upsert测试", "tests": Slice{}}
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// 使用 admin 表测试 Upsert(MySQL ON DUPLICATE KEY UPDATE)
|
|
|
|
|
|
timestamp := time.Now().Unix()
|
|
|
|
|
|
testPhone := fmt.Sprintf("199%08d", timestamp%100000000)
|
|
|
|
|
|
|
|
|
|
|
|
// 8.1 Upsert 插入新记录
|
|
|
|
|
|
test1 := Map{"name": "Upsert 插入新记录 (admin表)"}
|
|
|
|
|
|
affected1 := that.Db.Upsert("admin",
|
|
|
|
|
|
Map{
|
|
|
|
|
|
"name": "Upsert测试管理员",
|
|
|
|
|
|
"phone": testPhone,
|
|
|
|
|
|
"state": 1,
|
|
|
|
|
|
"password": "test123",
|
|
|
|
|
|
"role_id": 1,
|
|
|
|
|
|
"title": "测试职位",
|
|
|
|
|
|
"create_time[#]": "NOW()",
|
|
|
|
|
|
"modify_time[#]": "NOW()",
|
|
|
|
|
|
},
|
|
|
|
|
|
Slice{"phone"},
|
|
|
|
|
|
Slice{"name", "state", "title", "modify_time"},
|
|
|
|
|
|
)
|
|
|
|
|
|
test1["result"] = affected1 >= 0
|
|
|
|
|
|
test1["affected"] = affected1
|
|
|
|
|
|
test1["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test1)
|
|
|
|
|
|
|
|
|
|
|
|
// 8.2 Upsert 更新已存在记录
|
|
|
|
|
|
test2 := Map{"name": "Upsert 更新已存在记录"}
|
|
|
|
|
|
affected2 := that.Db.Upsert("admin",
|
|
|
|
|
|
Map{
|
|
|
|
|
|
"name": "Upsert更新后管理员",
|
|
|
|
|
|
"phone": testPhone,
|
|
|
|
|
|
"state": 1,
|
|
|
|
|
|
"password": "updated123",
|
|
|
|
|
|
"role_id": 2,
|
|
|
|
|
|
"title": "更新后职位",
|
|
|
|
|
|
"create_time[#]": "NOW()",
|
|
|
|
|
|
"modify_time[#]": "NOW()",
|
|
|
|
|
|
},
|
|
|
|
|
|
Slice{"phone"},
|
|
|
|
|
|
Slice{"name", "title", "role_id", "modify_time"},
|
|
|
|
|
|
)
|
|
|
|
|
|
test2["result"] = affected2 >= 0
|
|
|
|
|
|
test2["affected"] = affected2
|
|
|
|
|
|
tests = append(tests, test2)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证更新结果
|
|
|
|
|
|
updatedAdmin := that.Db.Get("admin", "*", Map{"phone": testPhone})
|
|
|
|
|
|
test2["updatedAdmin"] = updatedAdmin
|
|
|
|
|
|
|
|
|
|
|
|
// 清理测试数据
|
|
|
|
|
|
that.Db.Delete("admin", Map{"phone": testPhone})
|
|
|
|
|
|
|
|
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 9. 事务测试 ====================
|
|
|
|
|
|
func testTransaction(that *Context) Map {
|
|
|
|
|
|
result := Map{"name": "事务测试", "tests": Slice{}}
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// 9.1 事务成功提交
|
|
|
|
|
|
test1 := Map{"name": "事务成功提交"}
|
|
|
|
|
|
timestamp := time.Now().Unix()
|
|
|
|
|
|
testName1 := fmt.Sprintf("事务测试_%d", timestamp)
|
|
|
|
|
|
|
|
|
|
|
|
success1 := that.Db.Action(func(tx HoTimeDB) bool {
|
|
|
|
|
|
// 插入记录到 test_batch 表
|
|
|
|
|
|
recordId := tx.Insert("test_batch", Map{
|
|
|
|
|
|
"name": testName1,
|
|
|
|
|
|
"title": "事务提交测试",
|
|
|
|
|
|
"state": 1,
|
|
|
|
|
|
"create_time[#]": "NOW()",
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return recordId != 0
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
test1["result"] = success1
|
|
|
|
|
|
// 验证数据是否存在
|
|
|
|
|
|
checkRecord := that.Db.Get("test_batch", "*", Map{"name": testName1})
|
|
|
|
|
|
test1["recordExists"] = checkRecord != nil
|
|
|
|
|
|
tests = append(tests, test1)
|
|
|
|
|
|
|
|
|
|
|
|
// 9.2 事务回滚
|
|
|
|
|
|
test2 := Map{"name": "事务回滚"}
|
|
|
|
|
|
testName2 := fmt.Sprintf("事务回滚测试_%d", timestamp)
|
|
|
|
|
|
|
|
|
|
|
|
success2 := that.Db.Action(func(tx HoTimeDB) bool {
|
|
|
|
|
|
// 插入记录
|
2026-01-22 07:25:41 +08:00
|
|
|
|
_ = tx.Insert("test_batch", Map{
|
2026-01-22 05:31:17 +08:00
|
|
|
|
"name": testName2,
|
|
|
|
|
|
"title": "事务回滚测试",
|
|
|
|
|
|
"state": 1,
|
|
|
|
|
|
"create_time[#]": "NOW()",
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 返回 false 触发回滚
|
|
|
|
|
|
return false
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
test2["result"] = !success2 // 期望回滚,所以 success2 应该为 false
|
|
|
|
|
|
// 验证数据是否不存在(已回滚)
|
|
|
|
|
|
checkRecord2 := that.Db.Get("test_batch", "*", Map{"name": testName2})
|
|
|
|
|
|
test2["recordRolledBack"] = checkRecord2 == nil
|
|
|
|
|
|
tests = append(tests, test2)
|
|
|
|
|
|
|
|
|
|
|
|
// 清理测试数据
|
|
|
|
|
|
that.Db.Delete("test_batch", Map{"name": testName1})
|
|
|
|
|
|
|
|
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 10. 原生 SQL 测试 ====================
|
|
|
|
|
|
func testRawSQL(that *Context) Map {
|
|
|
|
|
|
result := Map{"name": "原生SQL测试", "tests": Slice{}}
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// 10.1 Query 查询 - 使用真实的 article 表
|
|
|
|
|
|
test1 := Map{"name": "Query 原生查询"}
|
|
|
|
|
|
articles1 := that.Db.Query("SELECT id, title, author FROM `article` WHERE state = ? LIMIT ?", 0, 5)
|
|
|
|
|
|
test1["result"] = len(articles1) >= 0
|
|
|
|
|
|
test1["count"] = len(articles1)
|
|
|
|
|
|
tests = append(tests, test1)
|
|
|
|
|
|
|
|
|
|
|
|
// 10.2 Exec 执行 - 使用 article 表
|
|
|
|
|
|
test2 := Map{"name": "Exec 原生执行"}
|
|
|
|
|
|
// 更新一条记录
|
|
|
|
|
|
testArticle := that.Db.Get("article", "id", Map{"state": 0})
|
|
|
|
|
|
if testArticle != nil {
|
|
|
|
|
|
res, err := that.Db.Exec("UPDATE `article` SET modify_time = NOW() WHERE id = ?", testArticle.GetInt64("id"))
|
|
|
|
|
|
if err.GetError() == nil && res != nil {
|
|
|
|
|
|
affected, _ := res.RowsAffected()
|
|
|
|
|
|
test2["result"] = affected >= 0
|
|
|
|
|
|
test2["affected"] = affected
|
|
|
|
|
|
} else {
|
|
|
|
|
|
test2["result"] = false
|
|
|
|
|
|
test2["error"] = err.GetError()
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
test2["result"] = true
|
|
|
|
|
|
test2["note"] = "无可用测试数据"
|
|
|
|
|
|
}
|
|
|
|
|
|
tests = append(tests, test2)
|
|
|
|
|
|
|
2026-01-22 07:16:42 +08:00
|
|
|
|
// ==================== IN/NOT IN 数组测试 ====================
|
|
|
|
|
|
// H1: IN (?) 配合非空数组能正确展开
|
|
|
|
|
|
test3 := Map{"name": "H1: IN (?) 非空数组展开"}
|
|
|
|
|
|
articles3 := that.Db.Query("SELECT id, title FROM `article` WHERE id IN (?) LIMIT 10", []int{1, 2, 3, 4, 5})
|
|
|
|
|
|
test3["result"] = len(articles3) >= 0
|
|
|
|
|
|
test3["count"] = len(articles3)
|
|
|
|
|
|
test3["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test3)
|
|
|
|
|
|
|
|
|
|
|
|
// H2: IN (?) 配合空数组替换为 1=0
|
|
|
|
|
|
test4 := Map{"name": "H2: IN (?) 空数组替换为1=0"}
|
|
|
|
|
|
articles4 := that.Db.Query("SELECT id, title FROM `article` WHERE id IN (?) LIMIT 10", []int{})
|
|
|
|
|
|
test4["result"] = len(articles4) == 0 // 空数组的IN应该返回0条
|
|
|
|
|
|
test4["count"] = len(articles4)
|
|
|
|
|
|
test4["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
test4["expected"] = "count=0, SQL应包含1=0"
|
|
|
|
|
|
tests = append(tests, test4)
|
|
|
|
|
|
|
|
|
|
|
|
// H3: NOT IN (?) 配合空数组替换为 1=1
|
|
|
|
|
|
test5 := Map{"name": "H3: NOT IN (?) 空数组替换为1=1"}
|
|
|
|
|
|
articles5 := that.Db.Query("SELECT id, title FROM `article` WHERE id NOT IN (?) LIMIT 10", []int{})
|
|
|
|
|
|
test5["result"] = len(articles5) > 0 // NOT IN空数组应该返回记录
|
|
|
|
|
|
test5["count"] = len(articles5)
|
|
|
|
|
|
test5["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
test5["expected"] = "count>0, SQL应包含1=1"
|
|
|
|
|
|
tests = append(tests, test5)
|
|
|
|
|
|
|
|
|
|
|
|
// H4: NOT IN (?) 配合非空数组正常展开
|
|
|
|
|
|
test6 := Map{"name": "H4: NOT IN (?) 非空数组展开"}
|
|
|
|
|
|
articles6 := that.Db.Query("SELECT id, title FROM `article` WHERE id NOT IN (?) LIMIT 10", []int{1, 2, 3})
|
|
|
|
|
|
test6["result"] = len(articles6) >= 0
|
|
|
|
|
|
test6["count"] = len(articles6)
|
|
|
|
|
|
test6["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test6)
|
|
|
|
|
|
|
|
|
|
|
|
// H5: 普通 ? 占位符保持原有行为
|
|
|
|
|
|
test7 := Map{"name": "H5: 普通?占位符不受影响"}
|
|
|
|
|
|
articles7 := that.Db.Query("SELECT id, title FROM `article` WHERE state = ? LIMIT ?", 0, 5)
|
|
|
|
|
|
test7["result"] = len(articles7) >= 0
|
|
|
|
|
|
test7["count"] = len(articles7)
|
|
|
|
|
|
test7["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test7)
|
|
|
|
|
|
|
|
|
|
|
|
// 额外测试: Select ORM方法的空数组处理
|
|
|
|
|
|
test8 := Map{"name": "ORM Select: IN空数组"}
|
|
|
|
|
|
articles8 := that.Db.Select("article", "id,title", Map{"id": []int{}, "LIMIT": 10})
|
|
|
|
|
|
test8["result"] = len(articles8) == 0
|
|
|
|
|
|
test8["count"] = len(articles8)
|
|
|
|
|
|
test8["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test8)
|
|
|
|
|
|
|
|
|
|
|
|
// 额外测试: Select ORM方法的NOT IN空数组处理
|
|
|
|
|
|
test9 := Map{"name": "ORM Select: NOT IN空数组"}
|
|
|
|
|
|
articles9 := that.Db.Select("article", "id,title", Map{"id[!]": []int{}, "LIMIT": 10})
|
|
|
|
|
|
test9["result"] = len(articles9) > 0 // NOT IN 空数组应返回记录
|
|
|
|
|
|
test9["count"] = len(articles9)
|
|
|
|
|
|
test9["lastQuery"] = that.Db.LastQuery
|
|
|
|
|
|
tests = append(tests, test9)
|
|
|
|
|
|
|
2026-01-22 05:31:17 +08:00
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
2026-01-30 17:51:43 +08:00
|
|
|
|
|
|
|
|
|
|
// ==================== 缓存测试 ====================
|
|
|
|
|
|
func testCacheAll(that *Context) Map {
|
|
|
|
|
|
result := Map{"name": "数据库缓存测试", "tests": Slice{}}
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前缓存模式
|
|
|
|
|
|
cacheMode := "unknown"
|
|
|
|
|
|
if that.Application.HoTimeCache != nil && that.Application.HoTimeCache.Config != nil {
|
|
|
|
|
|
dbConfig := that.Application.HoTimeCache.Config.GetMap("db")
|
|
|
|
|
|
if dbConfig != nil {
|
|
|
|
|
|
cacheMode = dbConfig.GetString("mode")
|
|
|
|
|
|
if cacheMode == "" {
|
|
|
|
|
|
cacheMode = "new"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
result["cache_mode"] = cacheMode
|
|
|
|
|
|
|
|
|
|
|
|
// 测试用的唯一前缀
|
|
|
|
|
|
testPrefix := fmt.Sprintf("cache_test_%d_", time.Now().UnixNano())
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 1. 基础读写测试 ====================
|
|
|
|
|
|
test1 := Map{"name": "1. 基础 set/get 测试"}
|
|
|
|
|
|
testKey1 := testPrefix + "basic"
|
|
|
|
|
|
testValue1 := Map{"name": "测试数据", "count": 123, "active": true}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置缓存
|
|
|
|
|
|
that.Application.Cache(testKey1, testValue1)
|
|
|
|
|
|
|
|
|
|
|
|
// 读取缓存
|
|
|
|
|
|
cached1 := that.Application.Cache(testKey1)
|
|
|
|
|
|
if cached1.Data != nil {
|
|
|
|
|
|
cachedMap := cached1.ToMap()
|
|
|
|
|
|
test1["result"] = cachedMap.GetString("name") == "测试数据" && cachedMap.GetInt("count") == 123
|
|
|
|
|
|
test1["cached_value"] = cachedMap
|
|
|
|
|
|
} else {
|
|
|
|
|
|
test1["result"] = false
|
|
|
|
|
|
test1["error"] = "缓存读取返回 nil"
|
|
|
|
|
|
}
|
|
|
|
|
|
tests = append(tests, test1)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 2. 删除缓存测试 ====================
|
|
|
|
|
|
test2 := Map{"name": "2. delete 删除缓存测试"}
|
|
|
|
|
|
testKey2 := testPrefix + "delete"
|
|
|
|
|
|
that.Application.Cache(testKey2, "删除测试值")
|
|
|
|
|
|
|
|
|
|
|
|
// 验证存在
|
|
|
|
|
|
before := that.Application.Cache(testKey2)
|
|
|
|
|
|
beforeExists := before.Data != nil
|
|
|
|
|
|
|
|
|
|
|
|
// 删除
|
|
|
|
|
|
that.Application.Cache(testKey2, nil)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证已删除
|
|
|
|
|
|
after := that.Application.Cache(testKey2)
|
|
|
|
|
|
afterExists := after.Data != nil
|
|
|
|
|
|
|
|
|
|
|
|
test2["result"] = beforeExists && !afterExists
|
|
|
|
|
|
test2["before_exists"] = beforeExists
|
|
|
|
|
|
test2["after_exists"] = afterExists
|
|
|
|
|
|
tests = append(tests, test2)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 3. 过期时间测试 ====================
|
|
|
|
|
|
test3 := Map{"name": "3. 过期时间测试(短超时)"}
|
|
|
|
|
|
testKey3 := testPrefix + "expire"
|
|
|
|
|
|
|
|
|
|
|
|
// 设置 2 秒过期
|
|
|
|
|
|
that.Application.Cache(testKey3, "短期数据", 2)
|
|
|
|
|
|
|
|
|
|
|
|
// 立即读取应该存在
|
|
|
|
|
|
immediate := that.Application.Cache(testKey3)
|
|
|
|
|
|
immediateExists := immediate.Data != nil
|
|
|
|
|
|
|
|
|
|
|
|
test3["result"] = immediateExists
|
|
|
|
|
|
test3["immediate_exists"] = immediateExists
|
|
|
|
|
|
test3["note"] = "设置了2秒过期,可等待后再次访问验证过期"
|
|
|
|
|
|
tests = append(tests, test3)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 4. 不存在的 key 读取测试 ====================
|
|
|
|
|
|
test4 := Map{"name": "4. 不存在的 key 读取测试"}
|
|
|
|
|
|
nonExistKey := testPrefix + "non_exist_key_" + fmt.Sprintf("%d", time.Now().UnixNano())
|
|
|
|
|
|
nonExist := that.Application.Cache(nonExistKey)
|
|
|
|
|
|
test4["result"] = nonExist.Data == nil
|
|
|
|
|
|
test4["value"] = nonExist.Data
|
|
|
|
|
|
tests = append(tests, test4)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 5. 重复 set 同一个 key 测试 ====================
|
|
|
|
|
|
test5 := Map{"name": "5. 重复 set 同一个 key 测试"}
|
|
|
|
|
|
testKey5 := testPrefix + "repeat"
|
|
|
|
|
|
|
|
|
|
|
|
that.Application.Cache(testKey5, "第一次值")
|
|
|
|
|
|
first := that.Application.Cache(testKey5).ToStr()
|
|
|
|
|
|
|
|
|
|
|
|
that.Application.Cache(testKey5, "第二次值")
|
|
|
|
|
|
second := that.Application.Cache(testKey5).ToStr()
|
|
|
|
|
|
|
|
|
|
|
|
that.Application.Cache(testKey5, Map{"version": 3})
|
|
|
|
|
|
third := that.Application.Cache(testKey5).ToMap()
|
|
|
|
|
|
|
|
|
|
|
|
test5["result"] = first == "第一次值" && second == "第二次值" && third.GetInt("version") == 3
|
|
|
|
|
|
test5["first"] = first
|
|
|
|
|
|
test5["second"] = second
|
|
|
|
|
|
test5["third"] = third
|
|
|
|
|
|
tests = append(tests, test5)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 6. 通配删除测试 ====================
|
|
|
|
|
|
test6 := Map{"name": "6. 通配删除测试 (key*)"}
|
|
|
|
|
|
wildcardPrefix := testPrefix + "wildcard_"
|
|
|
|
|
|
|
|
|
|
|
|
// 创建多个带相同前缀的缓存
|
|
|
|
|
|
that.Application.Cache(wildcardPrefix+"a", "值A")
|
|
|
|
|
|
that.Application.Cache(wildcardPrefix+"b", "值B")
|
|
|
|
|
|
that.Application.Cache(wildcardPrefix+"c", "值C")
|
|
|
|
|
|
|
|
|
|
|
|
// 验证都存在
|
|
|
|
|
|
aExists := that.Application.Cache(wildcardPrefix+"a").Data != nil
|
|
|
|
|
|
bExists := that.Application.Cache(wildcardPrefix+"b").Data != nil
|
|
|
|
|
|
cExists := that.Application.Cache(wildcardPrefix+"c").Data != nil
|
|
|
|
|
|
allExistBefore := aExists && bExists && cExists
|
|
|
|
|
|
|
|
|
|
|
|
// 通配删除
|
|
|
|
|
|
that.Application.Cache(wildcardPrefix+"*", nil)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证都已删除
|
|
|
|
|
|
aAfter := that.Application.Cache(wildcardPrefix+"a").Data != nil
|
|
|
|
|
|
bAfter := that.Application.Cache(wildcardPrefix+"b").Data != nil
|
|
|
|
|
|
cAfter := that.Application.Cache(wildcardPrefix+"c").Data != nil
|
|
|
|
|
|
allDeletedAfter := !aAfter && !bAfter && !cAfter
|
|
|
|
|
|
|
|
|
|
|
|
test6["result"] = allExistBefore && allDeletedAfter
|
|
|
|
|
|
test6["before"] = Map{"a": aExists, "b": bExists, "c": cExists}
|
|
|
|
|
|
test6["after"] = Map{"a": aAfter, "b": bAfter, "c": cAfter}
|
|
|
|
|
|
tests = append(tests, test6)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 7. 不同数据类型测试 ====================
|
|
|
|
|
|
test7 := Map{"name": "7. 不同数据类型存储测试"}
|
|
|
|
|
|
|
|
|
|
|
|
// 字符串
|
|
|
|
|
|
that.Application.Cache(testPrefix+"type_string", "字符串值")
|
|
|
|
|
|
typeString := that.Application.Cache(testPrefix + "type_string").ToStr()
|
|
|
|
|
|
|
|
|
|
|
|
// 整数
|
|
|
|
|
|
that.Application.Cache(testPrefix+"type_int", 12345)
|
|
|
|
|
|
typeInt := that.Application.Cache(testPrefix + "type_int").ToInt()
|
|
|
|
|
|
|
|
|
|
|
|
// 浮点数
|
|
|
|
|
|
that.Application.Cache(testPrefix+"type_float", 3.14159)
|
|
|
|
|
|
typeFloat := that.Application.Cache(testPrefix + "type_float").ToFloat64()
|
|
|
|
|
|
|
|
|
|
|
|
// 布尔值
|
|
|
|
|
|
that.Application.Cache(testPrefix+"type_bool", true)
|
|
|
|
|
|
typeBoolData := that.Application.Cache(testPrefix + "type_bool").Data
|
|
|
|
|
|
typeBool := typeBoolData == true || typeBoolData == "true" || typeBoolData == 1.0
|
|
|
|
|
|
|
|
|
|
|
|
// Map
|
|
|
|
|
|
that.Application.Cache(testPrefix+"type_map", Map{"key": "value", "num": 100})
|
|
|
|
|
|
typeMap := that.Application.Cache(testPrefix + "type_map").ToMap()
|
|
|
|
|
|
|
|
|
|
|
|
// Slice
|
|
|
|
|
|
that.Application.Cache(testPrefix+"type_slice", Slice{1, 2, 3, "four", Map{"five": 5}})
|
|
|
|
|
|
typeSlice := that.Application.Cache(testPrefix + "type_slice").ToSlice()
|
|
|
|
|
|
|
|
|
|
|
|
test7["result"] = typeString == "字符串值" &&
|
|
|
|
|
|
typeInt == 12345 &&
|
|
|
|
|
|
typeFloat > 3.14 && typeFloat < 3.15 &&
|
|
|
|
|
|
typeBool == true &&
|
|
|
|
|
|
typeMap.GetString("key") == "value" &&
|
|
|
|
|
|
len(typeSlice) == 5
|
|
|
|
|
|
|
|
|
|
|
|
test7["string"] = typeString
|
|
|
|
|
|
test7["int"] = typeInt
|
|
|
|
|
|
test7["float"] = typeFloat
|
|
|
|
|
|
test7["bool"] = typeBool
|
|
|
|
|
|
test7["map"] = typeMap
|
|
|
|
|
|
test7["slice"] = typeSlice
|
|
|
|
|
|
tests = append(tests, test7)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 8. 自定义超时时间测试 ====================
|
|
|
|
|
|
test8 := Map{"name": "8. 自定义超时时间参数测试"}
|
|
|
|
|
|
testKey8 := testPrefix + "custom_timeout"
|
|
|
|
|
|
|
|
|
|
|
|
// 设置 3600 秒(1小时)过期
|
|
|
|
|
|
that.Application.Cache(testKey8, "长期数据", 3600)
|
|
|
|
|
|
longTerm := that.Application.Cache(testKey8)
|
|
|
|
|
|
test8["result"] = longTerm.Data != nil
|
|
|
|
|
|
test8["value"] = longTerm.ToStr()
|
|
|
|
|
|
tests = append(tests, test8)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 9. 查询缓存表状态 ====================
|
|
|
|
|
|
test9 := Map{"name": "9. 缓存表状态查询"}
|
|
|
|
|
|
|
|
|
|
|
|
// 查询新表记录数
|
|
|
|
|
|
prefix := that.Db.GetPrefix()
|
|
|
|
|
|
newTableName := prefix + "hotime_cache"
|
|
|
|
|
|
legacyTableName := prefix + "cached"
|
|
|
|
|
|
|
|
|
|
|
|
newCount := that.Db.Count(newTableName)
|
|
|
|
|
|
test9["new_table_count"] = newCount
|
|
|
|
|
|
test9["new_table_name"] = newTableName
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试查询老表
|
|
|
|
|
|
legacyCount := int64(-1)
|
|
|
|
|
|
legacyExists := false
|
|
|
|
|
|
legacyData := that.Db.Query("SELECT COUNT(*) as cnt FROM `" + legacyTableName + "`")
|
|
|
|
|
|
if len(legacyData) > 0 {
|
|
|
|
|
|
legacyExists = true
|
|
|
|
|
|
legacyCount = legacyData[0].GetInt64("cnt")
|
|
|
|
|
|
}
|
|
|
|
|
|
test9["legacy_table_exists"] = legacyExists
|
|
|
|
|
|
test9["legacy_table_count"] = legacyCount
|
|
|
|
|
|
test9["legacy_table_name"] = legacyTableName
|
|
|
|
|
|
|
|
|
|
|
|
test9["result"] = newCount >= 0
|
|
|
|
|
|
tests = append(tests, test9)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 清理测试数据 ====================
|
|
|
|
|
|
// 删除所有测试创建的缓存
|
|
|
|
|
|
that.Application.Cache(testPrefix+"*", nil)
|
|
|
|
|
|
|
|
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
result["cleanup"] = "已清理所有测试缓存数据"
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// testCacheCompatible 专门测试兼容模式 - 白盒测试
|
|
|
|
|
|
func testCacheCompatible(that *Context) Map {
|
|
|
|
|
|
result := Map{
|
|
|
|
|
|
"test_name": "兼容模式白盒测试",
|
|
|
|
|
|
"timestamp": time.Now().Format("2006-01-02 15:04:05"),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
prefix := that.Db.GetPrefix()
|
|
|
|
|
|
newTableName := prefix + "hotime_cache"
|
|
|
|
|
|
legacyTableName := prefix + "cached"
|
|
|
|
|
|
|
|
|
|
|
|
tests := Slice{}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 1. 查询当前模式 ====================
|
|
|
|
|
|
test1 := Map{"name": "1. 查询当前缓存模式"}
|
|
|
|
|
|
// 读取配置确认模式
|
|
|
|
|
|
cacheConfig := that.Application.Config.GetMap("cache")
|
|
|
|
|
|
dbConfig := cacheConfig.GetMap("db")
|
|
|
|
|
|
mode := dbConfig.GetString("mode")
|
|
|
|
|
|
if mode == "" {
|
|
|
|
|
|
mode = "默认(compatible)"
|
|
|
|
|
|
}
|
|
|
|
|
|
test1["mode"] = mode
|
|
|
|
|
|
test1["result"] = true
|
|
|
|
|
|
tests = append(tests, test1)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 2. 查询老表数据 ====================
|
|
|
|
|
|
test2 := Map{"name": "2. 查询老表cached现有数据"}
|
|
|
|
|
|
|
|
|
|
|
|
legacyData := that.Db.Query("SELECT * FROM `" + legacyTableName + "` LIMIT 5")
|
|
|
|
|
|
test2["legacy_table"] = legacyTableName
|
|
|
|
|
|
test2["count"] = len(legacyData)
|
|
|
|
|
|
test2["data"] = legacyData
|
|
|
|
|
|
test2["result"] = true
|
|
|
|
|
|
tests = append(tests, test2)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 3. 查询新表数据 ====================
|
|
|
|
|
|
test3 := Map{"name": "3. 查询新表hotime_cache现有数据"}
|
|
|
|
|
|
|
|
|
|
|
|
newData := that.Db.Query("SELECT * FROM `" + newTableName + "` LIMIT 5")
|
|
|
|
|
|
test3["new_table"] = newTableName
|
|
|
|
|
|
test3["count"] = len(newData)
|
|
|
|
|
|
test3["data"] = newData
|
|
|
|
|
|
test3["result"] = true
|
|
|
|
|
|
tests = append(tests, test3)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 4. 测试老表回退读取 ====================
|
|
|
|
|
|
test4 := Map{"name": "4. 测试兼容模式老表回退读取"}
|
|
|
|
|
|
|
|
|
|
|
|
// 插入一条未过期的老表数据进行测试
|
|
|
|
|
|
testKey4 := "test_compat_fallback_" + ObjToStr(time.Now().UnixNano())
|
|
|
|
|
|
testValue4 := Map{"admin_id": 999, "admin_name": "测试老数据"}
|
|
|
|
|
|
testValueJson4, _ := json.Marshal(Map{"data": testValue4})
|
|
|
|
|
|
|
|
|
|
|
|
// 在老表插入未过期数据
|
|
|
|
|
|
that.Db.Insert(legacyTableName, Map{
|
|
|
|
|
|
"key": testKey4,
|
|
|
|
|
|
"value": string(testValueJson4),
|
|
|
|
|
|
"endtime": time.Now().Unix() + 3600, // 1小时后过期
|
|
|
|
|
|
"time": time.Now().UnixNano(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
test4["test_key"] = testKey4
|
|
|
|
|
|
|
|
|
|
|
|
// 确保新表没有这个 key
|
|
|
|
|
|
newExists := that.Db.Get(newTableName, "*", Map{"key": testKey4})
|
|
|
|
|
|
test4["key_in_new_table"] = newExists != nil
|
|
|
|
|
|
|
|
|
|
|
|
// 通过缓存 API 读取(应该回退到老表)
|
|
|
|
|
|
cacheValue := that.Application.Cache(testKey4)
|
|
|
|
|
|
test4["cache_api_result"] = cacheValue.Data
|
|
|
|
|
|
|
|
|
|
|
|
// 直接从老表读取确认
|
|
|
|
|
|
legacyValue := that.Db.Get(legacyTableName, "*", Map{"key": testKey4})
|
|
|
|
|
|
if legacyValue != nil {
|
|
|
|
|
|
test4["legacy_db_value"] = legacyValue.GetString("value")
|
|
|
|
|
|
test4["legacy_db_endtime"] = legacyValue.GetInt64("endtime")
|
|
|
|
|
|
test4["legacy_db_endtime_readable"] = time.Unix(legacyValue.GetInt64("endtime"), 0).Format("2006-01-02 15:04:05")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证:新表没数据,但缓存API能读到老表数据
|
|
|
|
|
|
test4["result"] = newExists == nil && cacheValue.Data != nil
|
|
|
|
|
|
tests = append(tests, test4)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 5. 测试写新删老 ====================
|
|
|
|
|
|
test5 := Map{"name": "5. 测试兼容模式写新删老"}
|
|
|
|
|
|
|
|
|
|
|
|
testKey5 := "test_compat_write_" + ObjToStr(time.Now().UnixNano())
|
|
|
|
|
|
testValue5 := "兼容模式测试数据"
|
|
|
|
|
|
|
|
|
|
|
|
// 先在老表插入一条数据
|
|
|
|
|
|
that.Db.Insert(legacyTableName, Map{
|
|
|
|
|
|
"key": testKey5,
|
|
|
|
|
|
"value": `{"data":"老表原始数据"}`,
|
|
|
|
|
|
"endtime": time.Now().Unix() + 3600, // 1小时后过期
|
|
|
|
|
|
"time": time.Now().UnixNano(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 确认老表有数据
|
|
|
|
|
|
legacyBefore := that.Db.Get(legacyTableName, "*", Map{"key": testKey5})
|
|
|
|
|
|
test5["step1_legacy_before"] = legacyBefore != nil
|
|
|
|
|
|
|
|
|
|
|
|
// 通过缓存 API 写入(应该写新表并删老表)
|
|
|
|
|
|
that.Application.Cache(testKey5, testValue5)
|
|
|
|
|
|
|
|
|
|
|
|
// 检查新表
|
|
|
|
|
|
newAfter := that.Db.Get(newTableName, "*", Map{"key": testKey5})
|
|
|
|
|
|
test5["step2_new_after"] = newAfter != nil
|
|
|
|
|
|
if newAfter != nil {
|
|
|
|
|
|
test5["new_value"] = newAfter.GetString("value")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查老表(应该被删除)
|
|
|
|
|
|
legacyAfter := that.Db.Get(legacyTableName, "*", Map{"key": testKey5})
|
|
|
|
|
|
test5["step3_legacy_after_deleted"] = legacyAfter == nil
|
|
|
|
|
|
|
|
|
|
|
|
test5["result"] = legacyBefore != nil && newAfter != nil && legacyAfter == nil
|
|
|
|
|
|
tests = append(tests, test5)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 6. 测试删除同时删两表 ====================
|
|
|
|
|
|
test6 := Map{"name": "6. 测试兼容模式删除(删除两表)"}
|
|
|
|
|
|
|
|
|
|
|
|
testKey6 := "test_compat_delete_" + ObjToStr(time.Now().UnixNano())
|
|
|
|
|
|
|
|
|
|
|
|
// 在老表插入
|
|
|
|
|
|
that.Db.Insert(legacyTableName, Map{
|
|
|
|
|
|
"key": testKey6,
|
|
|
|
|
|
"value": `{"data":"待删除老数据"}`,
|
|
|
|
|
|
"endtime": time.Now().Unix() + 3600,
|
|
|
|
|
|
"time": time.Now().UnixNano(),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 在新表插入
|
|
|
|
|
|
that.Db.Insert(newTableName, Map{
|
|
|
|
|
|
"key": testKey6,
|
|
|
|
|
|
"value": `"待删除新数据"`,
|
|
|
|
|
|
"end_time": time.Now().Add(time.Hour).Format("2006-01-02 15:04:05"),
|
|
|
|
|
|
"state": 0,
|
|
|
|
|
|
"create_time": time.Now().Format("2006-01-02 15:04:05"),
|
|
|
|
|
|
"modify_time": time.Now().Format("2006-01-02 15:04:05"),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 确认两表都有数据
|
|
|
|
|
|
test6["before_legacy"] = that.Db.Get(legacyTableName, "*", Map{"key": testKey6}) != nil
|
|
|
|
|
|
test6["before_new"] = that.Db.Get(newTableName, "*", Map{"key": testKey6}) != nil
|
|
|
|
|
|
|
|
|
|
|
|
// 通过缓存 API 删除
|
|
|
|
|
|
that.Application.Cache(testKey6, nil)
|
|
|
|
|
|
|
|
|
|
|
|
// 确认两表都被删除
|
|
|
|
|
|
test6["after_legacy_deleted"] = that.Db.Get(legacyTableName, "*", Map{"key": testKey6}) == nil
|
|
|
|
|
|
test6["after_new_deleted"] = that.Db.Get(newTableName, "*", Map{"key": testKey6}) == nil
|
|
|
|
|
|
|
|
|
|
|
|
test6["result"] = test6.GetBool("before_legacy") && test6.GetBool("before_new") &&
|
|
|
|
|
|
test6.GetBool("after_legacy_deleted") && test6.GetBool("after_new_deleted")
|
|
|
|
|
|
tests = append(tests, test6)
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 7. 清理测试数据 ====================
|
|
|
|
|
|
that.Db.Delete(newTableName, Map{"key[~]": "test_compat_%"})
|
|
|
|
|
|
that.Db.Delete(legacyTableName, Map{"key[~]": "test_compat_%"})
|
|
|
|
|
|
|
|
|
|
|
|
result["tests"] = tests
|
|
|
|
|
|
result["success"] = true
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|