From 18799bb9eb23edbb78c5efea2d193e52b40b4a5c Mon Sep 17 00:00:00 2001 From: Zwei Date: Sat, 23 Nov 2024 00:26:26 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E7=9A=84=20`driver.Valuer`=20=E7=9A=84=20`Value`=20=E6=96=B9?= =?UTF-8?q?=E6=B3=95=EF=BC=8C=E4=BC=9A=E8=A2=AB=E8=B0=83=E7=94=A8=203=20?= =?UTF-8?q?=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db.go | 2 +- main_test.go | 98 ++++++++++++++++++++++++++++++++++++++++++++++++---- models.go | 92 +++++++++++++++++++++++++----------------------- 3 files changed, 141 insertions(+), 51 deletions(-) diff --git a/db.go b/db.go index ccab03ed..fafc475c 100644 --- a/db.go +++ b/db.go @@ -83,7 +83,7 @@ func OpenTestConnection() (db *gorm.DB, err error) { func RunMigrations() { var err error - allModels := []interface{}{&User{}, &Account{}, &Pet{}, &Company{}, &Toy{}, &Language{}} + allModels := []interface{}{&Model{}} rand.Seed(time.Now().UnixNano()) rand.Shuffle(len(allModels), func(i, j int) { allModels[i], allModels[j] = allModels[j], allModels[i] }) diff --git a/main_test.go b/main_test.go index 60a388f7..a1aea73e 100644 --- a/main_test.go +++ b/main_test.go @@ -1,20 +1,104 @@ package main import ( + "context" + "slices" "testing" ) // GORM_REPO: https://github.com/go-gorm/gorm.git // GORM_BRANCH: master // TEST_DRIVERS: sqlite, mysql, postgres, sqlserver - func TestGORM(t *testing.T) { - user := User{Name: "jinzhu"} - - DB.Create(&user) + arrayInput := []string{"A", "B", "C"} + arraySave := []string{"A1", "B1", "C1"} - var result User - if err := DB.First(&result, user.ID).Error; err != nil { - t.Errorf("Failed, got error: %v", err) + data := Model{ + JsonField: JsonField{ + Array: slices.Clone(arrayInput), + }, } + + t.Run("Create", func(t *testing.T) { + err := DB.WithContext(context.TODO()).Model(&Model{}). + Create(&data). + Error + if err != nil { + t.Errorf("Failed, create error: %v", err) + } + + arrayCreate := data.JsonField.Array + t.Logf("arrayCreate is %v", arrayCreate) + if !slices.Equal(arrayCreate, arrayInput) { + t.Errorf("Failed, json field arrayCreate %v not equal arrayInput %v", arrayCreate, arrayInput) + } + }) + + t.Run("Find With SkipCustomMethod", func(t *testing.T) { + var modelSkip *ModelSkip + err := DB.WithContext(context.TODO()).Model(&Model{}). + Where("id", data.ID). + Find(&modelSkip). + Error + if err != nil { + t.Errorf("Failed, get error: %v", err) + } + + arraySkip := modelSkip.JsonField.Array + t.Logf("arraySkip is %v", arraySkip) + if !slices.Equal(arraySkip, arraySave) { + t.Errorf("Failed, modelSkip field arraySkip %v not equal arraySave %v", arraySkip, arraySave) + } + }) + + t.Run("Find", func(t *testing.T) { + var row *Model + err := DB.WithContext(context.TODO()).Model(&Model{}). + Where("id", data.ID). + Find(&row). + Error + if err != nil { + t.Errorf("Failed, find error: %v", err) + } + + arrayFind := row.JsonField.Array + t.Logf("arrayFind is %v", arrayFind) + if !slices.Equal(arrayFind, arrayInput) { + t.Errorf("Failed, json field arrayFind %v not equal arrayInput %v", arrayFind, arrayInput) + } + }) + + t.Run("Update", func(t *testing.T) { + arrayUpdate := []string{"X", "Y", "Z"} + arrayUpdateSave := []string{"X1", "Y1", "Z1"} + + err := DB.WithContext(context.TODO()).Model(&Model{}). + Where("id", data.ID). + Updates(Model{ + JsonField: JsonField{ + Array: slices.Clone(arrayUpdate), + }, + }). + Error + if err != nil { + t.Errorf("Failed, update error: %v", err) + } + + t.Run("ModelSkip", func(t *testing.T) { + var modelSkip *ModelSkip + err = DB.WithContext(context.TODO()).Model(&Model{}). + Where("id", data.ID). + Find(&modelSkip).Error + if err != nil { + t.Errorf("Failed, get error: %v", err) + } + + arraySkip := modelSkip.JsonField.Array + t.Logf("arraySkip is %v", arraySkip) + if !slices.Equal(arraySkip, arrayUpdateSave) { + t.Errorf("Failed, json field %v arrayInput not equal arrayUpdateSave %v", arraySkip, arrayUpdateSave) + } + }) + }) + } diff --git a/models.go b/models.go index 692a6842..fd175692 100644 --- a/models.go +++ b/models.go @@ -1,60 +1,66 @@ package main import ( - "database/sql" - "time" + "database/sql/driver" + "encoding/json" + "fmt" + "slices" + "strings" "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 { +type Model 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 -} - -type Account struct { - gorm.Model - UserID sql.NullInt64 - Number string + JsonField JsonField `gorm:"type:json;not null;" json:"jsonField"` } -type Pet struct { - gorm.Model - UserID *uint - Name string - Toy Toy `gorm:"polymorphic:Owner;"` +type JsonField struct { + Array []string `json:"array"` } -type Toy struct { - gorm.Model - Name string - OwnerID string - OwnerType string +func (j *JsonField) Scan(src any) error { + err := json.Unmarshal(src.([]byte), &j) + if err != nil { + return fmt.Errorf("json scan fail, err: %w", err) + } + + for i, s := range j.Array { + j.Array[i], _ = strings.CutSuffix(s, "1") + } + + return nil +} + +func (j JsonField) Value() (driver.Value, error) { + clone := slices.Clone(j.Array) + for i := range clone { + clone[i] += "1" // 我想要修改(加密)原来的字段,I want to modify/encrypt the fields + } + + data, err := json.Marshal(JsonField{ + Array: clone, + }) + if err != nil { + return nil, fmt.Errorf("json marshal fail, err: %w", err) + } + + return data, nil +} + +type SkipCustomMethod struct { + Array []string `gorm:"type:json;not null;" json:"array"` +} + +func (s *SkipCustomMethod) Scan(src any) error { + return json.Unmarshal(src.([]byte), &s) } -type Company struct { - ID int - Name string +func (s SkipCustomMethod) Value() (driver.Value, error) { + return json.Marshal(s) } -type Language struct { - Code string `gorm:"primarykey"` - Name string +// ModelSkip to skip JsonField.Value and JsonField.Scan +type ModelSkip struct { + JsonField SkipCustomMethod `json:"jsonField"` }