7 "github.com/jinzhu/gorm"
10 func TestUpdate(t *testing.T) {
11 product1 := Product{Code: "product1code"}
12 product2 := Product{Code: "product2code"}
14 DB.Save(&product1).Save(&product2).Update("code", "product2newcode")
16 if product2.Code != "product2newcode" {
17 t.Errorf("Record should be updated")
20 DB.First(&product1, product1.Id)
21 DB.First(&product2, product2.Id)
22 updatedAt1 := product1.UpdatedAt
24 if DB.First(&Product{}, "code = ?", product1.Code).RecordNotFound() {
25 t.Errorf("Product1 should not be updated")
28 if !DB.First(&Product{}, "code = ?", "product2code").RecordNotFound() {
29 t.Errorf("Product2's code should be updated")
32 if DB.First(&Product{}, "code = ?", "product2newcode").RecordNotFound() {
33 t.Errorf("Product2's code should be updated")
36 DB.Table("products").Where("code in (?)", []string{"product1code"}).Update("code", "product1newcode")
39 DB.First(&product4, product1.Id)
40 if updatedAt1.Format(time.RFC3339Nano) != product4.UpdatedAt.Format(time.RFC3339Nano) {
41 t.Errorf("updatedAt should be updated if something changed")
44 if !DB.First(&Product{}, "code = 'product1code'").RecordNotFound() {
45 t.Errorf("Product1's code should be updated")
48 if DB.First(&Product{}, "code = 'product1newcode'").RecordNotFound() {
49 t.Errorf("Product should not be changed to 789")
52 if DB.Model(product2).Update("CreatedAt", time.Now().Add(time.Hour)).Error != nil {
53 t.Error("No error should raise when update with CamelCase")
56 if DB.Model(&product2).UpdateColumn("CreatedAt", time.Now().Add(time.Hour)).Error != nil {
57 t.Error("No error should raise when update_column with CamelCase")
60 var products []Product
62 if count := DB.Model(Product{}).Update("CreatedAt", time.Now().Add(2*time.Hour)).RowsAffected; count != int64(len(products)) {
63 t.Error("RowsAffected should be correct when do batch update")
66 DB.First(&product4, product4.Id)
67 updatedAt4 := product4.UpdatedAt
68 DB.Model(&product4).Update("price", gorm.Expr("price + ? - ?", 100, 50))
70 DB.First(&product5, product4.Id)
71 if product5.Price != product4.Price+100-50 {
72 t.Errorf("Update with expression")
74 if product4.UpdatedAt.Format(time.RFC3339Nano) == updatedAt4.Format(time.RFC3339Nano) {
75 t.Errorf("Update with expression should update UpdatedAt")
79 func TestUpdateWithNoStdPrimaryKeyAndDefaultValues(t *testing.T) {
80 animal := Animal{Name: "Ferdinand"}
82 updatedAt1 := animal.UpdatedAt
84 DB.Save(&animal).Update("name", "Francis")
86 if updatedAt1.Format(time.RFC3339Nano) == animal.UpdatedAt.Format(time.RFC3339Nano) {
87 t.Errorf("updatedAt should not be updated if nothing changed")
92 if count := DB.Model(Animal{}).Update("CreatedAt", time.Now().Add(2*time.Hour)).RowsAffected; count != int64(len(animals)) {
93 t.Error("RowsAffected should be correct when do batch update")
96 animal = Animal{From: "somewhere"} // No name fields, should be filled with the default value (galeone)
97 DB.Save(&animal).Update("From", "a nice place") // The name field shoul be untouched
98 DB.First(&animal, animal.Counter)
99 if animal.Name != "galeone" {
100 t.Errorf("Name fields shouldn't be changed if untouched, but got %v", animal.Name)
103 // When changing a field with a default value, the change must occur
104 animal.Name = "amazing horse"
106 DB.First(&animal, animal.Counter)
107 if animal.Name != "amazing horse" {
108 t.Errorf("Update a filed with a default value should occur. But got %v\n", animal.Name)
111 // When changing a field with a default value with blank value
114 DB.First(&animal, animal.Counter)
115 if animal.Name != "" {
116 t.Errorf("Update a filed to blank with a default value should occur. But got %v\n", animal.Name)
120 func TestUpdates(t *testing.T) {
121 product1 := Product{Code: "product1code", Price: 10}
122 product2 := Product{Code: "product2code", Price: 10}
123 DB.Save(&product1).Save(&product2)
124 DB.Model(&product1).Updates(map[string]interface{}{"code": "product1newcode", "price": 100})
125 if product1.Code != "product1newcode" || product1.Price != 100 {
126 t.Errorf("Record should be updated also with map")
129 DB.First(&product1, product1.Id)
130 DB.First(&product2, product2.Id)
131 updatedAt2 := product2.UpdatedAt
133 if DB.First(&Product{}, "code = ? and price = ?", product2.Code, product2.Price).RecordNotFound() {
134 t.Errorf("Product2 should not be updated")
137 if DB.First(&Product{}, "code = ?", "product1newcode").RecordNotFound() {
138 t.Errorf("Product1 should be updated")
141 DB.Table("products").Where("code in (?)", []string{"product2code"}).Updates(Product{Code: "product2newcode"})
142 if !DB.First(&Product{}, "code = 'product2code'").RecordNotFound() {
143 t.Errorf("Product2's code should be updated")
147 DB.First(&product4, product2.Id)
148 if updatedAt2.Format(time.RFC3339Nano) != product4.UpdatedAt.Format(time.RFC3339Nano) {
149 t.Errorf("updatedAt should be updated if something changed")
152 if DB.First(&Product{}, "code = ?", "product2newcode").RecordNotFound() {
153 t.Errorf("product2's code should be updated")
156 updatedAt4 := product4.UpdatedAt
157 DB.Model(&product4).Updates(map[string]interface{}{"price": gorm.Expr("price + ?", 100)})
159 DB.First(&product5, product4.Id)
160 if product5.Price != product4.Price+100 {
161 t.Errorf("Updates with expression")
163 // product4's UpdatedAt will be reset when updating
164 if product4.UpdatedAt.Format(time.RFC3339Nano) == updatedAt4.Format(time.RFC3339Nano) {
165 t.Errorf("Updates with expression should update UpdatedAt")
169 func TestUpdateColumn(t *testing.T) {
170 product1 := Product{Code: "product1code", Price: 10}
171 product2 := Product{Code: "product2code", Price: 20}
172 DB.Save(&product1).Save(&product2).UpdateColumn(map[string]interface{}{"code": "product2newcode", "price": 100})
173 if product2.Code != "product2newcode" || product2.Price != 100 {
174 t.Errorf("product 2 should be updated with update column")
178 DB.First(&product3, product1.Id)
179 if product3.Code != "product1code" || product3.Price != 10 {
180 t.Errorf("product 1 should not be updated")
183 DB.First(&product2, product2.Id)
184 updatedAt2 := product2.UpdatedAt
185 DB.Model(product2).UpdateColumn("code", "update_column_new")
187 DB.First(&product4, product2.Id)
188 if updatedAt2.Format(time.RFC3339Nano) != product4.UpdatedAt.Format(time.RFC3339Nano) {
189 t.Errorf("updatedAt should not be updated with update column")
192 DB.Model(&product4).UpdateColumn("price", gorm.Expr("price + 100 - 50"))
194 DB.First(&product5, product4.Id)
195 if product5.Price != product4.Price+100-50 {
196 t.Errorf("UpdateColumn with expression")
198 if product5.UpdatedAt.Format(time.RFC3339Nano) != product4.UpdatedAt.Format(time.RFC3339Nano) {
199 t.Errorf("UpdateColumn with expression should not update UpdatedAt")
203 func TestSelectWithUpdate(t *testing.T) {
204 user := getPreparedUser("select_user", "select_with_update")
208 DB.First(&reloadUser, user.Id)
209 reloadUser.Name = "new_name"
211 reloadUser.BillingAddress = Address{Address1: "New Billing Address"}
212 reloadUser.ShippingAddress = Address{Address1: "New ShippingAddress Address"}
213 reloadUser.CreditCard = CreditCard{Number: "987654321"}
214 reloadUser.Emails = []Email{
215 {Email: "new_user_1@example1.com"}, {Email: "new_user_2@example2.com"}, {Email: "new_user_3@example2.com"},
217 reloadUser.Company = Company{Name: "new company"}
219 DB.Select("Name", "BillingAddress", "CreditCard", "Company", "Emails").Save(&reloadUser)
222 DB.Preload("BillingAddress").Preload("ShippingAddress").
223 Preload("CreditCard").Preload("Emails").Preload("Company").First(&queryUser, user.Id)
225 if queryUser.Name == user.Name || queryUser.Age != user.Age {
226 t.Errorf("Should only update users with name column")
229 if queryUser.BillingAddressID.Int64 == user.BillingAddressID.Int64 ||
230 queryUser.ShippingAddressId != user.ShippingAddressId ||
231 queryUser.CreditCard.ID == user.CreditCard.ID ||
232 len(queryUser.Emails) == len(user.Emails) || queryUser.Company.Id == user.Company.Id {
233 t.Errorf("Should only update selected relationships")
237 func TestSelectWithUpdateWithMap(t *testing.T) {
238 user := getPreparedUser("select_user", "select_with_update_map")
241 updateValues := map[string]interface{}{
244 "BillingAddress": Address{Address1: "New Billing Address"},
245 "ShippingAddress": Address{Address1: "New ShippingAddress Address"},
246 "CreditCard": CreditCard{Number: "987654321"},
248 {Email: "new_user_1@example1.com"}, {Email: "new_user_2@example2.com"}, {Email: "new_user_3@example2.com"},
250 "Company": Company{Name: "new company"},
254 DB.First(&reloadUser, user.Id)
255 DB.Model(&reloadUser).Select("Name", "BillingAddress", "CreditCard", "Company", "Emails").Update(updateValues)
258 DB.Preload("BillingAddress").Preload("ShippingAddress").
259 Preload("CreditCard").Preload("Emails").Preload("Company").First(&queryUser, user.Id)
261 if queryUser.Name == user.Name || queryUser.Age != user.Age {
262 t.Errorf("Should only update users with name column")
265 if queryUser.BillingAddressID.Int64 == user.BillingAddressID.Int64 ||
266 queryUser.ShippingAddressId != user.ShippingAddressId ||
267 queryUser.CreditCard.ID == user.CreditCard.ID ||
268 len(queryUser.Emails) == len(user.Emails) || queryUser.Company.Id == user.Company.Id {
269 t.Errorf("Should only update selected relationships")
273 func TestOmitWithUpdate(t *testing.T) {
274 user := getPreparedUser("omit_user", "omit_with_update")
278 DB.First(&reloadUser, user.Id)
279 reloadUser.Name = "new_name"
281 reloadUser.BillingAddress = Address{Address1: "New Billing Address"}
282 reloadUser.ShippingAddress = Address{Address1: "New ShippingAddress Address"}
283 reloadUser.CreditCard = CreditCard{Number: "987654321"}
284 reloadUser.Emails = []Email{
285 {Email: "new_user_1@example1.com"}, {Email: "new_user_2@example2.com"}, {Email: "new_user_3@example2.com"},
287 reloadUser.Company = Company{Name: "new company"}
289 DB.Omit("Name", "BillingAddress", "CreditCard", "Company", "Emails").Save(&reloadUser)
292 DB.Preload("BillingAddress").Preload("ShippingAddress").
293 Preload("CreditCard").Preload("Emails").Preload("Company").First(&queryUser, user.Id)
295 if queryUser.Name != user.Name || queryUser.Age == user.Age {
296 t.Errorf("Should only update users with name column")
299 if queryUser.BillingAddressID.Int64 != user.BillingAddressID.Int64 ||
300 queryUser.ShippingAddressId == user.ShippingAddressId ||
301 queryUser.CreditCard.ID != user.CreditCard.ID ||
302 len(queryUser.Emails) != len(user.Emails) || queryUser.Company.Id != user.Company.Id {
303 t.Errorf("Should only update relationships that not omitted")
307 func TestOmitWithUpdateWithMap(t *testing.T) {
308 user := getPreparedUser("select_user", "select_with_update_map")
311 updateValues := map[string]interface{}{
314 "BillingAddress": Address{Address1: "New Billing Address"},
315 "ShippingAddress": Address{Address1: "New ShippingAddress Address"},
316 "CreditCard": CreditCard{Number: "987654321"},
318 {Email: "new_user_1@example1.com"}, {Email: "new_user_2@example2.com"}, {Email: "new_user_3@example2.com"},
320 "Company": Company{Name: "new company"},
324 DB.First(&reloadUser, user.Id)
325 DB.Model(&reloadUser).Omit("Name", "BillingAddress", "CreditCard", "Company", "Emails").Update(updateValues)
328 DB.Preload("BillingAddress").Preload("ShippingAddress").
329 Preload("CreditCard").Preload("Emails").Preload("Company").First(&queryUser, user.Id)
331 if queryUser.Name != user.Name || queryUser.Age == user.Age {
332 t.Errorf("Should only update users with name column")
335 if queryUser.BillingAddressID.Int64 != user.BillingAddressID.Int64 ||
336 queryUser.ShippingAddressId == user.ShippingAddressId ||
337 queryUser.CreditCard.ID != user.CreditCard.ID ||
338 len(queryUser.Emails) != len(user.Emails) || queryUser.Company.Id != user.Company.Id {
339 t.Errorf("Should only update relationships not omitted")
343 func TestSelectWithUpdateColumn(t *testing.T) {
344 user := getPreparedUser("select_user", "select_with_update_map")
347 updateValues := map[string]interface{}{"Name": "new_name", "Age": 50}
350 DB.First(&reloadUser, user.Id)
351 DB.Model(&reloadUser).Select("Name").UpdateColumn(updateValues)
354 DB.First(&queryUser, user.Id)
356 if queryUser.Name == user.Name || queryUser.Age != user.Age {
357 t.Errorf("Should only update users with name column")
361 func TestOmitWithUpdateColumn(t *testing.T) {
362 user := getPreparedUser("select_user", "select_with_update_map")
365 updateValues := map[string]interface{}{"Name": "new_name", "Age": 50}
368 DB.First(&reloadUser, user.Id)
369 DB.Model(&reloadUser).Omit("Name").UpdateColumn(updateValues)
372 DB.First(&queryUser, user.Id)
374 if queryUser.Name != user.Name || queryUser.Age == user.Age {
375 t.Errorf("Should omit name column when update user")
379 func TestUpdateColumnsSkipsAssociations(t *testing.T) {
380 user := getPreparedUser("update_columns_user", "special_role")
382 address1 := "first street"
383 user.BillingAddress = Address{Address1: address1}
386 // Update a single field of the user and verify that the changed address is not stored.
388 user.BillingAddress.Address1 = "second street"
389 db := DB.Model(user).UpdateColumns(User{Age: newAge})
390 if db.RowsAffected != 1 {
391 t.Errorf("Expected RowsAffected=1 but instead RowsAffected=%v", DB.RowsAffected)
394 // Verify that Age now=`newAge`.
395 freshUser := &User{Id: user.Id}
397 if freshUser.Age != newAge {
398 t.Errorf("Expected freshly queried user to have Age=%v but instead found Age=%v", newAge, freshUser.Age)
401 // Verify that user's BillingAddress.Address1 is not changed and is still "first street".
402 DB.First(&freshUser.BillingAddress, freshUser.BillingAddressID)
403 if freshUser.BillingAddress.Address1 != address1 {
404 t.Errorf("Expected user's BillingAddress.Address1=%s to remain unchanged after UpdateColumns invocation, but BillingAddress.Address1=%s", address1, freshUser.BillingAddress.Address1)
408 func TestUpdatesWithBlankValues(t *testing.T) {
409 product := Product{Code: "product1", Price: 10}
412 DB.Model(&Product{Id: product.Id}).Updates(&Product{Price: 100})
415 DB.First(&product1, product.Id)
417 if product1.Code != "product1" || product1.Price != 100 {
418 t.Errorf("product's code should not be updated")
422 type ElementWithIgnoredField struct {
425 IgnoredField int64 `sql:"-"`
428 func (e ElementWithIgnoredField) TableName() string {
429 return "element_with_ignored_field"
432 func TestUpdatesTableWithIgnoredValues(t *testing.T) {
433 elem := ElementWithIgnoredField{Value: "foo", IgnoredField: 10}
436 DB.Table(elem.TableName()).
437 Where("id = ?", elem.Id).
438 // DB.Model(&ElementWithIgnoredField{Id: elem.Id}).
439 Updates(&ElementWithIgnoredField{Value: "bar", IgnoredField: 100})
441 var elem1 ElementWithIgnoredField
442 err := DB.First(&elem1, elem.Id).Error
444 t.Errorf("error getting an element from database: %s", err.Error())
447 if elem1.IgnoredField != 0 {
448 t.Errorf("element's ignored field should not be updated")
452 func TestUpdateDecodeVirtualAttributes(t *testing.T) {
460 DB.Model(&user).Updates(User{Name: "jinzhu2", IgnoreMe: 100})
462 if user.IgnoreMe != 100 {
463 t.Errorf("should decode virtual attributes to struct, so it could be used in callbacks")