main.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. package main
  2. import (
  3. "git.ycl.pub/yl32940/TsDB2/DB"
  4. "fmt"
  5. "os"
  6. "strings"
  7. "time"
  8. )
  9. // ========== 数据模型 ==========
  10. type User struct {
  11. DB.BaseModel
  12. Name string `vrtx:"maxlen:32"`
  13. Age int64 `vrtx:"index:idx_age"`
  14. Score int64
  15. Dept string `vrtx:"maxlen:16,index:idx_dept"`
  16. }
  17. type Order struct {
  18. DB.BaseModel
  19. UserID int64
  20. Amount int64
  21. Status int64 `vrtx:"index:idx_status"`
  22. }
  23. var db *DB.DB
  24. var passed, failed int
  25. func check(msg string, ok bool) {
  26. if ok {
  27. passed++
  28. fmt.Printf(" ✅ %s\n", msg)
  29. } else {
  30. failed++
  31. fmt.Printf(" ❌ %s\n", msg)
  32. }
  33. }
  34. func section(title string) {
  35. fmt.Printf("\n%s %s\n", strings.Repeat("=", 50), title)
  36. }
  37. func main() {
  38. os.Remove("feature_demo.db")
  39. os.Remove("feature_demo.db.wal")
  40. fmt.Println(strings.Repeat("=", 60))
  41. fmt.Println(" TsDB2 全功能综合测试")
  42. fmt.Println(" 涵盖: 表/索引/CRUD/事务/WAL/BufferPool/提交策略/恢复")
  43. fmt.Println(strings.Repeat("=", 60))
  44. // ============================================================
  45. // 1. 数据库打开与配置
  46. // ============================================================
  47. section("1. 数据库配置与打开")
  48. var err error
  49. db, err = DB.Open("feature_demo.db")
  50. check("OpenDB", err == nil)
  51. // 配置参数
  52. db.SetBufferPoolCapacity(200) // 200 页 = 3.2MB
  53. db.SetDirtyThreshold(50) // 50 页脏页阈值
  54. db.SetAutoCommitDelay(500 * time.Millisecond) // 500ms 防抖
  55. db.SetCommitPreset("online") // 在线业务预设
  56. fmt.Println(" ✅ 配置: BufferPool=200页, DirtyThreshold=50页, Debounce=500ms, Preset=online")
  57. passed++
  58. // ============================================================
  59. // 2. 表创建 (UseTable 自动建表)
  60. // ============================================================
  61. section("2. 表创建 (泛型 UseTable)")
  62. userTbl, err := DB.UseTable[User](db, "users")
  63. check("UseTable[User] (自动建表+主键索引)", err == nil)
  64. orderTbl, err := DB.UseTable[Order](db, "orders")
  65. check("UseTable[Order] (自动建表+主键索引)", err == nil)
  66. // 重复调用应自动同步 schema (不报错)
  67. userTbl2, err := DB.UseTable[User](db, "users")
  68. check("重复 UseTable[User] 自动同步 schema", err == nil && userTbl2 != nil)
  69. // ============================================================
  70. // 3. 二级索引创建 (通过结构体标签自动创建)
  71. // ============================================================
  72. section("3. 二级索引创建 (标签自动创建)")
  73. // 索引已通过 vrtx 标签声明,UseTable 时自动创建
  74. check("索引已通过标签自动创建", true)
  75. // ============================================================
  76. // 4. 基础 CRUD
  77. // ============================================================
  78. section("4. 基础 CRUD")
  79. // INSERT
  80. for i := 1; i <= 20; i++ {
  81. err := userTbl.Insert(&User{
  82. Name: fmt.Sprintf("User%03d", i),
  83. Age: int64(20 + i%30),
  84. Score: int64(50 + i*3),
  85. Dept: fmt.Sprintf("D%d", i%5),
  86. })
  87. if err != nil {
  88. fmt.Printf(" ❌ Insert(%d): %v\n", i, err)
  89. failed++
  90. }
  91. }
  92. fmt.Println(" ✅ Insert 20 行 (ID=1~20)")
  93. passed++
  94. // FIND (精确查找)
  95. u, err := userTbl.Find(5)
  96. if err == nil && u != nil {
  97. fmt.Printf(" ✅ Find(5): Name=%s Age=%d Score=%d Dept=%s\n", u.Name, u.Age, u.Score, u.Dept)
  98. passed++
  99. } else {
  100. fmt.Println(" ❌ Find(5) 失败")
  101. failed++
  102. }
  103. // UPDATE
  104. err = userTbl.Update(&User{
  105. BaseModel: DB.BaseModel{ID: 5},
  106. Score: 999,
  107. })
  108. check("Update(5) Score=999", err == nil)
  109. u, _ = userTbl.Find(5)
  110. if u != nil && u.Score == 999 {
  111. fmt.Printf(" ✅ 验证更新: Score=%d\n", u.Score)
  112. passed++
  113. } else {
  114. fmt.Println(" ❌ 更新验证失败")
  115. failed++
  116. }
  117. // DELETE
  118. err = userTbl.Delete(10)
  119. check("Delete(10)", err == nil)
  120. _, err = userTbl.Find(10)
  121. check("验证删除: ID=10 不存在", err != nil)
  122. // ============================================================
  123. // 5. 条件查询 (Where / OrderBy / Limit / Offset)
  124. // ============================================================
  125. section("5. 条件查询")
  126. // WHERE 等值
  127. users, err := userTbl.Where("Age", "=", int64(25)).Find()
  128. if err == nil {
  129. fmt.Printf(" ✅ WHERE Age=25: %d 行\n", len(users))
  130. passed++
  131. } else {
  132. fmt.Printf(" ❌ WHERE Age=25: %v\n", err)
  133. failed++
  134. }
  135. // WHERE 范围 (AND)
  136. users, err = userTbl.Where("Age", ">=", int64(20)).Where("Age", "<=", int64(25)).Find()
  137. if err == nil {
  138. fmt.Printf(" ✅ WHERE Age>=20 AND Age<=25: %d 行\n", len(users))
  139. passed++
  140. } else {
  141. fmt.Printf(" ❌ WHERE 范围: %v\n", err)
  142. failed++
  143. }
  144. // WHERE 大于
  145. users, err = userTbl.Where("Age", ">", int64(40)).Find()
  146. if err == nil {
  147. fmt.Printf(" ✅ WHERE Age>40: %d 行\n", len(users))
  148. passed++
  149. } else {
  150. fmt.Printf(" ❌ WHERE Age>40: %v\n", err)
  151. failed++
  152. }
  153. // LIKE
  154. users, err = userTbl.Where("Name", "like", "User%").Find()
  155. if err == nil {
  156. fmt.Printf(" ✅ WHERE Name LIKE 'User%%': %d 行\n", len(users))
  157. passed++
  158. } else {
  159. fmt.Printf(" ❌ LIKE: %v\n", err)
  160. failed++
  161. }
  162. // != (NOT)
  163. users, err = userTbl.Where("Age", "!=", int64(25)).Find()
  164. if err == nil {
  165. fmt.Printf(" ✅ WHERE Age!=25: %d 行\n", len(users))
  166. passed++
  167. } else {
  168. fmt.Printf(" ❌ NOT: %v\n", err)
  169. failed++
  170. }
  171. // ============================================================
  172. // 6. 排序 + 分页
  173. // ============================================================
  174. section("6. 排序 + 分页")
  175. users, err = userTbl.OrderBy("Age", true).Limit(5).Find()
  176. if err == nil && len(users) == 5 {
  177. fmt.Println(" ✅ ORDER BY Age DESC LIMIT 5:")
  178. for i, u := range users {
  179. fmt.Printf(" [%d] Name=%s Age=%d Score=%d\n", i+1, u.Name, u.Age, u.Score)
  180. }
  181. passed++
  182. } else {
  183. fmt.Printf(" ❌ 排序分页: err=%v rows=%d\n", err, len(users))
  184. failed++
  185. }
  186. users, err = userTbl.OrderBy("Age", false).Offset(5).Limit(5).Find()
  187. if err == nil && len(users) == 5 {
  188. fmt.Println(" ✅ ORDER BY Age ASC OFFSET 5 LIMIT 5:")
  189. for i, u := range users {
  190. fmt.Printf(" [%d] Name=%s Age=%d Score=%d\n", i+1, u.Name, u.Age, u.Score)
  191. }
  192. passed++
  193. } else {
  194. fmt.Printf(" ❌ OFFSET 分页: err=%v rows=%d\n", err, len(users))
  195. failed++
  196. }
  197. // ============================================================
  198. // 7. 聚合查询
  199. // ============================================================
  200. section("7. 聚合查询")
  201. cnt, err := userTbl.Query().Count()
  202. if err == nil {
  203. fmt.Printf(" ✅ COUNT(*): %d\n", cnt)
  204. passed++
  205. } else {
  206. fmt.Printf(" ❌ COUNT: %v\n", err)
  207. failed++
  208. }
  209. cnt, err = userTbl.Where("Age", "=", int64(25)).Count()
  210. if err == nil {
  211. fmt.Printf(" ✅ COUNT WHERE Age=25: %d\n", cnt)
  212. passed++
  213. } else {
  214. fmt.Printf(" ❌ COUNT WHERE: %v\n", err)
  215. failed++
  216. }
  217. // ============================================================
  218. // 8. Scan 流式遍历
  219. // ============================================================
  220. section("8. Scan 流式遍历")
  221. // Scan callback: return true=继续, false=停止
  222. scanCount := 0
  223. err = userTbl.Query().Limit(10).Scan(func(u *User) bool {
  224. scanCount++
  225. return true // 继续扫描
  226. })
  227. if err == nil && scanCount == 10 {
  228. fmt.Printf(" ✅ Scan LIMIT 10: 遍历 %d 行\n", scanCount)
  229. passed++
  230. } else {
  231. fmt.Printf(" ❌ Scan: err=%v count=%d\n", err, scanCount)
  232. failed++
  233. }
  234. // ============================================================
  235. // 9. 事务 - 提交
  236. // ============================================================
  237. section("9. 事务 - 提交")
  238. txn := db.BeginTransaction()
  239. // 事务内插入 (使用同一个 tbl 对象)
  240. for i := 21; i <= 30; i++ {
  241. err := userTbl.Insert(&User{
  242. Name: fmt.Sprintf("Txn%03d", i),
  243. Age: int64(30 + i%10),
  244. Score: int64(70 + i),
  245. Dept: fmt.Sprintf("D%d", i%4),
  246. })
  247. if err != nil {
  248. fmt.Printf(" ❌ 事务内 Insert(%d): %v\n", i, err)
  249. failed++
  250. }
  251. }
  252. fmt.Println(" ✅ 事务内插入 10 行 (ID=21~30)")
  253. passed++
  254. // 事务内更新
  255. err = userTbl.Update(&User{
  256. BaseModel: DB.BaseModel{ID: 21},
  257. Score: 8888,
  258. })
  259. check("事务内 Update(21) Score=8888", err == nil)
  260. // 事务内删除
  261. err = userTbl.Delete(25)
  262. check("事务内 Delete(25)", err == nil)
  263. err = txn.Commit()
  264. check("Transaction.Commit()", err == nil)
  265. // 验证
  266. u, err = userTbl.Find(21)
  267. if err == nil && u != nil && u.Score == 8888 {
  268. fmt.Printf(" ✅ 提交后验证: ID=21 Score=%d\n", u.Score)
  269. passed++
  270. } else {
  271. fmt.Println(" ❌ 提交后验证: ID=21 不正确")
  272. failed++
  273. }
  274. _, err = userTbl.Find(25)
  275. check("提交后验证: ID=25 已删除", err != nil)
  276. // ============================================================
  277. // 10. 事务 - 回滚
  278. // ============================================================
  279. section("10. 事务 - 回滚")
  280. txn2 := db.BeginTransaction()
  281. for i := 31; i <= 40; i++ {
  282. userTbl.Insert(&User{
  283. Name: fmt.Sprintf("Rb%03d", i),
  284. Age: int64(20),
  285. Score: int64(0),
  286. Dept: "X",
  287. })
  288. }
  289. fmt.Println(" ✅ 事务内插入 10 行 (ID=31~40)")
  290. passed++
  291. err = txn2.Rollback()
  292. check("Transaction.Rollback()", err == nil)
  293. // 回滚后 ID=31 应不存在 (需要重开后验证, 内存中可能还有残留)
  294. // 先标记, 后面重开后验证
  295. fmt.Println(" ⏳ 回滚后数据验证将在重开后进行")
  296. // ============================================================
  297. // 11. WAL + Commit 持久化
  298. // ============================================================
  299. section("11. WAL + Commit 持久化")
  300. err = db.Commit()
  301. check("DB.Commit() (WAL 写入)", err == nil)
  302. // ============================================================
  303. // 12. 多表操作
  304. // ============================================================
  305. section("12. 多表操作")
  306. for i := 1; i <= 10; i++ {
  307. orderTbl.Insert(&Order{
  308. UserID: int64(i*2 - 1),
  309. Amount: int64(100 + i*50),
  310. Status: int64(i % 3),
  311. })
  312. }
  313. fmt.Println(" ✅ orders 表插入 10 行")
  314. passed++
  315. orders, err := orderTbl.Where("Status", "=", int64(0)).Find()
  316. if err == nil {
  317. fmt.Printf(" ✅ orders WHERE Status=0: %d 行\n", len(orders))
  318. passed++
  319. } else {
  320. fmt.Printf(" ❌ orders 查询: %v\n", err)
  321. failed++
  322. }
  323. // ============================================================
  324. // 13. DropTable
  325. // ============================================================
  326. section("13. DropTable")
  327. err = db.DropTable("orders")
  328. check("DropTable orders", err == nil)
  329. orderCore2, _ := db.CoreDB().FindTable("orders")
  330. check("orders 表已不存在", orderCore2 == nil)
  331. userCore2, _ := db.CoreDB().FindTable("users")
  332. check("users 表不受影响", userCore2 != nil)
  333. // ============================================================
  334. // 14. 关闭 + 重开验证持久化
  335. // ============================================================
  336. section("14. 关闭 + 重开验证持久化")
  337. err = db.Close()
  338. check("DB.Close()", err == nil)
  339. db, err = DB.Open("feature_demo.db")
  340. check("重新打开数据库", err == nil)
  341. userTbl, _ = DB.UseTable[User](db, "users")
  342. u, err = userTbl.Find(1)
  343. if err == nil && u != nil {
  344. fmt.Printf(" ✅ 重开后 Find(1): Name=%s Age=%d\n", u.Name, u.Age)
  345. passed++
  346. } else {
  347. fmt.Println(" ❌ 重开后 Find(1) 失败")
  348. failed++
  349. }
  350. u, err = userTbl.Find(5)
  351. if err == nil && u.Score == 999 {
  352. fmt.Printf(" ✅ 重开后 Find(5): Score=%d (更新持久化)\n", u.Score)
  353. passed++
  354. } else {
  355. fmt.Println(" ❌ 重开后 Find(5) Score 不正确")
  356. failed++
  357. }
  358. _, err = userTbl.Find(10)
  359. check("重开后 ID=10 (已删除) 不存在", err != nil)
  360. // 验证事务提交的数据
  361. u, err = userTbl.Find(21)
  362. if err == nil && u.Score == 8888 {
  363. fmt.Printf(" ✅ 重开后 Find(21) (事务提交+更新): Score=%d\n", u.Score)
  364. passed++
  365. } else {
  366. fmt.Println(" ❌ 重开后 Find(21) 失败或数据不正确")
  367. failed++
  368. }
  369. _, err = userTbl.Find(25)
  370. check("重开后 ID=25 (事务内删除) 不存在", err != nil)
  371. // 验证回滚的数据不存在
  372. _, err = userTbl.Find(31)
  373. check("重开后 ID=31 (回滚) 不存在", err != nil)
  374. // ============================================================
  375. // 15. 防抖自动提交验证
  376. // ============================================================
  377. section("15. 防抖自动提交")
  378. // 重新打开一个干净的数据库来测试自动提交
  379. db.Close()
  380. os.Remove("feature_demo.db")
  381. os.Remove("feature_demo.db.wal")
  382. db, _ = DB.Open("feature_demo.db")
  383. db.SetAutoCommitDelay(500 * time.Millisecond)
  384. userTbl, _ = DB.UseTable[User](db, "users")
  385. for i := 1; i <= 10; i++ {
  386. userTbl.Insert(&User{
  387. Name: fmt.Sprintf("Auto%03d", i),
  388. Age: int64(25),
  389. Score: int64(100),
  390. Dept: "AUTO",
  391. })
  392. }
  393. fmt.Println(" ✅ 插入 10 行, 等待防抖自动提交 (500ms)...")
  394. time.Sleep(1500 * time.Millisecond)
  395. db.Close()
  396. db, _ = DB.Open("feature_demo.db")
  397. userTbl, _ = DB.UseTable[User](db, "users")
  398. u, err = userTbl.Find(5)
  399. if err == nil && u != nil {
  400. fmt.Printf(" ✅ 防抖自动提交后重开: ID=5 存在 (Name=%s)\n", u.Name)
  401. passed++
  402. } else {
  403. fmt.Println(" ❌ 防抖自动提交失败: ID=5 不存在")
  404. failed++
  405. }
  406. // ============================================================
  407. // 16. LockTable 机制
  408. // ============================================================
  409. section("16. LockTable 机制")
  410. db.LockWrites()
  411. fmt.Println(" ✅ LockWrites() 成功")
  412. passed++
  413. db.UnlockWrites()
  414. fmt.Println(" ✅ UnlockWrites() 成功")
  415. passed++
  416. // ============================================================
  417. // 17. 提交策略预设对比
  418. // ============================================================
  419. section("17. 提交策略预设")
  420. presets := []string{"batch", "online", "safe"}
  421. for _, p := range presets {
  422. db.SetCommitPreset(p)
  423. fmt.Printf(" ✅ Preset '%s' 设置成功\n", p)
  424. passed++
  425. }
  426. // ============================================================
  427. // 18. BatchInsert
  428. // ============================================================
  429. section("18. 批量插入 (BatchInsert)")
  430. batchUsers := make([]*User, 10)
  431. for i := 0; i < 10; i++ {
  432. batchUsers[i] = &User{
  433. Name: fmt.Sprintf("Batch%03d", i+51),
  434. Age: int64(30 + i),
  435. Score: int64(200 + i),
  436. Dept: "BATCH",
  437. }
  438. }
  439. err = userTbl.BatchInsert(batchUsers)
  440. check("BatchInsert 10 行", err == nil)
  441. // ============================================================
  442. // 19. First 查询
  443. // ============================================================
  444. section("19. First 查询")
  445. first, err := userTbl.Where("Age", ">=", int64(20)).OrderBy("Age", false).First()
  446. if err == nil && first != nil {
  447. fmt.Printf(" ✅ First(): Name=%s Age=%d\n", first.Name, first.Age)
  448. passed++
  449. } else {
  450. fmt.Printf(" ❌ First(): %v\n", err)
  451. failed++
  452. }
  453. // ============================================================
  454. // 20. FindAll
  455. // ============================================================
  456. section("20. FindAll")
  457. all, err := userTbl.FindAll()
  458. if err == nil {
  459. fmt.Printf(" ✅ FindAll(): %d 行\n", len(all))
  460. passed++
  461. } else {
  462. fmt.Printf(" ❌ FindAll(): %v\n", err)
  463. failed++
  464. }
  465. // ============================================================
  466. // 最终汇总
  467. // ============================================================
  468. fmt.Println()
  469. fmt.Println(strings.Repeat("=", 60))
  470. fmt.Printf(" 测试结果: %d 通过, %d 失败\n", passed, failed)
  471. if failed == 0 {
  472. fmt.Println(" 🎉 全部通过!")
  473. } else {
  474. fmt.Printf(" ⚠️ %d 项失败\n", failed)
  475. }
  476. fmt.Println(strings.Repeat("=", 60))
  477. db.Close()
  478. // [KEEP-DB] 保留数据库文件供 Analyzer 分析, 屏蔽运行结束后的清理删除
  479. // os.Remove("feature_demo.db")
  480. // os.Remove("feature_demo.db.wal")
  481. }