| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- // demo: gormvrtx (TsDB2 GORM Dialector) 完整走查。
- //
- // 覆盖: AutoMigrate (建表/加列/索引) → CRUD → 事务 → Preload 关联 (独立第二条查询,
- // 不走 JOIN)。每步断言, 失败打印并 os.Exit(1)。
- //
- // 运行: cd gormvrtx/demo && go run main.go
- // 依赖: 主模块 git.ycl.pub/yl32940/TsDB2 (go.mod replace 到 ../..)
- package main
- import (
- "errors"
- "fmt"
- "os"
- "path/filepath"
- "time"
- "gorm.io/gorm"
- "git.ycl.pub/yl32940/TsDB2/gormvrtx"
- )
- // User 与 Order: has-many 关联, Preload 时 GORM 会单独发一条 IN 查询 (不 JOIN)。
- type User struct {
- ID uint `gorm:"primaryKey"`
- Name string `gorm:"size:32;not null"`
- Age int
- Email string `gorm:"size:64;uniqueIndex"`
- Orders []Order `gorm:"foreignKey:UserID"`
- }
- // UserWithAddr 迁移演进的下一步: 加一列。
- type UserWithAddr struct {
- ID uint `gorm:"primaryKey"`
- Name string `gorm:"size:32;not null"`
- Age int
- Email string `gorm:"size:64;uniqueIndex"`
- Addr string `gorm:"size:128"`
- }
- func (UserWithAddr) TableName() string { return "users" }
- type Order struct {
- ID uint `gorm:"primaryKey"`
- UserID uint `gorm:"index"`
- Amount float64
- }
- var failed bool
- // check 断言: 失败即标记并打印。
- func check(ok bool, format string, args ...interface{}) {
- if ok {
- fmt.Printf(" ok: %s\n", fmt.Sprintf(format, args...))
- return
- }
- failed = true
- fmt.Printf(" FAIL: %s\n", fmt.Sprintf(format, args...))
- }
- func main() {
- dir, err := os.MkdirTemp("", "gormvrtx_demo")
- if err != nil {
- panic(err)
- }
- defer os.RemoveAll(dir)
- dsn := filepath.Join(dir, "demo.db")
- db, err := gorm.Open(gormvrtx.Open(dsn), &gorm.Config{})
- if err != nil {
- fmt.Println("打开失败:", err)
- os.Exit(1)
- }
- fmt.Println("[1] AutoMigrate 建表 (主键/普通字段/uniqueIndex)")
- if err := db.AutoMigrate(&User{}, &Order{}); err != nil {
- fmt.Println(" FAIL: AutoMigrate:", err)
- os.Exit(1)
- }
- check(db.Migrator().HasTable(&User{}), "users 表存在")
- check(db.Migrator().HasTable(&Order{}), "orders 表存在")
- check(db.Migrator().HasIndex(&User{}, "pk_users"), "主键索引 pk_users")
- check(db.Migrator().HasIndex(&User{}, "idx_users_email"), "唯一索引 idx_users_email")
- check(db.Migrator().HasIndex(&Order{}, "idx_orders_user_id"), "普通索引 idx_orders_user_id")
- fmt.Println("[2] AutoMigrate 加列 (AddField 路径)")
- if err := db.AutoMigrate(&UserWithAddr{}); err != nil {
- fmt.Println(" FAIL: AutoMigrate 加列:", err)
- os.Exit(1)
- }
- check(db.Migrator().HasColumn(&UserWithAddr{}, "addr"), "addr 列出现")
- fmt.Println("[3] CRUD")
- u := &UserWithAddr{Name: "alice", Age: 30, Email: "alice@example.com", Addr: "Beijing"}
- if err := db.Create(u).Error; err != nil {
- fmt.Println(" FAIL: Create:", err)
- os.Exit(1)
- }
- check(u.ID > 0, "Create 回填主键 ID=%d", u.ID)
- var got UserWithAddr
- if err := db.First(&got, u.ID).Error; err != nil {
- fmt.Println(" FAIL: First:", err)
- os.Exit(1)
- }
- check(got.Name == "alice" && got.Age == 30 && got.Addr == "Beijing",
- "First 读回 name=%s age=%d addr=%s", got.Name, got.Age, got.Addr)
- for i := 0; i < 3; i++ {
- if err := db.Create(&UserWithAddr{Name: fmt.Sprintf("u%d", i), Age: 20 + i,
- Email: fmt.Sprintf("u%d@example.com", i)}).Error; err != nil {
- fmt.Println(" FAIL: Create:", err)
- os.Exit(1)
- }
- }
- var list []UserWithAddr
- if err := db.Where("age >= ?", 20).Order("age desc").Limit(2).Find(&list).Error; err != nil {
- fmt.Println(" FAIL: Find:", err)
- os.Exit(1)
- }
- // alice(30) u2(22) u1(21) u0(20) 满足 age>=20, desc 前 2 = 30,22
- age0, age1 := 0, 0
- if len(list) >= 2 {
- age0, age1 = list[0].Age, list[1].Age
- }
- check(len(list) == 2 && age0 == 30 && age1 == 22,
- "Find+Where+Order+Limit 取回 %d 行 (ages %d,%d)", len(list), age0, age1)
- if err := db.Model(&UserWithAddr{}).Where("id = ?", u.ID).
- Updates(map[string]interface{}{"age": 31}).Error; err != nil {
- fmt.Println(" FAIL: Updates:", err)
- os.Exit(1)
- }
- var after UserWithAddr
- _ = db.First(&after, u.ID)
- check(after.Age == 31, "Updates 生效 age=31")
- var n int64
- _ = db.Model(&UserWithAddr{}).Count(&n)
- check(n == 4, "Count=%d (期望 4)", n)
- if err := db.Where("email = ?", "alice@example.com").Delete(&UserWithAddr{}).Error; err != nil {
- fmt.Println(" FAIL: Delete:", err)
- os.Exit(1)
- }
- _ = db.Model(&UserWithAddr{}).Count(&n)
- check(n == 3, "Delete 后 Count=%d (期望 3)", n)
- fmt.Println("[4] 事务 (回滚 / 提交)")
- boom := errors.New("rollback please")
- err = db.Transaction(func(tx *gorm.DB) error {
- _ = tx.Create(&UserWithAddr{Name: "ghost", Email: "ghost@example.com"})
- return boom
- })
- check(errors.Is(err, boom), "回调错误透出, 事务回滚")
- _ = db.Model(&UserWithAddr{}).Count(&n)
- check(n == 3, "回滚后仍 %d 行", n)
- err = db.Transaction(func(tx *gorm.DB) error {
- return tx.Create(&UserWithAddr{Name: "carol", Age: 41, Email: "carol@example.com"}).Error
- })
- check(err == nil, "事务提交成功")
- _ = db.Model(&UserWithAddr{}).Count(&n)
- check(n == 4, "提交后 %d 行", n)
- fmt.Println("[5] Preload 关联 (独立查询, 不 JOIN)")
- // carol 的 ID
- var carol UserWithAddr
- _ = db.Where("email = ?", "carol@example.com").First(&carol).Error
- for i := 1; i <= 2; i++ {
- if err := db.Create(&Order{UserID: carol.ID, Amount: float64(100 * i)}).Error; err != nil {
- fmt.Println(" FAIL: Create Order:", err)
- os.Exit(1)
- }
- }
- var users []User
- if err := db.Preload("Orders").Where("email = ?", "carol@example.com").Find(&users).Error; err != nil {
- fmt.Println(" FAIL: Preload:", err)
- os.Exit(1)
- }
- check(len(users) == 1 && len(users[0].Orders) == 2,
- "Preload Orders: %d 个用户 / %d 张订单", len(users), ordersOf(users))
- if failed {
- fmt.Println("\n结果: 存在失败项")
- os.Exit(1)
- }
- fmt.Println("\n结果: 全部通过")
- }
- func ordersOf(users []User) int {
- if len(users) >= 1 {
- return len(users[0].Orders)
- }
- return 0
- }
- // time 保留引用 (模型扩展 DATETIME 列时可用的提示)。
- var _ = time.Time{}
|