diff --git a/callbacks/update.go b/callbacks/update.go index 17de97f0..7e8c0f3e 100644 --- a/callbacks/update.go +++ b/callbacks/update.go @@ -164,7 +164,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) { case reflect.Struct: set = make([]clause.Assignment, 0, len(stmt.Schema.FieldsByDBName)) for _, field := range stmt.Schema.FieldsByDBName { - if !field.PrimaryKey || stmt.Dest != stmt.Model { + if !field.PrimaryKey || (!stmt.ReflectValue.CanAddr() || stmt.Dest != stmt.Model) { if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) { value, isZero := field.ValueOf(stmt.ReflectValue) if field.AutoUpdateTime > 0 { @@ -186,7 +186,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) { } } - if stmt.Dest != stmt.Model { + if !stmt.ReflectValue.CanAddr() || stmt.Dest != stmt.Model { reflectValue := reflect.Indirect(reflect.ValueOf(stmt.Model)) switch reflectValue.Kind() { case reflect.Slice, reflect.Array: diff --git a/dialects/mssql/mssql_test.go b/dialects/mssql/mssql_test.go deleted file mode 100644 index 49b3cd6a..00000000 --- a/dialects/mssql/mssql_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package mssql_test - -import ( - "fmt" - "os" - "testing" - - "github.com/jinzhu/gorm" - "github.com/jinzhu/gorm/dialects/mssql" - "github.com/jinzhu/gorm/tests" -) - -var ( - DB *gorm.DB - err error -) - -func init() { - dsn := "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm" - if os.Getenv("GORM_DSN") != "" { - dsn = os.Getenv("GORM_DSN") - } - - if DB, err = gorm.Open(mssql.Open(dsn), &gorm.Config{}); err != nil { - panic(fmt.Sprintf("failed to initialize database, got error %v", err)) - } -} - -func TestCURD(t *testing.T) { - tests.RunTestsSuit(t, DB) -} - -func TestMigrate(t *testing.T) { - tests.TestMigrate(t, DB) -} diff --git a/dialects/mysql/mysql_test.go b/dialects/mysql/mysql_test.go deleted file mode 100644 index cb3b240a..00000000 --- a/dialects/mysql/mysql_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package mysql_test - -import ( - "fmt" - "os" - "testing" - - "github.com/jinzhu/gorm" - "github.com/jinzhu/gorm/dialects/mysql" - "github.com/jinzhu/gorm/tests" -) - -var ( - DB *gorm.DB - err error -) - -func init() { - dsn := "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local" - if os.Getenv("GORM_DSN") != "" { - dsn = os.Getenv("GORM_DSN") - } - - if DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}); err != nil { - panic(fmt.Sprintf("failed to initialize database, got error %v", err)) - } -} - -func TestCURD(t *testing.T) { - tests.RunTestsSuit(t, DB) -} - -func TestMigrate(t *testing.T) { - tests.TestMigrate(t, DB) -} diff --git a/dialects/postgres/postgres_test.go b/dialects/postgres/postgres_test.go deleted file mode 100644 index 2185c19c..00000000 --- a/dialects/postgres/postgres_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package postgres_test - -import ( - "fmt" - "os" - "testing" - - "github.com/jinzhu/gorm" - "github.com/jinzhu/gorm/dialects/postgres" - "github.com/jinzhu/gorm/tests" -) - -var ( - DB *gorm.DB - err error -) - -func init() { - dsn := "user=gorm password=gorm DB.name=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai" - if os.Getenv("GORM_DSN") != "" { - dsn = os.Getenv("GORM_DSN") - } - - if DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}); err != nil { - panic(fmt.Sprintf("failed to initialize database, got error %v", err)) - } -} - -func TestCURD(t *testing.T) { - tests.RunTestsSuit(t, DB) -} - -func TestMigrate(t *testing.T) { - tests.TestMigrate(t, DB) -} diff --git a/dialects/sqlite/sqlite_test.go b/dialects/sqlite/sqlite_test.go deleted file mode 100644 index a42bc8ee..00000000 --- a/dialects/sqlite/sqlite_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package sqlite_test - -import ( - "fmt" - "os" - "path/filepath" - "testing" - - "github.com/jinzhu/gorm" - "github.com/jinzhu/gorm/dialects/sqlite" - "github.com/jinzhu/gorm/tests" -) - -var ( - DB *gorm.DB - err error -) - -func init() { - if DB, err = gorm.Open(sqlite.Open(filepath.Join(os.TempDir(), "gorm.db")), &gorm.Config{}); err != nil { - panic(fmt.Sprintf("failed to initialize database, got error %v", err)) - } -} - -func TestCURD(t *testing.T) { - tests.RunTestsSuit(t, DB) -} - -func TestMigrate(t *testing.T) { - tests.TestMigrate(t, DB) -} diff --git a/gorm.go b/gorm.go index 942024cf..6b2a6d75 100644 --- a/gorm.go +++ b/gorm.go @@ -189,3 +189,7 @@ func (db *DB) getInstance() *DB { return db } + +func Expr(expr string, args ...interface{}) clause.Expr { + return clause.Expr{SQL: expr, Vars: args} +} diff --git a/schema/field_test.go b/schema/field_test.go index c04149ff..aac46de9 100644 --- a/schema/field_test.go +++ b/schema/field_test.go @@ -19,7 +19,7 @@ func TestFieldValuerAndSetter(t *testing.T) { Model: gorm.Model{ ID: 10, CreatedAt: time.Now(), - DeletedAt: tests.Now(), + DeletedAt: gorm.DeletedAt{Time: time.Now(), Valid: true}, }, Name: "valuer_and_setter", Age: 18, @@ -46,7 +46,7 @@ func TestFieldValuerAndSetter(t *testing.T) { "name": "valuer_and_setter_2", "id": 2, "created_at": time.Now(), - "deleted_at": tests.Now(), + "deleted_at": time.Now(), "age": 20, "birthday": time.Now(), "active": false, @@ -89,7 +89,7 @@ func TestPointerFieldValuerAndSetter(t *testing.T) { Model: &gorm.Model{ ID: 10, CreatedAt: time.Now(), - DeletedAt: tests.Now(), + DeletedAt: gorm.DeletedAt{Time: time.Now(), Valid: true}, }, Name: &name, Age: &age, @@ -116,7 +116,7 @@ func TestPointerFieldValuerAndSetter(t *testing.T) { "name": "valuer_and_setter_2", "id": 2, "created_at": time.Now(), - "deleted_at": tests.Now(), + "deleted_at": time.Now(), "age": 20, "birthday": time.Now(), "active": false, diff --git a/tests/tests_all.sh b/tests/tests_all.sh index cd42e1e0..0c24a888 100755 --- a/tests/tests_all.sh +++ b/tests/tests_all.sh @@ -9,16 +9,8 @@ for dialect in "${dialects[@]}" ; do then if [ "$GORM_VERBOSE" = "" ] then - cd dialects/${dialect} - DEBUG=false GORM_DIALECT=${dialect} go test -race ./... - cd ../.. - DEBUG=false GORM_DIALECT=${dialect} go test -race ./... else - cd dialects/${dialect} - DEBUG=false GORM_DIALECT=${dialect} go test -race ./... - cd ../.. - DEBUG=false GORM_DIALECT=${dialect} go test -race -v ./... fi fi diff --git a/tests/update_test.go b/tests/update_test.go index 71da0751..cb61b40e 100644 --- a/tests/update_test.go +++ b/tests/update_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/jinzhu/gorm" . "github.com/jinzhu/gorm/tests" ) @@ -114,3 +115,47 @@ func TestUpdate(t *testing.T) { CheckUser(t, result4, *user) } } + +func TestUpdates(t *testing.T) { + var users = []*User{ + GetUser("updates_01", Config{}), + GetUser("updates_02", Config{}), + } + + DB.Create(&users) + lastUpdatedAt := users[0].UpdatedAt + + // update with map + DB.Model(users[0]).Updates(map[string]interface{}{"name": "updates_01_newname", "age": 100}) + if users[0].Name != "updates_01_newname" || users[0].Age != 100 { + t.Errorf("Record should be updated also with map") + } + + if users[0].UpdatedAt.UnixNano() == lastUpdatedAt.UnixNano() { + t.Errorf("User's updated at should be changed, but got %v, was %v", users[0].UpdatedAt.UnixNano(), lastUpdatedAt) + } + + // user2 should not be updated + var user1, user2 User + DB.First(&user1, users[0].ID) + DB.First(&user2, users[1].ID) + CheckUser(t, user1, *users[0]) + CheckUser(t, user2, *users[1]) + + // update with struct + DB.Table("users").Where("name in ?", []string{users[1].Name}).Updates(User{Name: "updates_02_newname"}) + + var user3 User + if DB.First(&user3, "name = ?", "updates_02_newname").RecordNotFound() { + t.Errorf("User2's name should be updated") + } + AssertEqual(t, user2.UpdatedAt, user3.UpdatedAt) + + // update with gorm exprs + DB.Model(&user3).Updates(map[string]interface{}{"age": gorm.Expr("age + ?", 100)}) + var user4 User + DB.First(&user4, user3.ID) + + user3.Age += 100 + AssertEqual(t, user4.UpdatedAt, user3.UpdatedAt) +}