Skip to content

Commit

Permalink
自定义实现的 driver.ValuerValue 方法,会被调用 3 次
Browse files Browse the repository at this point in the history
  • Loading branch information
niluan304 committed Nov 22, 2024
1 parent fabf3ff commit 3deb1d4
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 50 deletions.
2 changes: 1 addition & 1 deletion db.go
Original file line number Diff line number Diff line change
Expand Up @@ -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] })

Expand Down
86 changes: 80 additions & 6 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,94 @@
package main

import (
"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"}
arrayInput := []string{"A", "B", "C"}
arraySave := []string{"A1", "B1", "C1"}

data := Model{
JsonField: JsonField{
Array: slices.Clone(arrayInput),
},
}

DB.Create(&user)
err := DB.Model(&Model{}).
Create(&data).
Error
if err != nil {
t.Errorf("Failed, create error: %v", err)
}

var result User
if err := DB.First(&result, user.ID).Error; err != nil {
t.Errorf("Failed, got error: %v", err)
if !slices.Equal(data.JsonField.Array, arrayInput) {
t.Errorf("Failed, json field arrayInput not equal")
}

t.Run("Find", func(t *testing.T) {
var row *Model
err := DB.Model(&Model{}).
Where("id", data.ID).
Find(&row).
Error
if err != nil {
t.Errorf("Failed, find error: %v", err)
}

arrayFind := row.JsonField.Array
if !slices.Equal(arrayFind, arrayInput) {
t.Errorf("Failed, json field arrayFind %v not equal arrayInput %v", arrayFind, arrayInput)
}

t.Run("Find With SkipCustomMethod", func(t *testing.T) {
var modelSkip *ModelSkip
err = DB.Model(&Model{}).
Where("id", data.ID).
Find(&modelSkip).
Error
if err != nil {
t.Errorf("Failed, get error: %v", err)
}

arraySkip := modelSkip.JsonField.Array
if !slices.Equal(arraySkip, arraySave) {
t.Errorf("Failed, modelSkip field arraySkip %v not equal arraySave %v", arraySkip, arraySave)
}
})

t.Run("Update", func(t *testing.T) {
arrayUpdate := []string{"X", "Y", "Z"}
arrayUpdateSave := []string{"X1", "Y1", "Z1"}

err = DB.Model(&Model{}).
Where("id", row.ID).
Updates(Model{
JsonField: JsonField{
Array: slices.Clone(arrayUpdate),
},
}).
Error
if err != nil {
t.Errorf("Failed, update error: %v", err)
}

var modelSkip *ModelSkip
err = DB.Model(&Model{}).
Where("id", row.ID).
Find(&modelSkip).Error
if err != nil {
t.Errorf("Failed, get error: %v", err)
}

arraySkip := modelSkip.JsonField.Array
if !slices.Equal(arraySkip, arrayUpdateSave) {
t.Errorf("Failed, json field %v arrayInput not equal arrayUpdateSave %v", arraySkip, arrayUpdateSave)
}
})
})

}
88 changes: 45 additions & 43 deletions models.go
Original file line number Diff line number Diff line change
@@ -1,60 +1,62 @@
package main

import (
"database/sql"
"time"
"database/sql/driver"
"encoding/json"
"fmt"
"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) {
for i := range j.Array {
j.Array[i] += "1" // 我想要修改(加密)原来的字段,I want to modify/encrypt the fields
}

data, err := json.Marshal(j)
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"`
}

0 comments on commit 3deb1d4

Please sign in to comment.