refactor(db): 重构数据库构建器以支持JOIN参数传递并删除示例配置文件
- 修改 Get 方法以根据是否存在 JOIN 来构建参数结构 - 修改 Count 方法以根据是否存在 JOIN 来传递参数 - 修改 Select 方法以根据是否存在 JOIN 来构建参数结构 - 在 where.go 中添加对 [##] 键的支持以直接添加 SQL 片段 - 删除 example/config/admin.json 配置文件 - 删除 example/config/config.json 配置文件 - 删除 example/config/configNote.json 配置文件 - 删除 example/config/rule.json 配置文件 - 删除 example/benchmark_test.go 压测文件 - 重构 example/main.go 文件,添加完整的 HoTimeDB 功能测试套件 - 添加调试日志功能以跟踪数据库操作流程
This commit is contained in:
parent
f2f1fcc9aa
commit
0318c95055
1024
.cursor/debug.log
1024
.cursor/debug.log
File diff suppressed because one or more lines are too long
19
config/app.json
Normal file
19
config/app.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"flow": {},
|
||||
"id": "d751713988987e9331980363e24189ce",
|
||||
"label": "HoTime管理平台",
|
||||
"labelConfig": {
|
||||
"add": "添加",
|
||||
"delete": "删除",
|
||||
"download": "下载清单",
|
||||
"edit": "编辑",
|
||||
"info": "查看详情",
|
||||
"show": "开启"
|
||||
},
|
||||
"menus": [],
|
||||
"name": "admin",
|
||||
"stop": [
|
||||
"role",
|
||||
"org"
|
||||
]
|
||||
}
|
||||
@ -1,28 +1,14 @@
|
||||
{
|
||||
"cache": {
|
||||
"db": {
|
||||
"db": true,
|
||||
"session": true,
|
||||
"timeout": 72000
|
||||
},
|
||||
"memory": {
|
||||
"db": true,
|
||||
"session": true,
|
||||
"timeout": 7200
|
||||
},
|
||||
"redis": {
|
||||
"db": true,
|
||||
"host": "127.0.0.1",
|
||||
"password": "",
|
||||
"port": 6379,
|
||||
"session": true,
|
||||
"timeout": 7200
|
||||
}
|
||||
},
|
||||
"codeConfig": [
|
||||
{
|
||||
"config": "config/admin.json",
|
||||
"configDB": "config/adminDB.json",
|
||||
"config": "config/app.json",
|
||||
"mode": 0,
|
||||
"name": "",
|
||||
"rule": "config/rule.json",
|
||||
@ -30,12 +16,8 @@
|
||||
}
|
||||
],
|
||||
"db": {
|
||||
"mysql": {
|
||||
"host": "192.168.6.253",
|
||||
"name": "dgs-cms260122",
|
||||
"password": "dasda8454456",
|
||||
"port": "3306",
|
||||
"user": "root"
|
||||
"sqlite": {
|
||||
"path": "config/data.db"
|
||||
}
|
||||
},
|
||||
"defFile": [
|
||||
@ -50,7 +32,7 @@
|
||||
"5": "数据结果异常"
|
||||
},
|
||||
"mode": 2,
|
||||
"port": "8081",
|
||||
"port": "80",
|
||||
"sessionName": "HOTIME",
|
||||
"tpt": "tpt"
|
||||
}
|
||||
0
config/data.db
Normal file
0
config/data.db
Normal file
@ -396,7 +396,7 @@
|
||||
"list": false,
|
||||
"must": false,
|
||||
"name": "auth",
|
||||
"strict": true,
|
||||
"strict": false,
|
||||
"type": "auth"
|
||||
},
|
||||
{
|
||||
@ -23,12 +23,33 @@ func (that *HoTimeDB) Table(table string) *HotimeDBBuilder {
|
||||
|
||||
// Get 获取单条记录
|
||||
func (that *HotimeDBBuilder) Get(qu ...interface{}) Map {
|
||||
return that.HoTimeDB.Get(that.table, that.join, qu, that.where)
|
||||
// 构建参数:根据是否有 JOIN 来决定参数结构
|
||||
var args []interface{}
|
||||
if len(that.join) > 0 {
|
||||
// 有 JOIN 时:join, fields, where
|
||||
if len(qu) > 0 {
|
||||
args = append(args, that.join, qu[0], that.where)
|
||||
} else {
|
||||
args = append(args, that.join, "*", that.where)
|
||||
}
|
||||
} else {
|
||||
// 无 JOIN 时:fields, where
|
||||
if len(qu) > 0 {
|
||||
args = append(args, qu[0], that.where)
|
||||
} else {
|
||||
args = append(args, "*", that.where)
|
||||
}
|
||||
}
|
||||
return that.HoTimeDB.Get(that.table, args...)
|
||||
}
|
||||
|
||||
// Count 统计数量
|
||||
func (that *HotimeDBBuilder) Count() int {
|
||||
return that.HoTimeDB.Count(that.table, that.join, that.where)
|
||||
// 构建参数:根据是否有 JOIN 来决定参数结构
|
||||
if len(that.join) > 0 {
|
||||
return that.HoTimeDB.Count(that.table, that.join, that.where)
|
||||
}
|
||||
return that.HoTimeDB.Count(that.table, that.where)
|
||||
}
|
||||
|
||||
// Page 设置分页
|
||||
@ -40,10 +61,28 @@ func (that *HotimeDBBuilder) Page(page, pageRow int) *HotimeDBBuilder {
|
||||
|
||||
// Select 查询多条记录
|
||||
func (that *HotimeDBBuilder) Select(qu ...interface{}) []Map {
|
||||
if that.page != 0 {
|
||||
return that.HoTimeDB.Page(that.page, that.pageRow).PageSelect(that.table, that.join, qu, that.where)
|
||||
// 构建参数:根据是否有 JOIN 来决定参数结构
|
||||
var args []interface{}
|
||||
if len(that.join) > 0 {
|
||||
// 有 JOIN 时:join, fields, where
|
||||
if len(qu) > 0 {
|
||||
args = append(args, that.join, qu[0], that.where)
|
||||
} else {
|
||||
args = append(args, that.join, "*", that.where)
|
||||
}
|
||||
} else {
|
||||
// 无 JOIN 时:fields, where
|
||||
if len(qu) > 0 {
|
||||
args = append(args, qu[0], that.where)
|
||||
} else {
|
||||
args = append(args, "*", that.where)
|
||||
}
|
||||
}
|
||||
return that.HoTimeDB.Select(that.table, that.join, qu, that.where)
|
||||
|
||||
if that.page != 0 {
|
||||
return that.HoTimeDB.Page(that.page, that.pageRow).PageSelect(that.table, args...)
|
||||
}
|
||||
return that.HoTimeDB.Select(that.table, args...)
|
||||
}
|
||||
|
||||
// Update 更新记录
|
||||
|
||||
@ -186,6 +186,9 @@ func (that *HoTimeDB) varCond(k string, v interface{}) (string, []interface{}) {
|
||||
if k == "[#]" {
|
||||
k = strings.Replace(k, "[#]", "", -1)
|
||||
where += " " + ObjToStr(v) + " "
|
||||
} else if k == "[##]" {
|
||||
// 直接添加 SQL 片段(key 为 [##] 时)
|
||||
where += " " + ObjToStr(v) + " "
|
||||
} else if length > 0 && strings.Contains(k, "[") && k[length-1] == ']' {
|
||||
def := false
|
||||
|
||||
|
||||
@ -1,262 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 压测配置
|
||||
type BenchConfig struct {
|
||||
URL string // 测试URL
|
||||
Concurrency int // 并发数
|
||||
Duration time.Duration // 持续时间
|
||||
Timeout time.Duration // 请求超时时间
|
||||
}
|
||||
|
||||
// 压测结果
|
||||
type BenchResult struct {
|
||||
TotalRequests int64 // 总请求数
|
||||
SuccessRequests int64 // 成功请求数
|
||||
FailedRequests int64 // 失败请求数
|
||||
TotalDuration time.Duration // 总耗时
|
||||
MinLatency time.Duration // 最小延迟
|
||||
MaxLatency time.Duration // 最大延迟
|
||||
AvgLatency time.Duration // 平均延迟
|
||||
QPS float64 // 每秒请求数
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("==========================================")
|
||||
fmt.Println(" HoTime 框架性能压力测试")
|
||||
fmt.Println("==========================================")
|
||||
fmt.Println()
|
||||
|
||||
// 测试配置
|
||||
configs := []BenchConfig{
|
||||
{
|
||||
URL: "http://127.0.0.1:8081/app/test/hello",
|
||||
Concurrency: 10,
|
||||
Duration: 10 * time.Second,
|
||||
Timeout: 5 * time.Second,
|
||||
},
|
||||
{
|
||||
URL: "http://127.0.0.1:8081/app/test/hello",
|
||||
Concurrency: 50,
|
||||
Duration: 10 * time.Second,
|
||||
Timeout: 5 * time.Second,
|
||||
},
|
||||
{
|
||||
URL: "http://127.0.0.1:8081/app/test/hello",
|
||||
Concurrency: 100,
|
||||
Duration: 10 * time.Second,
|
||||
Timeout: 5 * time.Second,
|
||||
},
|
||||
{
|
||||
URL: "http://127.0.0.1:8081/app/test/hello",
|
||||
Concurrency: 200,
|
||||
Duration: 10 * time.Second,
|
||||
Timeout: 5 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
// 先检查服务是否可用
|
||||
fmt.Println("正在检查服务是否可用...")
|
||||
if !checkService(configs[0].URL) {
|
||||
fmt.Println("❌ 服务不可用,请先启动示例应用:")
|
||||
fmt.Println(" cd example && go run main.go")
|
||||
return
|
||||
}
|
||||
fmt.Println("✅ 服务已就绪")
|
||||
fmt.Println()
|
||||
|
||||
// 执行压测
|
||||
for i, config := range configs {
|
||||
fmt.Printf("【测试 %d】并发数: %d, 持续时间: %v\n", i+1, config.Concurrency, config.Duration)
|
||||
fmt.Println("------------------------------------------")
|
||||
|
||||
result := runBenchmark(config)
|
||||
printResult(result)
|
||||
fmt.Println()
|
||||
|
||||
// 测试间隔,让服务恢复
|
||||
if i < len(configs)-1 {
|
||||
fmt.Println("等待 3 秒后开始下一轮测试...")
|
||||
time.Sleep(3 * time.Second)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("==========================================")
|
||||
fmt.Println(" 压力测试完成")
|
||||
fmt.Println("==========================================")
|
||||
}
|
||||
|
||||
// 检查服务是否可用
|
||||
func checkService(url string) bool {
|
||||
client := &http.Client{Timeout: 3 * time.Second}
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return resp.StatusCode == 200
|
||||
}
|
||||
|
||||
// 执行压测
|
||||
func runBenchmark(config BenchConfig) BenchResult {
|
||||
var (
|
||||
totalRequests int64
|
||||
successRequests int64
|
||||
failedRequests int64
|
||||
totalLatency int64 // 纳秒
|
||||
minLatency int64 = int64(time.Hour)
|
||||
maxLatency int64
|
||||
mu sync.Mutex
|
||||
)
|
||||
|
||||
// 创建HTTP客户端
|
||||
client := &http.Client{
|
||||
Timeout: config.Timeout,
|
||||
Transport: &http.Transport{
|
||||
MaxIdleConns: config.Concurrency * 2,
|
||||
MaxIdleConnsPerHost: config.Concurrency * 2,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
// 控制退出
|
||||
done := make(chan struct{})
|
||||
var wg sync.WaitGroup
|
||||
|
||||
startTime := time.Now()
|
||||
|
||||
// 启动并发goroutine
|
||||
for i := 0; i < config.Concurrency; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
default:
|
||||
reqStart := time.Now()
|
||||
success := makeRequest(client, config.URL)
|
||||
latency := time.Since(reqStart).Nanoseconds()
|
||||
|
||||
atomic.AddInt64(&totalRequests, 1)
|
||||
atomic.AddInt64(&totalLatency, latency)
|
||||
|
||||
if success {
|
||||
atomic.AddInt64(&successRequests, 1)
|
||||
} else {
|
||||
atomic.AddInt64(&failedRequests, 1)
|
||||
}
|
||||
|
||||
// 更新最小/最大延迟
|
||||
mu.Lock()
|
||||
if latency < minLatency {
|
||||
minLatency = latency
|
||||
}
|
||||
if latency > maxLatency {
|
||||
maxLatency = latency
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 等待指定时间
|
||||
time.Sleep(config.Duration)
|
||||
close(done)
|
||||
wg.Wait()
|
||||
|
||||
totalDuration := time.Since(startTime)
|
||||
|
||||
// 计算结果
|
||||
result := BenchResult{
|
||||
TotalRequests: totalRequests,
|
||||
SuccessRequests: successRequests,
|
||||
FailedRequests: failedRequests,
|
||||
TotalDuration: totalDuration,
|
||||
MinLatency: time.Duration(minLatency),
|
||||
MaxLatency: time.Duration(maxLatency),
|
||||
}
|
||||
|
||||
if totalRequests > 0 {
|
||||
result.AvgLatency = time.Duration(totalLatency / totalRequests)
|
||||
result.QPS = float64(totalRequests) / totalDuration.Seconds()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 发起单个请求
|
||||
func makeRequest(client *http.Client, url string) bool {
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证响应
|
||||
if resp.StatusCode != 200 {
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证JSON格式
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证返回状态
|
||||
if status, ok := result["status"].(float64); !ok || status != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 打印结果
|
||||
func printResult(result BenchResult) {
|
||||
successRate := float64(result.SuccessRequests) / float64(result.TotalRequests) * 100
|
||||
|
||||
fmt.Printf("总请求数: %d\n", result.TotalRequests)
|
||||
fmt.Printf("成功请求: %d\n", result.SuccessRequests)
|
||||
fmt.Printf("失败请求: %d\n", result.FailedRequests)
|
||||
fmt.Printf("成功率: %.2f%%\n", successRate)
|
||||
fmt.Printf("总耗时: %v\n", result.TotalDuration.Round(time.Millisecond))
|
||||
fmt.Printf("QPS: %.2f 请求/秒\n", result.QPS)
|
||||
fmt.Printf("最小延迟: %v\n", result.MinLatency.Round(time.Microsecond))
|
||||
fmt.Printf("最大延迟: %v\n", result.MaxLatency.Round(time.Microsecond))
|
||||
fmt.Printf("平均延迟: %v\n", result.AvgLatency.Round(time.Microsecond))
|
||||
|
||||
// 性能评级
|
||||
fmt.Print("性能评级: ")
|
||||
switch {
|
||||
case result.QPS >= 10000:
|
||||
fmt.Println("🚀 优秀 (QPS >= 10000)")
|
||||
case result.QPS >= 5000:
|
||||
fmt.Println("⭐ 良好 (QPS >= 5000)")
|
||||
case result.QPS >= 2000:
|
||||
fmt.Println("👍 中等 (QPS >= 2000)")
|
||||
case result.QPS >= 1000:
|
||||
fmt.Println("📊 一般 (QPS >= 1000)")
|
||||
default:
|
||||
fmt.Println("⚠️ 需优化 (QPS < 1000)")
|
||||
}
|
||||
}
|
||||
@ -1,472 +0,0 @@
|
||||
{
|
||||
"flow": {
|
||||
"admin": {
|
||||
"sql": {
|
||||
"role_id": "role_id"
|
||||
},
|
||||
"stop": false,
|
||||
"table": "admin"
|
||||
},
|
||||
"article": {
|
||||
"sql": {
|
||||
"admin_id": "id"
|
||||
},
|
||||
"stop": false,
|
||||
"table": "article"
|
||||
},
|
||||
"ctg": {
|
||||
"sql": {
|
||||
"admin_id": "id"
|
||||
},
|
||||
"stop": false,
|
||||
"table": "ctg"
|
||||
},
|
||||
"ctg_article": {
|
||||
"sql": {
|
||||
"admin_id": "id"
|
||||
},
|
||||
"stop": false,
|
||||
"table": "ctg_article"
|
||||
},
|
||||
"ctg_copy": {
|
||||
"sql": {
|
||||
"admin_id": "id"
|
||||
},
|
||||
"stop": false,
|
||||
"table": "ctg_copy"
|
||||
},
|
||||
"logs": {
|
||||
"sql": {
|
||||
|
||||
},
|
||||
"stop": false,
|
||||
"table": "logs"
|
||||
},
|
||||
"org": {
|
||||
"sql": {
|
||||
"admin_id": "id"
|
||||
},
|
||||
"stop": false,
|
||||
"table": "org"
|
||||
},
|
||||
"role": {
|
||||
"sql": {
|
||||
"admin_id": "id",
|
||||
"id": "role_id"
|
||||
},
|
||||
"stop": true,
|
||||
"table": "role"
|
||||
}
|
||||
},
|
||||
"id": "74a8a59407fa7d6c7fcdc85742dbae57",
|
||||
"label": "HoTime管理平台",
|
||||
"labelConfig": {
|
||||
"add": "添加",
|
||||
"delete": "删除",
|
||||
"download": "下载清单",
|
||||
"edit": "编辑",
|
||||
"info": "查看详情",
|
||||
"show": "开启"
|
||||
},
|
||||
"menus": [
|
||||
{
|
||||
"auth": [
|
||||
"show"
|
||||
],
|
||||
"icon": "Setting",
|
||||
"label": "ebw_news",
|
||||
"menus": [
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_news",
|
||||
"table": "ebw_news"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_news_addition_res",
|
||||
"table": "ebw_news_addition_res"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_annex",
|
||||
"table": "ebw_annex"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_customer",
|
||||
"table": "ebw_customer"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_items",
|
||||
"table": "ebw_items"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_res",
|
||||
"table": "ebw_res"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_vote",
|
||||
"table": "ebw_vote"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_vote_option",
|
||||
"table": "ebw_vote_option"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_user",
|
||||
"table": "ebw_user"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_attachment",
|
||||
"table": "ebw_attachment"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_jobs",
|
||||
"table": "ebw_jobs"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "ebw_vote_user",
|
||||
"table": "ebw_vote_user"
|
||||
}
|
||||
],
|
||||
"name": "sys:ebw"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show"
|
||||
],
|
||||
"icon": "Setting",
|
||||
"label": "系统管理",
|
||||
"menus": [
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"download"
|
||||
],
|
||||
"label": "日志管理",
|
||||
"table": "logs"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "角色管理",
|
||||
"table": "role"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "组织管理",
|
||||
"table": "org"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "人员管理",
|
||||
"table": "admin"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "文章管理",
|
||||
"table": "article"
|
||||
}
|
||||
],
|
||||
"name": "sys"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show"
|
||||
],
|
||||
"icon": "Setting",
|
||||
"label": "外部系统",
|
||||
"menus": [
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "外部系统",
|
||||
"table": "swiper_sys"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "顶部",
|
||||
"table": "swiper_top"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "飘窗",
|
||||
"table": "swiper_fly"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "底部",
|
||||
"table": "swiper_bottom"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "中间",
|
||||
"table": "swiper_center"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "关联专题",
|
||||
"table": "swiper_point"
|
||||
}
|
||||
],
|
||||
"name": "sys:swiper"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show"
|
||||
],
|
||||
"icon": "Setting",
|
||||
"label": "栏目管理",
|
||||
"menus": [
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "栏目管理",
|
||||
"table": "ctg"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "关联栏目",
|
||||
"table": "ctg_article"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "栏目管理",
|
||||
"table": "ctg_copy"
|
||||
}
|
||||
],
|
||||
"name": "sys:ctg"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show"
|
||||
],
|
||||
"icon": "Setting",
|
||||
"label": "纪委信箱",
|
||||
"menus": [
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "纪委信箱",
|
||||
"table": "mail_discipline"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "总经理信箱",
|
||||
"table": "mail"
|
||||
},
|
||||
{
|
||||
"auth": [
|
||||
"show",
|
||||
"add",
|
||||
"delete",
|
||||
"edit",
|
||||
"info",
|
||||
"download"
|
||||
],
|
||||
"label": "党委书记信箱",
|
||||
"table": "mail_part"
|
||||
}
|
||||
],
|
||||
"name": "sys:mail"
|
||||
}
|
||||
],
|
||||
"name": "admin",
|
||||
"stop": [
|
||||
"role",
|
||||
"org"
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
943
example/main.go
943
example/main.go
@ -1,25 +1,962 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
. "code.hoteas.com/golang/hotime"
|
||||
. "code.hoteas.com/golang/hotime/common"
|
||||
. "code.hoteas.com/golang/hotime/db"
|
||||
)
|
||||
|
||||
// 调试日志文件路径
|
||||
const debugLogPath = `d:\work\hotimev1\.cursor\debug.log`
|
||||
|
||||
// debugLog 写入调试日志
|
||||
func debugLog(location, message string, data interface{}, hypothesisId string) {
|
||||
// #region agent log
|
||||
logEntry := Map{
|
||||
"location": location,
|
||||
"message": message,
|
||||
"data": data,
|
||||
"timestamp": time.Now().UnixMilli(),
|
||||
"sessionId": "debug-session",
|
||||
"runId": "hotimedb-test-run",
|
||||
"hypothesisId": hypothesisId,
|
||||
}
|
||||
jsonBytes, _ := json.Marshal(logEntry)
|
||||
f, err := os.OpenFile(debugLogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err == nil {
|
||||
f.WriteString(string(jsonBytes) + "\n")
|
||||
f.Close()
|
||||
}
|
||||
// #endregion
|
||||
}
|
||||
|
||||
func main() {
|
||||
debugLog("main.go:35", "开始 HoTimeDB 全功能测试", nil, "START")
|
||||
|
||||
appIns := Init("config/config.json")
|
||||
appIns.SetConnectListener(func(that *Context) (isFinished bool) {
|
||||
|
||||
return isFinished
|
||||
})
|
||||
|
||||
appIns.Run(Router{
|
||||
"app": {
|
||||
"test": {
|
||||
"hello": func(that *Context) {
|
||||
that.Display(0, Map{"message": "Hello World"})
|
||||
// 测试入口 - 运行所有测试
|
||||
"all": func(that *Context) {
|
||||
results := Map{}
|
||||
debugLog("main.go:48", "开始所有测试", nil, "ALL_TESTS")
|
||||
|
||||
// 初始化测试表
|
||||
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. 批量插入测试
|
||||
results["7_batch_insert"] = testBatchInsert(that)
|
||||
|
||||
// 8. Upsert 测试
|
||||
results["8_upsert"] = testUpsert(that)
|
||||
|
||||
// 9. 事务测试
|
||||
results["9_transaction"] = testTransaction(that)
|
||||
|
||||
// 10. 原生 SQL 测试
|
||||
results["10_raw_sql"] = testRawSQL(that)
|
||||
|
||||
debugLog("main.go:80", "所有测试完成", results, "ALL_TESTS_DONE")
|
||||
that.Display(0, results)
|
||||
},
|
||||
|
||||
// 查询数据库表结构
|
||||
"tables": func(that *Context) {
|
||||
debugLog("main.go:tables", "查询数据库表结构", nil, "TABLES")
|
||||
// 查询所有表
|
||||
tables := that.Db.Query("SHOW TABLES")
|
||||
debugLog("main.go:tables", "表列表", tables, "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})
|
||||
debugLog("main.go:describe", "表结构", Map{"table": tableName, "columns": columns, "data": data}, "DESCRIBE")
|
||||
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)) },
|
||||
"batch": func(that *Context) { that.Display(0, testBatchInsert(that)) },
|
||||
"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)) },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 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
|
||||
)`)
|
||||
|
||||
// 检查 admin 表数据
|
||||
adminCount := that.Db.Count("admin")
|
||||
articleCount := that.Db.Count("article")
|
||||
|
||||
debugLog("main.go:init", "MySQL数据库初始化检查完成", Map{
|
||||
"adminCount": adminCount,
|
||||
"articleCount": articleCount,
|
||||
"dbType": "MySQL",
|
||||
}, "INIT")
|
||||
}
|
||||
|
||||
// ==================== 1. 基础 CRUD 测试 ====================
|
||||
func testBasicCRUD(that *Context) Map {
|
||||
result := Map{"name": "基础CRUD测试", "tests": Slice{}}
|
||||
tests := Slice{}
|
||||
|
||||
debugLog("main.go:103", "开始基础 CRUD 测试 (MySQL)", nil, "H1_CRUD")
|
||||
|
||||
// 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
|
||||
debugLog("main.go:118", "Insert 测试", Map{"adminId": adminId, "success": adminId > 0, "query": that.Db.LastQuery}, "H1_INSERT")
|
||||
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
|
||||
debugLog("main.go:126", "Get 测试", Map{"admin": admin, "success": admin != nil}, "H1_GET")
|
||||
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)
|
||||
debugLog("main.go:134", "Select 单条件测试", Map{"count": len(admins1)}, "H1_SELECT1")
|
||||
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
|
||||
debugLog("main.go:149", "Select 多条件自动AND测试", Map{"count": len(admins2), "query": that.Db.LastQuery}, "H1_SELECT2")
|
||||
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
|
||||
debugLog("main.go:160", "Update 测试", Map{"affected": affected}, "H1_UPDATE")
|
||||
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
|
||||
debugLog("main.go:175", "Delete 测试", Map{"affected": deleteAffected}, "H1_DELETE")
|
||||
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{}
|
||||
|
||||
debugLog("main.go:188", "开始条件查询语法测试 (MySQL)", nil, "H2_CONDITION")
|
||||
|
||||
// 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)
|
||||
debugLog("main.go:195", "等于条件测试", Map{"count": len(articles1)}, "H2_EQUAL")
|
||||
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
|
||||
debugLog("main.go:204", "不等于条件测试", Map{"count": len(articles2), "query": that.Db.LastQuery}, "H2_NOT_EQUAL")
|
||||
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)
|
||||
debugLog("main.go:216", "大于小于条件测试", Map{"count": len(articles3)}, "H2_GREATER_LESS")
|
||||
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)
|
||||
debugLog("main.go:228", "大于等于小于等于条件测试", Map{"count": len(articles4)}, "H2_GTE_LTE")
|
||||
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
|
||||
debugLog("main.go:237", "LIKE 模糊查询测试", Map{"count": len(articles5), "query": that.Db.LastQuery}, "H2_LIKE")
|
||||
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)
|
||||
debugLog("main.go:245", "右模糊查询测试", Map{"count": len(articles6)}, "H2_LIKE_RIGHT")
|
||||
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
|
||||
debugLog("main.go:254", "BETWEEN 区间查询测试", Map{"count": len(articles7), "query": that.Db.LastQuery}, "H2_BETWEEN")
|
||||
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)
|
||||
debugLog("main.go:262", "NOT BETWEEN 查询测试", Map{"count": len(articles8)}, "H2_NOT_BETWEEN")
|
||||
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
|
||||
debugLog("main.go:271", "IN 查询测试", Map{"count": len(articles9), "query": that.Db.LastQuery}, "H2_IN")
|
||||
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)
|
||||
debugLog("main.go:279", "NOT IN 查询测试", Map{"count": len(articles10)}, "H2_NOT_IN")
|
||||
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)
|
||||
debugLog("main.go:287", "IS NULL 查询测试", Map{"count": len(articles11)}, "H2_IS_NULL")
|
||||
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)
|
||||
debugLog("main.go:295", "IS NOT NULL 查询测试", Map{"count": len(articles12)}, "H2_IS_NOT_NULL")
|
||||
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
|
||||
debugLog("main.go:307", "直接 SQL 片段查询测试", Map{"count": len(articles13), "query": that.Db.LastQuery}, "H2_RAW_SQL")
|
||||
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)
|
||||
debugLog("main.go:321", "显式 AND 条件测试", Map{"count": len(articles14)}, "H2_EXPLICIT_AND")
|
||||
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)
|
||||
debugLog("main.go:335", "OR 条件测试", Map{"count": len(articles15)}, "H2_OR")
|
||||
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
|
||||
debugLog("main.go:353", "嵌套 AND/OR 条件测试", Map{"count": len(articles16), "query": that.Db.LastQuery}, "H2_NESTED")
|
||||
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{}
|
||||
|
||||
debugLog("main.go:366", "开始链式查询测试 (MySQL)", nil, "H3_CHAIN")
|
||||
|
||||
// 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)
|
||||
debugLog("main.go:375", "基本链式查询测试", Map{"count": len(articles1)}, "H3_BASIC")
|
||||
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)
|
||||
debugLog("main.go:387", "链式 And 条件测试", Map{"count": len(articles2)}, "H3_AND")
|
||||
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)
|
||||
debugLog("main.go:401", "链式 Or 条件测试", Map{"count": len(articles3)}, "H3_OR")
|
||||
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)
|
||||
debugLog("main.go:413", "链式 Order 排序测试", Map{"count": len(articles4)}, "H3_ORDER")
|
||||
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)
|
||||
debugLog("main.go:424", "链式 Limit 限制测试", Map{"count": len(articles5)}, "H3_LIMIT")
|
||||
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
|
||||
debugLog("main.go:434", "链式 Get 获取单条测试", Map{"article": article6}, "H3_GET")
|
||||
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
|
||||
debugLog("main.go:444", "链式 Count 统计测试", Map{"count": count7}, "H3_COUNT")
|
||||
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)
|
||||
debugLog("main.go:455", "链式 Page 分页测试", Map{"count": len(articles8)}, "H3_PAGE")
|
||||
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
|
||||
debugLog("main.go:466", "链式 Group 分组测试", Map{"stats": stats9}, "H3_GROUP")
|
||||
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"] = "无可用测试数据"
|
||||
}
|
||||
debugLog("main.go:483", "链式 Update 更新测试", test10, "H3_UPDATE")
|
||||
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{}
|
||||
|
||||
debugLog("main.go:496", "开始 JOIN 查询测试 (MySQL)", nil, "H4_JOIN")
|
||||
|
||||
// 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
|
||||
debugLog("main.go:508", "LEFT JOIN 链式查询测试", Map{"count": len(articles1)}, "H4_LEFT_JOIN")
|
||||
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
|
||||
debugLog("main.go:525", "传统 JOIN 语法测试", Map{"count": len(articles2), "query": that.Db.LastQuery}, "H4_TRADITIONAL_JOIN")
|
||||
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
|
||||
debugLog("main.go:539", "多表 JOIN 测试", Map{"count": len(articles3)}, "H4_MULTI_JOIN")
|
||||
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)
|
||||
debugLog("main.go:551", "INNER JOIN 测试", Map{"count": len(articles4)}, "H4_INNER_JOIN")
|
||||
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{}
|
||||
|
||||
debugLog("main.go:564", "开始聚合函数测试 (MySQL)", nil, "H5_AGGREGATE")
|
||||
|
||||
// 5.1 Count 总数
|
||||
test1 := Map{"name": "Count 总数统计"}
|
||||
count1 := that.Db.Count("article")
|
||||
test1["result"] = count1 >= 0
|
||||
test1["count"] = count1
|
||||
debugLog("main.go:571", "Count 总数统计测试", Map{"count": count1}, "H5_COUNT")
|
||||
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
|
||||
debugLog("main.go:579", "Count 条件统计测试", Map{"count": count2}, "H5_COUNT_WHERE")
|
||||
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
|
||||
debugLog("main.go:587", "Sum 求和测试", Map{"sum": sum3}, "H5_SUM")
|
||||
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
|
||||
debugLog("main.go:595", "Avg 平均值测试", Map{"avg": avg4}, "H5_AVG")
|
||||
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
|
||||
debugLog("main.go:603", "Max 最大值测试", Map{"max": max5}, "H5_MAX")
|
||||
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
|
||||
debugLog("main.go:611", "Min 最小值测试", Map{"min": min6}, "H5_MIN")
|
||||
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
|
||||
debugLog("main.go:625", "GROUP BY 分组统计测试", Map{"stats": stats7}, "H5_GROUP_BY")
|
||||
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{}
|
||||
|
||||
debugLog("main.go:638", "开始分页查询测试 (MySQL)", nil, "H6_PAGINATION")
|
||||
|
||||
// 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)
|
||||
debugLog("main.go:648", "PageSelect 分页查询测试", Map{"count": len(articles1)}, "H6_PAGE_SELECT")
|
||||
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)
|
||||
debugLog("main.go:659", "PageSelect 第二页测试", Map{"count": len(articles2)}, "H6_PAGE_2")
|
||||
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)
|
||||
debugLog("main.go:671", "链式 Page 分页测试", Map{"count": len(articles3)}, "H6_CHAIN_PAGE")
|
||||
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
|
||||
debugLog("main.go:684", "Offset 偏移查询测试", Map{"count": len(articles4), "query": that.Db.LastQuery}, "H6_OFFSET")
|
||||
tests = append(tests, test4)
|
||||
|
||||
result["tests"] = tests
|
||||
result["success"] = true
|
||||
return result
|
||||
}
|
||||
|
||||
// ==================== 7. 批量插入测试 ====================
|
||||
func testBatchInsert(that *Context) Map {
|
||||
result := Map{"name": "批量插入测试", "tests": Slice{}}
|
||||
tests := Slice{}
|
||||
|
||||
debugLog("main.go:697", "开始批量插入测试 (MySQL)", nil, "H7_BATCH")
|
||||
|
||||
// 7.1 批量插入
|
||||
test1 := Map{"name": "BatchInsert 批量插入"}
|
||||
timestamp := time.Now().UnixNano()
|
||||
affected1 := that.Db.BatchInsert("test_batch", []Map{
|
||||
{"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
|
||||
debugLog("main.go:710", "BatchInsert 批量插入测试", Map{"affected": affected1, "query": that.Db.LastQuery}, "H7_BATCH_INSERT")
|
||||
tests = append(tests, test1)
|
||||
|
||||
// 7.2 带 [#] 的批量插入
|
||||
test2 := Map{"name": "BatchInsert 带 [#] 标记"}
|
||||
timestamp2 := time.Now().UnixNano()
|
||||
affected2 := that.Db.BatchInsert("test_batch", []Map{
|
||||
{"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
|
||||
debugLog("main.go:722", "BatchInsert 带 [#] 标记测试", Map{"affected": affected2}, "H7_BATCH_RAW")
|
||||
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{}
|
||||
|
||||
debugLog("main.go:739", "开始 Upsert 测试 (MySQL)", nil, "H8_UPSERT")
|
||||
|
||||
// 使用 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
|
||||
debugLog("main.go:763", "Upsert 插入新记录测试", Map{"affected": affected1, "query": that.Db.LastQuery}, "H8_UPSERT_INSERT")
|
||||
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
|
||||
debugLog("main.go:783", "Upsert 更新已存在记录测试", Map{"affected": affected2}, "H8_UPSERT_UPDATE")
|
||||
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{}
|
||||
|
||||
debugLog("main.go:803", "开始事务测试 (MySQL)", nil, "H9_TRANSACTION")
|
||||
|
||||
// 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()",
|
||||
})
|
||||
debugLog("main.go:818", "事务内插入记录", Map{"recordId": recordId}, "H9_TX_INSERT")
|
||||
|
||||
return recordId != 0
|
||||
})
|
||||
|
||||
test1["result"] = success1
|
||||
// 验证数据是否存在
|
||||
checkRecord := that.Db.Get("test_batch", "*", Map{"name": testName1})
|
||||
test1["recordExists"] = checkRecord != nil
|
||||
debugLog("main.go:831", "事务成功提交测试", Map{"success": success1, "recordExists": checkRecord != nil}, "H9_TX_SUCCESS")
|
||||
tests = append(tests, test1)
|
||||
|
||||
// 9.2 事务回滚
|
||||
test2 := Map{"name": "事务回滚"}
|
||||
testName2 := fmt.Sprintf("事务回滚测试_%d", timestamp)
|
||||
|
||||
success2 := that.Db.Action(func(tx HoTimeDB) bool {
|
||||
// 插入记录
|
||||
recordId := tx.Insert("test_batch", Map{
|
||||
"name": testName2,
|
||||
"title": "事务回滚测试",
|
||||
"state": 1,
|
||||
"create_time[#]": "NOW()",
|
||||
})
|
||||
debugLog("main.go:846", "事务内插入(将回滚)", Map{"recordId": recordId}, "H9_TX_ROLLBACK_INSERT")
|
||||
|
||||
// 返回 false 触发回滚
|
||||
return false
|
||||
})
|
||||
|
||||
test2["result"] = !success2 // 期望回滚,所以 success2 应该为 false
|
||||
// 验证数据是否不存在(已回滚)
|
||||
checkRecord2 := that.Db.Get("test_batch", "*", Map{"name": testName2})
|
||||
test2["recordRolledBack"] = checkRecord2 == nil
|
||||
debugLog("main.go:856", "事务回滚测试", Map{"success": success2, "rolledBack": checkRecord2 == nil}, "H9_TX_ROLLBACK")
|
||||
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{}
|
||||
|
||||
debugLog("main.go:872", "开始原生 SQL 测试 (MySQL)", nil, "H10_RAW_SQL")
|
||||
|
||||
// 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)
|
||||
debugLog("main.go:879", "Query 原生查询测试", Map{"count": len(articles1)}, "H10_QUERY")
|
||||
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"] = "无可用测试数据"
|
||||
}
|
||||
debugLog("main.go:899", "Exec 原生执行测试", test2, "H10_EXEC")
|
||||
tests = append(tests, test2)
|
||||
|
||||
result["tests"] = tests
|
||||
result["success"] = true
|
||||
return result
|
||||
}
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user