2026-01-25 05:14:18 +08:00
|
|
|
|
# HoTime 改进规划
|
|
|
|
|
|
|
2026-07-13 07:45:51 +08:00
|
|
|
|
> 相关规范:[DatabaseDesign](DatabaseDesign_数据库设计规范.md) · [CodeGen](CodeGen_代码生成.md) · [Testing](Testing_API测试框架.md) · [文档索引](README.md)
|
|
|
|
|
|
|
2026-01-25 05:14:18 +08:00
|
|
|
|
本文档记录 HoTime 框架的待改进项和设计思考,供后续版本迭代参考。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 一、备注语法优化
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
当前字段备注语法使用空格、冒号、大括号组合:
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
`status` int COMMENT '状态:0-正常,1-异常 这是数据库备注{这是前端提示}'
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
- 多种分隔符混用,不够直观
|
|
|
|
|
|
- 显示名称如需包含特殊字符可能冲突
|
|
|
|
|
|
|
|
|
|
|
|
### 改进方向
|
|
|
|
|
|
|
|
|
|
|
|
使用 `|` 作为统一分隔符,保持干净清爽:
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
-- 方案 A:简洁直观
|
|
|
|
|
|
`status` int COMMENT '状态|0-正常,1-异常|请选择状态'
|
|
|
|
|
|
-- 解析:显示名称|选项|提示
|
|
|
|
|
|
|
|
|
|
|
|
-- 方案 B:保持兼容,空格后内容仍作为数据库备注
|
|
|
|
|
|
`status` int COMMENT '状态|0-正常,1-异常|请选择状态 这是数据库备注'
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 待确认
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] 是否需要保留空格后的数据库备注功能
|
|
|
|
|
|
- [ ] 如果只有提示没有选项,如何表示(如 `名称||请输入名称`)
|
|
|
|
|
|
- [ ] 是否向后兼容旧语法
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 二、SQLite 备注支持
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
SQLite 不支持表/字段备注,需要手动在配置文件中设置。
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
SQLite 项目配置工作量大,不够"快速开发"。
|
|
|
|
|
|
|
|
|
|
|
|
### 待探索方案
|
|
|
|
|
|
|
|
|
|
|
|
1. **配置文件方案(当前)**:通过 admin.json 手动配置,学习成本可接受
|
|
|
|
|
|
2. **轻量级方案**:考虑是否有更简单的替代方案,但不增加复杂度
|
|
|
|
|
|
|
|
|
|
|
|
### 暂时结论
|
|
|
|
|
|
|
|
|
|
|
|
当前方案虽不完美,但符合"简单好用"原则,暂不改动。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 三、软删除支持
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
框架暂不支持软删除。
|
|
|
|
|
|
|
|
|
|
|
|
### 设计考量
|
|
|
|
|
|
|
|
|
|
|
|
软删除存在以下问题:
|
|
|
|
|
|
- 数据安全性:软删除的数据仍可被恢复或误用
|
|
|
|
|
|
- 查询复杂度:所有查询需要额外过滤条件
|
|
|
|
|
|
- 存储膨胀:删除的数据持续占用空间
|
|
|
|
|
|
|
|
|
|
|
|
### 待探索方案
|
|
|
|
|
|
|
|
|
|
|
|
1. **可选软删除**:通过配置决定某张表是否启用软删除
|
|
|
|
|
|
2. **日志表方案**:独立的操作日志表,只写不删不改
|
|
|
|
|
|
- 记录所有增删改操作
|
|
|
|
|
|
- 原表正常物理删除
|
|
|
|
|
|
- 需要时可从日志恢复
|
|
|
|
|
|
3. **归档表方案**:删除时移动到归档表
|
|
|
|
|
|
|
|
|
|
|
|
### 倾向方案
|
|
|
|
|
|
|
|
|
|
|
|
日志表方案更符合数据安全和审计需求:
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
CREATE TABLE `_operation_log` (
|
|
|
|
|
|
`id` int AUTO_INCREMENT,
|
|
|
|
|
|
`table_name` varchar(100) COMMENT '操作表名',
|
|
|
|
|
|
`record_id` int COMMENT '记录ID',
|
|
|
|
|
|
`operation` varchar(20) COMMENT '操作类型:insert,update,delete',
|
|
|
|
|
|
`old_data` text COMMENT '操作前数据(JSON)',
|
|
|
|
|
|
`new_data` text COMMENT '操作后数据(JSON)',
|
|
|
|
|
|
`operator_id` int COMMENT '操作人ID',
|
|
|
|
|
|
`operator_table` varchar(100) COMMENT '操作人表名',
|
|
|
|
|
|
`create_time` datetime COMMENT '操作时间',
|
|
|
|
|
|
PRIMARY KEY (`id`)
|
|
|
|
|
|
) COMMENT='操作日志';
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 待确认
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] 是否所有表都记录日志
|
|
|
|
|
|
- [ ] 日志保留策略(永久/定期归档)
|
|
|
|
|
|
- [ ] 是否提供恢复接口
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 四、多对多关联表增强
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
关联表(如 `user_role`)按普通表处理,生成标准 CRUD。
|
|
|
|
|
|
|
|
|
|
|
|
### 可能的增强
|
|
|
|
|
|
|
|
|
|
|
|
1. **自动识别**:只有两个 `_id` 外键的表识别为关联表
|
|
|
|
|
|
2. **专用接口**:生成关联管理接口(批量绑定/解绑)
|
|
|
|
|
|
3. **级联查询**:自动生成带关联数据的查询
|
|
|
|
|
|
|
|
|
|
|
|
### 待确认
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] 是否需要此功能
|
|
|
|
|
|
- [ ] 如何保持简单性
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 五、自动填充字段扩展
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
自动填充:
|
|
|
|
|
|
- `create_time`:新增时自动填充当前时间
|
|
|
|
|
|
- `modify_time`:新增/编辑时自动填充当前时间
|
|
|
|
|
|
|
|
|
|
|
|
### 可能的扩展
|
|
|
|
|
|
|
|
|
|
|
|
| 字段 | 填充时机 | 填充内容 |
|
|
|
|
|
|
|------|----------|----------|
|
|
|
|
|
|
| create_by | 新增 | 当前用户ID |
|
|
|
|
|
|
| modify_by | 新增/编辑 | 当前用户ID |
|
|
|
|
|
|
| create_ip | 新增 | 客户端IP |
|
|
|
|
|
|
|
|
|
|
|
|
### 待确认
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] 是否需要扩展
|
|
|
|
|
|
- [ ] 字段命名规范
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 六、版本控制/乐观锁
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
`version` 字段规则存在但未启用。
|
|
|
|
|
|
|
|
|
|
|
|
### 待确认
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] 是否需要支持乐观锁
|
|
|
|
|
|
- [ ] 如果不需要,是否从默认规则中移除
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-03-16 06:53:31 +08:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 七、测试框架:响应字段断言(部分匹配)
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
`Post` / `Get` 等终端方法目前只支持断言响应体中的 `status` 和 `msg` 字段:
|
|
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
|
a.JSON(Map{"phone": phone, "password": "123456"}).Post("正常登录", 0)
|
|
|
|
|
|
a.JSON(Map{"phone": phone, "password": "123456"}).Post("密码为空", 4, "用户名或密码不能为空")
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
如需验证响应 `result` 内部的具体字段,只能手动写:
|
|
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
|
resp := a.JSON(Map{...}).Post("查询列表", 0)
|
|
|
|
|
|
if resp.GetBody().GetMap("result").GetInt("total") != 10 {
|
|
|
|
|
|
resp.Fail("total 应为 10")
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
这种写法冗长、可读性差,且失败时无法显示期望值与实际值的对比。
|
|
|
|
|
|
|
|
|
|
|
|
### 改进方向
|
|
|
|
|
|
|
|
|
|
|
|
在终端方法签名中增加**可选的响应字段部分匹配参数**:
|
|
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
|
// 现有签名(不变)
|
|
|
|
|
|
func (c *ApiCase) Post(desc string, status int, msg ...string) *ApiResponse
|
|
|
|
|
|
|
|
|
|
|
|
// 新增重载或扩展参数,支持传入期望的 result 字段(Map 类型)
|
|
|
|
|
|
a.JSON(Map{...}).Post("查询列表", 0, Map{"total": 10})
|
|
|
|
|
|
a.JSON(Map{...}).Post("查询列表", 0, Map{"total": 10, "list": notEmpty})
|
|
|
|
|
|
a.JSON(Map{...}).Post("正常登录", 0, Map{"token": notEmpty})
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 核心设计原则
|
|
|
|
|
|
|
|
|
|
|
|
**部分匹配,而非精确匹配**:
|
|
|
|
|
|
|
|
|
|
|
|
- 只验证期望 Map 中列出的字段,响应中额外的字段不报错
|
|
|
|
|
|
- 避免因响应新增字段导致测试频繁失败,降低维护成本
|
|
|
|
|
|
- 精确匹配适合快照测试场景,但与"快速精准"目标相悖,不引入
|
|
|
|
|
|
|
|
|
|
|
|
### 支持的断言值类型
|
|
|
|
|
|
|
|
|
|
|
|
| 断言值 | 含义 | 示例 |
|
|
|
|
|
|
|--------|------|------|
|
|
|
|
|
|
| 具体值(string/int/bool) | 字段等于该值 | `Map{"total": 10}` |
|
|
|
|
|
|
| `notEmpty`(特殊常量) | 字段存在且非空/非零 | `Map{"token": notEmpty}` |
|
|
|
|
|
|
| 嵌套 Map | 递归部分匹配子对象 | `Map{"user": Map{"id": 1}}` |
|
|
|
|
|
|
|
|
|
|
|
|
### 预期写法
|
|
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
|
// 断言 total 值
|
|
|
|
|
|
a.Query(Map{"page": "1"}).Get("查询列表", 0, Map{"total": 5})
|
|
|
|
|
|
|
|
|
|
|
|
// 断言 token 字段存在且非空(不关心具体值)
|
|
|
|
|
|
resp := a.JSON(Map{"phone": "138...", "password": "123456"}).Post("正常登录", 0, Map{"token": notEmpty})
|
|
|
|
|
|
|
|
|
|
|
|
// 组合:status + msg + result 字段三合一
|
|
|
|
|
|
a.JSON(Map{"phone": ""}).Post("手机号为空", 4, "手机号不能为空") // 只验 status+msg
|
|
|
|
|
|
a.JSON(Map{"phone": "138..."}).Post("正常注册", 0, Map{"id": notEmpty}) // 验 status + result.id
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 失败输出格式
|
|
|
|
|
|
|
|
|
|
|
|
失败时应显示期望值和实际值对比,便于快速定位:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
--- FAIL: TestApi/app/user/login/正常登录
|
|
|
|
|
|
期望 result.token 非空,实际值为 ""
|
|
|
|
|
|
期望 result.total = 10,实际值为 0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 实现要点
|
|
|
|
|
|
|
|
|
|
|
|
- 参数类型可设计为 `...interface{}`,兼容现有 `msg ...string` 的调用方式,通过类型断言区分
|
|
|
|
|
|
- `notEmpty` 可定义为框架内的特殊常量(如 `var notEmpty = struct{}{}`)
|
|
|
|
|
|
- 断言逻辑复用 `ApiResponse` 已有的 `GetBody()` 链路,递归遍历期望 Map
|
|
|
|
|
|
|
|
|
|
|
|
### 待确认
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] 终端方法签名如何兼容:新增第四参数 `result Map`,还是利用 `...interface{}` 统一
|
|
|
|
|
|
- [ ] `notEmpty` 常量的导出名称和定义位置
|
|
|
|
|
|
- [ ] 嵌套 Map 递归断言是否纳入首批实现范围
|
|
|
|
|
|
- [ ] 失败输出是否需要完整响应体 dump
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-25 05:14:18 +08:00
|
|
|
|
## 改进优先级
|
|
|
|
|
|
|
|
|
|
|
|
| 优先级 | 改进项 | 状态 |
|
|
|
|
|
|
|--------|--------|------|
|
|
|
|
|
|
| 高 | 备注语法优化(`\|` 分隔符) | 待设计 |
|
2026-03-16 06:53:31 +08:00
|
|
|
|
| 高 | 测试框架:响应字段部分匹配断言 | 待实现 |
|
2026-07-13 18:11:08 +08:00
|
|
|
|
| 高 | 测试框架其它缺口(DB 断言、FromCase 无模板失败、Header API 等) | 见 [Testing 已知局限](Testing_API测试框架.md#已知局限与后续) |
|
2026-01-25 05:14:18 +08:00
|
|
|
|
| 中 | 软删除/日志表支持 | 待设计 |
|
|
|
|
|
|
| 低 | 多对多关联表增强 | 待评估 |
|
|
|
|
|
|
| 低 | 自动填充字段扩展 | 待评估 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 更新记录
|
|
|
|
|
|
|
|
|
|
|
|
| 日期 | 内容 |
|
|
|
|
|
|
|------|------|
|
2026-07-13 18:11:08 +08:00
|
|
|
|
| 2026-07-13 | 测试框架文档补齐 Flows/控制台;缺口清单链到 Testing |
|
2026-01-25 05:14:18 +08:00
|
|
|
|
| 2026-01-24 | 初始版本,记录分析结果和待改进项 |
|
2026-03-16 06:53:31 +08:00
|
|
|
|
| 2026-03-15 | 新增测试框架响应字段断言改进规划(七) |
|
2026-03-20 11:25:09 +08:00
|
|
|
|
| 2026-03-20 | 完成达梦(DM8)数据库完整支持:Dialect 适配(MERGE INTO Upsert、双引号标识符)、LastInsertId、保留字自动引号、schema 正确处理、代码生成器 DM 兼容、缓存表自动建表、测试框架 DM 适配 |
|