diff --git a/callbacks/update.go b/callbacks/update.go index f56aa22c..17de97f0 100644 --- a/callbacks/update.go +++ b/callbacks/update.go @@ -119,7 +119,9 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) { } case reflect.Struct: assignValue = func(field *schema.Field, value interface{}) { - field.Set(reflectModelValue, value) + if reflectModelValue.CanAddr() { + field.Set(reflectModelValue, value) + } } default: assignValue = func(field *schema.Field, value interface{}) { diff --git a/schema/field.go b/schema/field.go index f4fbad95..d435c928 100644 --- a/schema/field.go +++ b/schema/field.go @@ -231,6 +231,8 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field { case reflect.String: field.DataType = String if field.HasDefaultValue { + field.DefaultValue = strings.Trim(field.DefaultValue, "'") + field.DefaultValue = strings.Trim(field.DefaultValue, "\"") field.DefaultValueInterface = field.DefaultValue } case reflect.Struct: diff --git a/tests/non_std_test.go b/tests/non_std_test.go new file mode 100644 index 00000000..b8a278fe --- /dev/null +++ b/tests/non_std_test.go @@ -0,0 +1,63 @@ +package tests_test + +import ( + "testing" + "time" + + . "github.com/jinzhu/gorm/tests" +) + +type Animal struct { + Counter uint64 `gorm:"primary_key:yes"` + Name string `gorm:"DEFAULT:'galeone'"` + From string //test reserved sql keyword as field name + Age time.Time `gorm:"DEFAULT:current_timestamp"` + unexported string // unexported value + CreatedAt time.Time + UpdatedAt time.Time +} + +func init() { + DB.Migrator().DropTable(&Animal{}) + DB.AutoMigrate(&Animal{}) +} + +func TestNonStdPrimaryKeyAndDefaultValues(t *testing.T) { + animal := Animal{Name: "Ferdinand"} + DB.Save(&animal) + updatedAt1 := animal.UpdatedAt + + DB.Save(&animal).Update("name", "Francis") + if updatedAt1.Format(time.RFC3339Nano) == animal.UpdatedAt.Format(time.RFC3339Nano) { + t.Errorf("UpdatedAt should be updated") + } + + var animals []Animal + DB.Find(&animals) + if count := DB.Model(Animal{}).Update("CreatedAt", time.Now().Add(2*time.Hour)).RowsAffected; count != int64(len(animals)) { + t.Error("RowsAffected should be correct when do batch update") + } + + animal = Animal{From: "somewhere"} // No name fields, should be filled with the default value (galeone) + DB.Save(&animal).Update("From", "a nice place") // The name field shoul be untouched + DB.First(&animal, animal.Counter) + if animal.Name != "galeone" { + t.Errorf("Name fields shouldn't be changed if untouched, but got %v", animal.Name) + } + + // When changing a field with a default value, the change must occur + animal.Name = "amazing horse" + DB.Save(&animal) + DB.First(&animal, animal.Counter) + if animal.Name != "amazing horse" { + t.Errorf("Update a filed with a default value should occur. But got %v\n", animal.Name) + } + + // When changing a field with a default value with blank value + animal.Name = "" + DB.Save(&animal) + DB.First(&animal, animal.Counter) + if animal.Name != "" { + t.Errorf("Update a filed to blank with a default value should occur. But got %v\n", animal.Name) + } +} diff --git a/tests/update_belongs_to_test.go b/tests/update_belongs_to_test.go new file mode 100644 index 00000000..267fd4e8 --- /dev/null +++ b/tests/update_belongs_to_test.go @@ -0,0 +1,25 @@ +package tests_test + +import ( + "testing" + + . "github.com/jinzhu/gorm/tests" +) + +func TestUpdateBelongsTo(t *testing.T) { + var user = *GetUser("update-belongs-to", Config{}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + user.Company = Company{Name: "company-belongs-to-association"} + user.Manager = &User{Name: "manager-belongs-to-association"} + if err := DB.Save(&user).Error; err != nil { + t.Fatalf("errors happened when update: %v", err) + } + + var user2 User + DB.Preload("Company").Preload("Manager").Find(&user2, "id = ?", user.ID) + CheckUser(t, user2, user) +} diff --git a/tests/update_has_many_test.go b/tests/update_has_many_test.go new file mode 100644 index 00000000..e723b940 --- /dev/null +++ b/tests/update_has_many_test.go @@ -0,0 +1,41 @@ +package tests_test + +import ( + "testing" + + . "github.com/jinzhu/gorm/tests" +) + +func TestUpdateHasManyAssociations(t *testing.T) { + var user = *GetUser("update-has-many", Config{}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + user.Pets = []*Pet{{Name: "pet1"}, {Name: "pet2"}} + if err := DB.Save(&user).Error; err != nil { + t.Fatalf("errors happened when update: %v", err) + } + + var user2 User + DB.Preload("Pets").Find(&user2, "id = ?", user.ID) + CheckUser(t, user2, user) + + t.Run("Polymorphic", func(t *testing.T) { + var user = *GetUser("update-has-many", Config{}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + user.Toys = []Toy{{Name: "toy1"}, {Name: "toy2"}} + if err := DB.Save(&user).Error; err != nil { + t.Fatalf("errors happened when update: %v", err) + } + + var user2 User + DB.Preload("Toys").Find(&user2, "id = ?", user.ID) + CheckUser(t, user2, user) + }) +} diff --git a/tests/update_has_one_test.go b/tests/update_has_one_test.go new file mode 100644 index 00000000..4c5036cf --- /dev/null +++ b/tests/update_has_one_test.go @@ -0,0 +1,43 @@ +package tests_test + +import ( + "testing" + + . "github.com/jinzhu/gorm/tests" +) + +func TestUpdateHasOne(t *testing.T) { + var user = *GetUser("update-has-one", Config{}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + user.Account = Account{Number: "account-has-one-association"} + + if err := DB.Save(&user).Error; err != nil { + t.Fatalf("errors happened when update: %v", err) + } + + var user2 User + DB.Preload("Account").Find(&user2, "id = ?", user.ID) + CheckUser(t, user2, user) + + t.Run("Polymorphic", func(t *testing.T) { + var pet = Pet{Name: "create"} + + if err := DB.Create(&pet).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + pet.Toy = Toy{Name: "Update-HasOneAssociation-Polymorphic"} + + if err := DB.Save(&pet).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + var pet2 Pet + DB.Preload("Toy").Find(&pet2, "id = ?", pet.ID) + CheckPet(t, pet2, pet) + }) +} diff --git a/tests/update_many2many_test.go b/tests/update_many2many_test.go new file mode 100644 index 00000000..bc7a60af --- /dev/null +++ b/tests/update_many2many_test.go @@ -0,0 +1,29 @@ +package tests_test + +import ( + "testing" + + . "github.com/jinzhu/gorm/tests" +) + +func TestUpdateMany2ManyAssociations(t *testing.T) { + var user = *GetUser("update-many2many", Config{}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + user.Languages = []Language{{Code: "zh-CN", Name: "Chinese"}, {Code: "en", Name: "English"}} + for _, lang := range user.Languages { + DB.Create(&lang) + } + user.Friends = []*User{{Name: "friend-1"}, {Name: "friend-2"}} + + if err := DB.Save(&user).Error; err != nil { + t.Fatalf("errors happened when update: %v", err) + } + + var user2 User + DB.Preload("Languages").Preload("Friends").Find(&user2, "id = ?", user.ID) + CheckUser(t, user2, user) +} diff --git a/tests/update_test.go b/tests/update_test.go index 10835f97..71da0751 100644 --- a/tests/update_test.go +++ b/tests/update_test.go @@ -18,7 +18,7 @@ func TestUpdate(t *testing.T) { lastUpdatedAt time.Time ) - checkUpdatedTime := func(name string, n time.Time) { + checkUpdatedAtChanged := func(name string, n time.Time) { if n.UnixNano() == lastUpdatedAt.UnixNano() { t.Errorf("%v: user's updated at should be changed, but got %v, was %v", name, n, lastUpdatedAt) } @@ -52,7 +52,7 @@ func TestUpdate(t *testing.T) { } else if user.Age != 10 { t.Errorf("Age should equals to 10, but got %v", user.Age) } - checkUpdatedTime("Update", user.UpdatedAt) + checkUpdatedAtChanged("Update", user.UpdatedAt) checkOtherData("Update") var result User @@ -70,7 +70,7 @@ func TestUpdate(t *testing.T) { } else if user.Active != true { t.Errorf("Active should be true, but got %v", user.Active) } - checkUpdatedTime("Updates with map", user.UpdatedAt) + checkUpdatedAtChanged("Updates with map", user.UpdatedAt) checkOtherData("Updates with map") var result2 User @@ -85,7 +85,7 @@ func TestUpdate(t *testing.T) { } else if user.Age != 2 { t.Errorf("Age should equals to 2, but got %v", user.Age) } - checkUpdatedTime("Updates with struct", user.UpdatedAt) + checkUpdatedAtChanged("Updates with struct", user.UpdatedAt) checkOtherData("Updates with struct") var result3 User @@ -104,7 +104,7 @@ func TestUpdate(t *testing.T) { } else if user.Active != false { t.Errorf("Active should equals to false, but got %v", user.Active) } - checkUpdatedTime("Save", user.UpdatedAt) + checkUpdatedAtChanged("Save", user.UpdatedAt) checkOtherData("Save") var result4 User @@ -114,113 +114,3 @@ func TestUpdate(t *testing.T) { CheckUser(t, result4, *user) } } - -func TestUpdateBelongsTo(t *testing.T) { - var user = *GetUser("update-belongs-to", Config{}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - user.Company = Company{Name: "company-belongs-to-association"} - user.Manager = &User{Name: "manager-belongs-to-association"} - if err := DB.Save(&user).Error; err != nil { - t.Fatalf("errors happened when update: %v", err) - } - - var user2 User - DB.Preload("Company").Preload("Manager").Find(&user2, "id = ?", user.ID) - CheckUser(t, user2, user) -} - -func TestUpdateHasOne(t *testing.T) { - var user = *GetUser("update-has-one", Config{}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - user.Account = Account{Number: "account-has-one-association"} - - if err := DB.Save(&user).Error; err != nil { - t.Fatalf("errors happened when update: %v", err) - } - - var user2 User - DB.Preload("Account").Find(&user2, "id = ?", user.ID) - CheckUser(t, user2, user) - - t.Run("Polymorphic", func(t *testing.T) { - var pet = Pet{Name: "create"} - - if err := DB.Create(&pet).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - pet.Toy = Toy{Name: "Update-HasOneAssociation-Polymorphic"} - - if err := DB.Save(&pet).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - var pet2 Pet - DB.Preload("Toy").Find(&pet2, "id = ?", pet.ID) - CheckPet(t, pet2, pet) - }) -} - -func TestUpdateHasManyAssociations(t *testing.T) { - var user = *GetUser("update-has-many", Config{}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - user.Pets = []*Pet{{Name: "pet1"}, {Name: "pet2"}} - if err := DB.Save(&user).Error; err != nil { - t.Fatalf("errors happened when update: %v", err) - } - - var user2 User - DB.Preload("Pets").Find(&user2, "id = ?", user.ID) - CheckUser(t, user2, user) - - t.Run("Polymorphic", func(t *testing.T) { - var user = *GetUser("update-has-many", Config{}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - user.Toys = []Toy{{Name: "toy1"}, {Name: "toy2"}} - if err := DB.Save(&user).Error; err != nil { - t.Fatalf("errors happened when update: %v", err) - } - - var user2 User - DB.Preload("Toys").Find(&user2, "id = ?", user.ID) - CheckUser(t, user2, user) - }) -} - -func TestUpdateMany2ManyAssociations(t *testing.T) { - var user = *GetUser("update-many2many", Config{}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - user.Languages = []Language{{Code: "zh-CN", Name: "Chinese"}, {Code: "en", Name: "English"}} - for _, lang := range user.Languages { - DB.Create(&lang) - } - user.Friends = []*User{{Name: "friend-1"}, {Name: "friend-2"}} - - if err := DB.Save(&user).Error; err != nil { - t.Fatalf("errors happened when update: %v", err) - } - - var user2 User - DB.Preload("Languages").Preload("Friends").Find(&user2, "id = ?", user.ID) - CheckUser(t, user2, user) -}