From 7981a53f1033d2babc045a6d2d62f8723cbfa6bf Mon Sep 17 00:00:00 2001 From: Stephano George Date: Wed, 21 Sep 2022 14:09:51 +0800 Subject: [PATCH] Find/Scan bug when JOIN --- db.go | 13 ++++++++---- go.mod | 13 ++++-------- main_test.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++------ models.go | 55 ++++++++++++--------------------------------------- 4 files changed, 76 insertions(+), 61 deletions(-) diff --git a/db.go b/db.go index ccab03ed..478599ad 100644 --- a/db.go +++ b/db.go @@ -1,6 +1,7 @@ package main import ( + "gorm.io/gorm/schema" "log" "math/rand" "os" @@ -69,7 +70,9 @@ func OpenTestConnection() (db *gorm.DB, err error) { db, err = gorm.Open(sqlserver.Open(dbDSN), &gorm.Config{}) default: log.Println("testing sqlite3...") - db, err = gorm.Open(sqlite.Open(filepath.Join(os.TempDir(), "gorm.db")), &gorm.Config{}) + db, err = gorm.Open(sqlite.Open(filepath.Join(os.TempDir(), "gorm.db")), &gorm.Config{ + NamingStrategy: schema.NamingStrategy{SingularTable: true}, + }) } if debug := os.Getenv("DEBUG"); debug == "true" { @@ -83,12 +86,14 @@ func OpenTestConnection() (db *gorm.DB, err error) { func RunMigrations() { var err error - allModels := []interface{}{&User{}, &Account{}, &Pet{}, &Company{}, &Toy{}, &Language{}} + err = DB.SetupJoinTable(&User{}, "Languages", &UserLanguage{}) + if err != nil { + panic(err) + } + allModels := []interface{}{&User{}, &Pet{}, &Language{}, &UserLanguage{}} rand.Seed(time.Now().UnixNano()) rand.Shuffle(len(allModels), func(i, j int) { allModels[i], allModels[j] = allModels[j], allModels[i] }) - DB.Migrator().DropTable("user_friends", "user_speaks") - if err = DB.Migrator().DropTable(allModels...); err != nil { log.Printf("Failed to drop table, got error %v\n", err) os.Exit(1) diff --git a/go.mod b/go.mod index 4da7ed1f..b6a22196 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,9 @@ module gorm.io/playground go 1.16 require ( - github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect - github.com/jackc/pgx/v4 v4.16.1 // indirect - golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 // indirect - gorm.io/driver/mysql v1.3.3 - gorm.io/driver/postgres v1.3.5 - gorm.io/driver/sqlite v1.3.2 + gorm.io/driver/mysql v1.3.6 + gorm.io/driver/postgres v1.3.10 + gorm.io/driver/sqlite v1.3.6 gorm.io/driver/sqlserver v1.3.2 - gorm.io/gorm v1.23.4 + gorm.io/gorm v1.23.9 ) - -replace gorm.io/gorm => ./gorm diff --git a/main_test.go b/main_test.go index 60a388f7..3b9930fc 100644 --- a/main_test.go +++ b/main_test.go @@ -1,6 +1,8 @@ package main import ( + "database/sql" + "log" "testing" ) @@ -8,13 +10,55 @@ import ( // GORM_BRANCH: master // TEST_DRIVERS: sqlite, mysql, postgres, sqlserver -func TestGORM(t *testing.T) { - user := User{Name: "jinzhu"} +type Result struct { + User + UserLanguage + Language + Pet +} - DB.Create(&user) +func TestGORM(t *testing.T) { + if err := DB.Create(&User{Name: "jinzhu"}).Error; err != nil { + panic(err) + } + if err := DB.Create(&Language{Name: "ZH"}).Error; err != nil { + panic(err) + } + if err := DB.Create(&UserLanguage{UserID: 1, LanguageID: 1, Skilled: sql.NullBool{Bool: true, Valid: true}}).Error; err != nil { + panic(err) + } + if err := DB.Create(&Pet{UserID: 1, Name: "mimi"}).Error; err != nil { + panic(err) + } + results := query() + for _, result := range results { + if result.Pet.UserID == 0 { + panic("result.Pet.UserID == 0") + } else if result.Pet.Name != "mimi" { + log.Fatalf("result.Pet.Name != \"mimi\": %s", result.Pet.Name) + } + } + if err := DB.Create(&Pet{UserID: 1, Name: "wang"}).Error; err != nil { + panic(err) + } + results = query() + for _, result := range results { + if result.Language.Name != "ZH" { + log.Fatalf("result.Language.Name != \"ZH\": %s", result.Language.Name) + } + if result.Pet.UserID == 0 { + panic("result.Pet.UserID == 0") + } + } +} - var result User - if err := DB.First(&result, user.ID).Error; err != nil { - t.Errorf("Failed, got error: %v", err) +func query() []Result { + results := make([]Result, 0, 8) + if err := DB.Select("user.*, user_language.*, language.*, pet.*").Table("user"). + Joins("JOIN user_language ON user_language.user_id = user.id"). + Joins("JOIN language ON language.id = user_language.language_id"). + Joins("LEFT OUTER JOIN pet ON pet.user_id = user.id").Find(&results).Error; err != nil { + panic(err) } + return results } diff --git a/models.go b/models.go index 692a6842..38bc1d02 100644 --- a/models.go +++ b/models.go @@ -2,59 +2,30 @@ package main import ( "database/sql" - "time" - "gorm.io/gorm" ) -// User has one `Account` (has one), many `Pets` (has many) and `Toys` (has many - polymorphic) -// He works in a Company (belongs to), he has a Manager (belongs to - single-table), and also managed a Team (has many - single-table) -// He speaks many languages (many to many) and has many friends (many to many - single-table) -// His pet also has one Toy (has one - polymorphic) type User struct { gorm.Model Name string - Age uint - Birthday *time.Time - Account Account - Pets []*Pet - Toys []Toy `gorm:"polymorphic:Owner"` - CompanyID *int - Company Company - ManagerID *uint - Manager *User - Team []User `gorm:"foreignkey:ManagerID"` - Languages []Language `gorm:"many2many:UserSpeak"` - Friends []*User `gorm:"many2many:user_friends"` - Active bool + Pets []Pet + Languages []Language `gorm:"many2many:user_language;"` } -type Account struct { - gorm.Model - UserID sql.NullInt64 - Number string +type Language struct { + ID uint `gorm:"primaryKey"` + Name string } -type Pet struct { - gorm.Model - UserID *uint - Name string - Toy Toy `gorm:"polymorphic:Owner;"` +type UserLanguage struct { + UserID uint `gorm:"primaryKey"` + LanguageID uint `gorm:"primaryKey"` + Language Language + Skilled sql.NullBool } -type Toy struct { +type Pet struct { gorm.Model - Name string - OwnerID string - OwnerType string -} - -type Company struct { - ID int - Name string -} - -type Language struct { - Code string `gorm:"primarykey"` - Name string + UserID uint + Name string }