From e5bdd610c36b0e65c957c53f8a4ffb0f11714615 Mon Sep 17 00:00:00 2001 From: kinggo <30891428+longlihale@users.noreply.github.com> Date: Wed, 8 Dec 2021 13:58:06 +0800 Subject: [PATCH 1/4] fix: save not use soft_delete (#4897) * fix: Save not use soft_delete * fix: save not use soft_delete * fix: save not use soft_delete * fix: save not use soft_delete Co-authored-by: kinggo <> --- callbacks/create.go | 2 +- callbacks/delete.go | 17 ++++++++++------- callbacks/query.go | 2 +- callbacks/update.go | 18 +++++++++++------- soft_delete.go | 4 ++-- tests/update_test.go | 8 +++++++- 6 files changed, 32 insertions(+), 19 deletions(-) diff --git a/callbacks/create.go b/callbacks/create.go index 9dc5b8b1..29113128 100644 --- a/callbacks/create.go +++ b/callbacks/create.go @@ -57,7 +57,7 @@ func Create(config *Config) func(db *gorm.DB) { } } - if db.Statement.SQL.String() == "" { + if db.Statement.SQL.Len() == 0 { db.Statement.SQL.Grow(180) db.Statement.AddClauseIfNotExists(clause.Insert{}) db.Statement.AddClause(ConvertToCreateValues(db.Statement)) diff --git a/callbacks/delete.go b/callbacks/delete.go index b05a9d08..7f1e09ce 100644 --- a/callbacks/delete.go +++ b/callbacks/delete.go @@ -118,13 +118,7 @@ func Delete(config *Config) func(db *gorm.DB) { return } - if db.Statement.Schema != nil && !db.Statement.Unscoped { - for _, c := range db.Statement.Schema.DeleteClauses { - db.Statement.AddClause(c) - } - } - - if db.Statement.SQL.String() == "" { + if db.Statement.SQL.Len() == 0 { db.Statement.SQL.Grow(100) db.Statement.AddClauseIfNotExists(clause.Delete{}) @@ -147,6 +141,15 @@ func Delete(config *Config) func(db *gorm.DB) { } db.Statement.AddClauseIfNotExists(clause.From{}) + } + + if db.Statement.Schema != nil { + for _, c := range db.Statement.Schema.DeleteClauses { + db.Statement.AddClause(c) + } + } + + if db.Statement.SQL.Len() == 0 { db.Statement.Build(db.Statement.BuildClauses...) } diff --git a/callbacks/query.go b/callbacks/query.go index 2f98a4b6..efb08609 100644 --- a/callbacks/query.go +++ b/callbacks/query.go @@ -33,7 +33,7 @@ func BuildQuerySQL(db *gorm.DB) { } } - if db.Statement.SQL.String() == "" { + if db.Statement.SQL.Len() == 0 { db.Statement.SQL.Grow(100) clauseSelect := clause.Select{Distinct: db.Statement.Distinct} diff --git a/callbacks/update.go b/callbacks/update.go index fa7640de..b3eaaf11 100644 --- a/callbacks/update.go +++ b/callbacks/update.go @@ -59,13 +59,7 @@ func Update(config *Config) func(db *gorm.DB) { return } - if db.Statement.Schema != nil && !db.Statement.Unscoped { - for _, c := range db.Statement.Schema.UpdateClauses { - db.Statement.AddClause(c) - } - } - - if db.Statement.SQL.String() == "" { + if db.Statement.SQL.Len() == 0 { db.Statement.SQL.Grow(180) db.Statement.AddClauseIfNotExists(clause.Update{}) if set := ConvertToAssignments(db.Statement); len(set) != 0 { @@ -73,6 +67,16 @@ func Update(config *Config) func(db *gorm.DB) { } else if _, ok := db.Statement.Clauses["SET"]; !ok { return } + + } + + if db.Statement.Schema != nil { + for _, c := range db.Statement.Schema.UpdateClauses { + db.Statement.AddClause(c) + } + } + + if db.Statement.SQL.Len() == 0 { db.Statement.Build(db.Statement.BuildClauses...) } diff --git a/soft_delete.go b/soft_delete.go index 11c4fafc..4e236fc4 100644 --- a/soft_delete.go +++ b/soft_delete.go @@ -103,7 +103,7 @@ func (sd SoftDeleteUpdateClause) MergeClause(*clause.Clause) { } func (sd SoftDeleteUpdateClause) ModifyStatement(stmt *Statement) { - if stmt.SQL.String() == "" { + if stmt.SQL.Len() == 0 && !stmt.Statement.Unscoped { if _, ok := stmt.Clauses["WHERE"]; stmt.DB.AllowGlobalUpdate || ok { SoftDeleteQueryClause(sd).ModifyStatement(stmt) } @@ -129,7 +129,7 @@ func (sd SoftDeleteDeleteClause) MergeClause(*clause.Clause) { } func (sd SoftDeleteDeleteClause) ModifyStatement(stmt *Statement) { - if stmt.SQL.String() == "" { + if stmt.SQL.Len() == 0 && !stmt.Statement.Unscoped { curTime := stmt.DB.NowFunc() stmt.AddClause(clause.Set{{Column: clause.Column{Name: sd.Field.DBName}, Value: curTime}}) stmt.SetColumn(sd.Field.DBName, curTime, true) diff --git a/tests/update_test.go b/tests/update_test.go index 14ed9820..abe520db 100644 --- a/tests/update_test.go +++ b/tests/update_test.go @@ -645,7 +645,13 @@ func TestSave(t *testing.T) { dryDB := DB.Session(&gorm.Session{DryRun: true}) stmt := dryDB.Save(&user).Statement - if !regexp.MustCompile("WHERE .id. = [^ ]+$").MatchString(stmt.SQL.String()) { + if !regexp.MustCompile(`.id. = .* AND .users.\..deleted_at. IS NULL`).MatchString(stmt.SQL.String()) { + t.Fatalf("invalid updating SQL, got %v", stmt.SQL.String()) + } + + dryDB = DB.Session(&gorm.Session{DryRun: true}) + stmt = dryDB.Unscoped().Save(&user).Statement + if !regexp.MustCompile(`WHERE .id. = [^ ]+$`).MatchString(stmt.SQL.String()) { t.Fatalf("invalid updating SQL, got %v", stmt.SQL.String()) } From 2a578d767f01af839c2e91fdeeb3bbb4caed4ae4 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 10 Dec 2021 10:44:11 +0100 Subject: [PATCH 2/4] Use Golangci configuration file (#4896) --- .github/workflows/reviewdog.yml | 2 -- .golangci.yml | 11 +++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 .golangci.yml diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index abfd57f3..95b6fb04 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -9,5 +9,3 @@ jobs: uses: actions/checkout@v2 - name: golangci-lint uses: reviewdog/action-golangci-lint@v2 - with: - golangci_lint_flags: '-E cyclop,unconvert,misspell,unparam,ineffassign,gocritic,prealloc,exportloopref,gosec' diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..16903ed6 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,11 @@ +linters: + enable: + - cyclop + - exportloopref + - gocritic + - gosec + - ineffassign + - misspell + - prealloc + - unconvert + - unparam From 380cc64ff5b3f5379a076b19b23ed0ddd1638ba7 Mon Sep 17 00:00:00 2001 From: piyongcai Date: Fri, 10 Dec 2021 17:45:36 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix=20type=20alias=20AutoMigrate=20bug?= =?UTF-8?q?=EF=BC=88Add=20Test=20Case=EF=BC=89=20(#4888)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix type alias AutoMigrate bug. eg ```go package main type IDer interface{ GetID() int64 } // ID will add some method to implement some interface eg: GetID type ID int64 func (z ID) GetID() int64 { return int64(z) } type Test struct { ID Code string `gorm:"size:50"` Name string `gorm:"size:50"` } func main() { db, err := gorm.Open(postgres.New(postgres.Config{ DSN: `dsn`, PreferSimpleProtocol: false, }), &gorm.Config{ Logger: logger.Default.LogMode(logger.Info), SkipDefaultTransaction: true, }) if err != nil { log.Fatal(err) } if err = db.AutoMigrate(&Test{}); err != nil { // invalid embedded struct for Test's field ID, should be struct, but got main.ID log.Fatal(err) } } ``` * fix type alias AutoMigrate bug. eg ```go package main type IDer interface{ GetID() int64 } // ID will add some method to implement some interface eg: GetID type ID int64 func (z ID) GetID() int64 { return int64(z) } type Test struct { ID Code string `gorm:"size:50"` Name string `gorm:"size:50"` } func main() { db, err := gorm.Open(postgres.New(postgres.Config{ DSN: `dsn`, PreferSimpleProtocol: false, }), &gorm.Config{ Logger: logger.Default.LogMode(logger.Info), SkipDefaultTransaction: true, }) if err != nil { log.Fatal(err) } if err = db.AutoMigrate(&Test{}); err != nil { // invalid embedded struct for Test's field ID, should be struct, but got main.ID log.Fatal(err) } } ``` * Add typealis test. * try to fix golangci-lint --- schema/field.go | 7 +++-- schema/field_test.go | 66 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/schema/field.go b/schema/field.go index f3189c7a..c6c89cc1 100644 --- a/schema/field.go +++ b/schema/field.go @@ -347,7 +347,9 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field { } if _, ok := field.TagSettings["EMBEDDED"]; ok || (fieldStruct.Anonymous && !isValuer && (field.Creatable || field.Updatable || field.Readable)) { - if reflect.Indirect(fieldValue).Kind() == reflect.Struct { + kind := reflect.Indirect(fieldValue).Kind() + switch kind { + case reflect.Struct: var err error field.Creatable = false field.Updatable = false @@ -396,7 +398,8 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field { ef.TagSettings[k] = v } } - } else { + case reflect.Invalid, reflect.Uintptr, reflect.Array, reflect.Chan, reflect.Func, reflect.Interface, + reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer, reflect.Complex64, reflect.Complex128: schema.err = fmt.Errorf("invalid embedded struct for %s's field %s, should be struct, but got %v", field.Schema.Name, field.Name, field.FieldType) } } diff --git a/schema/field_test.go b/schema/field_test.go index 4be3e5ab..8768a4c3 100644 --- a/schema/field_test.go +++ b/schema/field_test.go @@ -244,7 +244,7 @@ func TestParseFieldWithPermission(t *testing.T) { t.Fatalf("Failed to parse user with permission, got error %v", err) } - fields := []schema.Field{ + fields := []*schema.Field{ {Name: "ID", DBName: "id", BindNames: []string{"ID"}, DataType: schema.Uint, PrimaryKey: true, Size: 64, Creatable: true, Updatable: true, Readable: true, HasDefaultValue: true, AutoIncrement: true}, {Name: "Name", DBName: "", BindNames: []string{"Name"}, DataType: "", Tag: `gorm:"-"`, Creatable: false, Updatable: false, Readable: false}, {Name: "Name2", DBName: "name2", BindNames: []string{"Name2"}, DataType: schema.String, Tag: `gorm:"->"`, Creatable: false, Updatable: false, Readable: true}, @@ -257,6 +257,68 @@ func TestParseFieldWithPermission(t *testing.T) { } for _, f := range fields { - checkSchemaField(t, user, &f, func(f *schema.Field) {}) + checkSchemaField(t, user, f, func(f *schema.Field) {}) } } + +type ID int64 +type INT int +type INT8 int8 +type INT16 int16 +type INT32 int32 +type INT64 int64 +type UINT uint +type UINT8 uint8 +type UINT16 uint16 +type UINT32 uint32 +type UINT64 uint64 +type FLOAT32 float32 +type FLOAT64 float64 +type BOOL bool +type STRING string +type TypeAlias struct { + ID + INT `gorm:"column:fint"` + INT8 `gorm:"column:fint8"` + INT16 `gorm:"column:fint16"` + INT32 `gorm:"column:fint32"` + INT64 `gorm:"column:fint64"` + UINT `gorm:"column:fuint"` + UINT8 `gorm:"column:fuint8"` + UINT16 `gorm:"column:fuint16"` + UINT32 `gorm:"column:fuint32"` + UINT64 `gorm:"column:fuint64"` + FLOAT32 `gorm:"column:ffloat32"` + FLOAT64 `gorm:"column:ffloat64"` + BOOL `gorm:"column:fbool"` + STRING `gorm:"column:fstring"` +} + +func TestTypeAliasField(t *testing.T){ + alias, err := schema.Parse(&TypeAlias{}, &sync.Map{}, schema.NamingStrategy{}) + if err != nil { + t.Fatalf("Failed to parse TypeAlias with permission, got error %v", err) + } + + fields := []*schema.Field{ + {Name: "ID", DBName: "id", BindNames: []string{"ID"}, DataType: schema.Int , Creatable: true, Updatable: true, Readable: true, Size: 64, PrimaryKey: true, HasDefaultValue: true, AutoIncrement: true }, + {Name: "INT", DBName: "fint", BindNames: []string{"INT"}, DataType: schema.Int , Creatable: true, Updatable: true, Readable: true, Size: 64, Tag: `gorm:"column:fint"`}, + {Name: "INT8", DBName: "fint8", BindNames: []string{"INT8"}, DataType: schema.Int , Creatable: true, Updatable: true, Readable: true, Size: 8, Tag: `gorm:"column:fint8"`}, + {Name: "INT16", DBName: "fint16", BindNames: []string{"INT16"}, DataType: schema.Int , Creatable: true, Updatable: true, Readable: true, Size: 16, Tag: `gorm:"column:fint16"`}, + {Name: "INT32", DBName: "fint32", BindNames: []string{"INT32"}, DataType: schema.Int , Creatable: true, Updatable: true, Readable: true, Size: 32, Tag: `gorm:"column:fint32"`}, + {Name: "INT64", DBName: "fint64", BindNames: []string{"INT64"}, DataType: schema.Int , Creatable: true, Updatable: true, Readable: true, Size: 64, Tag: `gorm:"column:fint64"`}, + {Name: "UINT", DBName: "fuint", BindNames: []string{"UINT"}, DataType: schema.Uint , Creatable: true, Updatable: true, Readable: true, Size: 64, Tag: `gorm:"column:fuint"`}, + {Name: "UINT8", DBName: "fuint8", BindNames: []string{"UINT8"}, DataType: schema.Uint , Creatable: true, Updatable: true, Readable: true, Size: 8, Tag: `gorm:"column:fuint8"`}, + {Name: "UINT16", DBName: "fuint16", BindNames: []string{"UINT16"}, DataType: schema.Uint , Creatable: true, Updatable: true, Readable: true, Size: 16, Tag: `gorm:"column:fuint16"`}, + {Name: "UINT32", DBName: "fuint32", BindNames: []string{"UINT32"}, DataType: schema.Uint , Creatable: true, Updatable: true, Readable: true, Size: 32, Tag: `gorm:"column:fuint32"`}, + {Name: "UINT64", DBName: "fuint64", BindNames: []string{"UINT64"}, DataType: schema.Uint , Creatable: true, Updatable: true, Readable: true, Size: 64, Tag: `gorm:"column:fuint64"`}, + {Name: "FLOAT32", DBName: "ffloat32", BindNames: []string{"FLOAT32"}, DataType: schema.Float , Creatable: true, Updatable: true, Readable: true, Size: 32, Tag: `gorm:"column:ffloat32"`}, + {Name: "FLOAT64", DBName: "ffloat64", BindNames: []string{"FLOAT64"}, DataType: schema.Float , Creatable: true, Updatable: true, Readable: true, Size: 64, Tag: `gorm:"column:ffloat64"`}, + {Name: "BOOL", DBName: "fbool", BindNames: []string{"BOOL"}, DataType: schema.Bool , Creatable: true, Updatable: true, Readable: true, Tag: `gorm:"column:fbool"`}, + {Name: "STRING", DBName: "fstring", BindNames: []string{"STRING"}, DataType: schema.String, Creatable: true, Updatable: true, Readable: true, Tag: `gorm:"column:fstring"`}, + } + + for _, f := range fields { + checkSchemaField(t, alias, f, func(f *schema.Field) {}) + } +} \ No newline at end of file From adf8f70f06d905ce0ba6e5fb5dc7a1f7bb07ca23 Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Fri, 10 Dec 2021 17:50:19 +0800 Subject: [PATCH 4/4] Upgrade go.mod --- go.mod | 2 +- go.sum | 4 ++-- tests/go.mod | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 75662c80..57362745 100644 --- a/go.mod +++ b/go.mod @@ -4,5 +4,5 @@ go 1.14 require ( github.com/jinzhu/inflection v1.0.0 - github.com/jinzhu/now v1.1.3 + github.com/jinzhu/now v1.1.4 ) diff --git a/go.sum b/go.sum index c17a1ceb..50fbba2f 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,4 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI= -github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= diff --git a/tests/go.mod b/tests/go.mod index 6315c7f1..c3133f38 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -5,14 +5,14 @@ go 1.14 require ( github.com/google/uuid v1.3.0 github.com/jackc/pgx/v4 v4.14.1 // indirect - github.com/jinzhu/now v1.1.3 + github.com/jinzhu/now v1.1.4 github.com/lib/pq v1.10.4 - golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect - gorm.io/driver/mysql v1.2.0 + golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b // indirect + gorm.io/driver/mysql v1.2.1 gorm.io/driver/postgres v1.2.3 gorm.io/driver/sqlite v1.2.6 gorm.io/driver/sqlserver v1.2.1 - gorm.io/gorm v1.22.3 + gorm.io/gorm v1.22.4 ) replace gorm.io/gorm => ../