update_test.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. package gorm_test
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/jinzhu/gorm"
  6. )
  7. func TestUpdate(t *testing.T) {
  8. product1 := Product{Code: "product1code"}
  9. product2 := Product{Code: "product2code"}
  10. DB.Save(&product1).Save(&product2).Update("code", "product2newcode")
  11. if product2.Code != "product2newcode" {
  12. t.Errorf("Record should be updated")
  13. }
  14. DB.First(&product1, product1.Id)
  15. DB.First(&product2, product2.Id)
  16. updatedAt1 := product1.UpdatedAt
  17. if DB.First(&Product{}, "code = ?", product1.Code).RecordNotFound() {
  18. t.Errorf("Product1 should not be updated")
  19. }
  20. if !DB.First(&Product{}, "code = ?", "product2code").RecordNotFound() {
  21. t.Errorf("Product2's code should be updated")
  22. }
  23. if DB.First(&Product{}, "code = ?", "product2newcode").RecordNotFound() {
  24. t.Errorf("Product2's code should be updated")
  25. }
  26. DB.Table("products").Where("code in (?)", []string{"product1code"}).Update("code", "product1newcode")
  27. var product4 Product
  28. DB.First(&product4, product1.Id)
  29. if updatedAt1.Format(time.RFC3339Nano) != product4.UpdatedAt.Format(time.RFC3339Nano) {
  30. t.Errorf("updatedAt should be updated if something changed")
  31. }
  32. if !DB.First(&Product{}, "code = 'product1code'").RecordNotFound() {
  33. t.Errorf("Product1's code should be updated")
  34. }
  35. if DB.First(&Product{}, "code = 'product1newcode'").RecordNotFound() {
  36. t.Errorf("Product should not be changed to 789")
  37. }
  38. if DB.Model(product2).Update("CreatedAt", time.Now().Add(time.Hour)).Error != nil {
  39. t.Error("No error should raise when update with CamelCase")
  40. }
  41. if DB.Model(&product2).UpdateColumn("CreatedAt", time.Now().Add(time.Hour)).Error != nil {
  42. t.Error("No error should raise when update_column with CamelCase")
  43. }
  44. var products []Product
  45. DB.Find(&products)
  46. if count := DB.Model(Product{}).Update("CreatedAt", time.Now().Add(2*time.Hour)).RowsAffected; count != int64(len(products)) {
  47. t.Error("RowsAffected should be correct when do batch update")
  48. }
  49. DB.First(&product4, product4.Id)
  50. updatedAt4 := product4.UpdatedAt
  51. DB.Model(&product4).Update("price", gorm.Expr("price + ? - ?", 100, 50))
  52. var product5 Product
  53. DB.First(&product5, product4.Id)
  54. if product5.Price != product4.Price+100-50 {
  55. t.Errorf("Update with expression")
  56. }
  57. if product4.UpdatedAt.Format(time.RFC3339Nano) == updatedAt4.Format(time.RFC3339Nano) {
  58. t.Errorf("Update with expression should update UpdatedAt")
  59. }
  60. }
  61. func TestUpdateWithNoStdPrimaryKeyAndDefaultValues(t *testing.T) {
  62. animal := Animal{Name: "Ferdinand"}
  63. DB.Save(&animal)
  64. updatedAt1 := animal.UpdatedAt
  65. DB.Save(&animal).Update("name", "Francis")
  66. if updatedAt1.Format(time.RFC3339Nano) == animal.UpdatedAt.Format(time.RFC3339Nano) {
  67. t.Errorf("updatedAt should not be updated if nothing changed")
  68. }
  69. var animals []Animal
  70. DB.Find(&animals)
  71. if count := DB.Model(Animal{}).Update("CreatedAt", time.Now().Add(2*time.Hour)).RowsAffected; count != int64(len(animals)) {
  72. t.Error("RowsAffected should be correct when do batch update")
  73. }
  74. animal = Animal{From: "somewhere"} // No name fields, should be filled with the default value (galeone)
  75. DB.Save(&animal).Update("From", "a nice place") // The name field shoul be untouched
  76. DB.First(&animal, animal.Counter)
  77. if animal.Name != "galeone" {
  78. t.Errorf("Name fields shouldn't be changed if untouched, but got %v", animal.Name)
  79. }
  80. // When changing a field with a default value, the change must occur
  81. animal.Name = "amazing horse"
  82. DB.Save(&animal)
  83. DB.First(&animal, animal.Counter)
  84. if animal.Name != "amazing horse" {
  85. t.Errorf("Update a filed with a default value should occur. But got %v\n", animal.Name)
  86. }
  87. // When changing a field with a default value with blank value
  88. animal.Name = ""
  89. DB.Save(&animal)
  90. DB.First(&animal, animal.Counter)
  91. if animal.Name != "" {
  92. t.Errorf("Update a filed to blank with a default value should occur. But got %v\n", animal.Name)
  93. }
  94. }
  95. func TestUpdates(t *testing.T) {
  96. product1 := Product{Code: "product1code", Price: 10}
  97. product2 := Product{Code: "product2code", Price: 10}
  98. DB.Save(&product1).Save(&product2)
  99. DB.Model(&product1).Updates(map[string]interface{}{"code": "product1newcode", "price": 100})
  100. if product1.Code != "product1newcode" || product1.Price != 100 {
  101. t.Errorf("Record should be updated also with map")
  102. }
  103. DB.First(&product1, product1.Id)
  104. DB.First(&product2, product2.Id)
  105. updatedAt2 := product2.UpdatedAt
  106. if DB.First(&Product{}, "code = ? and price = ?", product2.Code, product2.Price).RecordNotFound() {
  107. t.Errorf("Product2 should not be updated")
  108. }
  109. if DB.First(&Product{}, "code = ?", "product1newcode").RecordNotFound() {
  110. t.Errorf("Product1 should be updated")
  111. }
  112. DB.Table("products").Where("code in (?)", []string{"product2code"}).Updates(Product{Code: "product2newcode"})
  113. if !DB.First(&Product{}, "code = 'product2code'").RecordNotFound() {
  114. t.Errorf("Product2's code should be updated")
  115. }
  116. var product4 Product
  117. DB.First(&product4, product2.Id)
  118. if updatedAt2.Format(time.RFC3339Nano) != product4.UpdatedAt.Format(time.RFC3339Nano) {
  119. t.Errorf("updatedAt should be updated if something changed")
  120. }
  121. if DB.First(&Product{}, "code = ?", "product2newcode").RecordNotFound() {
  122. t.Errorf("product2's code should be updated")
  123. }
  124. updatedAt4 := product4.UpdatedAt
  125. DB.Model(&product4).Updates(map[string]interface{}{"price": gorm.Expr("price + ?", 100)})
  126. var product5 Product
  127. DB.First(&product5, product4.Id)
  128. if product5.Price != product4.Price+100 {
  129. t.Errorf("Updates with expression")
  130. }
  131. // product4's UpdatedAt will be reset when updating
  132. if product4.UpdatedAt.Format(time.RFC3339Nano) == updatedAt4.Format(time.RFC3339Nano) {
  133. t.Errorf("Updates with expression should update UpdatedAt")
  134. }
  135. }
  136. func TestUpdateColumn(t *testing.T) {
  137. product1 := Product{Code: "product1code", Price: 10}
  138. product2 := Product{Code: "product2code", Price: 20}
  139. DB.Save(&product1).Save(&product2).UpdateColumn(map[string]interface{}{"code": "product2newcode", "price": 100})
  140. if product2.Code != "product2newcode" || product2.Price != 100 {
  141. t.Errorf("product 2 should be updated with update column")
  142. }
  143. var product3 Product
  144. DB.First(&product3, product1.Id)
  145. if product3.Code != "product1code" || product3.Price != 10 {
  146. t.Errorf("product 1 should not be updated")
  147. }
  148. DB.First(&product2, product2.Id)
  149. updatedAt2 := product2.UpdatedAt
  150. DB.Model(product2).UpdateColumn("code", "update_column_new")
  151. var product4 Product
  152. DB.First(&product4, product2.Id)
  153. if updatedAt2.Format(time.RFC3339Nano) != product4.UpdatedAt.Format(time.RFC3339Nano) {
  154. t.Errorf("updatedAt should not be updated with update column")
  155. }
  156. DB.Model(&product4).UpdateColumn("price", gorm.Expr("price + 100 - 50"))
  157. var product5 Product
  158. DB.First(&product5, product4.Id)
  159. if product5.Price != product4.Price+100-50 {
  160. t.Errorf("UpdateColumn with expression")
  161. }
  162. if product5.UpdatedAt.Format(time.RFC3339Nano) != product4.UpdatedAt.Format(time.RFC3339Nano) {
  163. t.Errorf("UpdateColumn with expression should not update UpdatedAt")
  164. }
  165. }
  166. func TestSelectWithUpdate(t *testing.T) {
  167. user := getPreparedUser("select_user", "select_with_update")
  168. DB.Create(user)
  169. var reloadUser User
  170. DB.First(&reloadUser, user.Id)
  171. reloadUser.Name = "new_name"
  172. reloadUser.Age = 50
  173. reloadUser.BillingAddress = Address{Address1: "New Billing Address"}
  174. reloadUser.ShippingAddress = Address{Address1: "New ShippingAddress Address"}
  175. reloadUser.CreditCard = CreditCard{Number: "987654321"}
  176. reloadUser.Emails = []Email{
  177. {Email: "new_user_1@example1.com"}, {Email: "new_user_2@example2.com"}, {Email: "new_user_3@example2.com"},
  178. }
  179. reloadUser.Company = Company{Name: "new company"}
  180. DB.Select("Name", "BillingAddress", "CreditCard", "Company", "Emails").Save(&reloadUser)
  181. var queryUser User
  182. DB.Preload("BillingAddress").Preload("ShippingAddress").
  183. Preload("CreditCard").Preload("Emails").Preload("Company").First(&queryUser, user.Id)
  184. if queryUser.Name == user.Name || queryUser.Age != user.Age {
  185. t.Errorf("Should only update users with name column")
  186. }
  187. if queryUser.BillingAddressID.Int64 == user.BillingAddressID.Int64 ||
  188. queryUser.ShippingAddressId != user.ShippingAddressId ||
  189. queryUser.CreditCard.ID == user.CreditCard.ID ||
  190. len(queryUser.Emails) == len(user.Emails) || queryUser.Company.Id == user.Company.Id {
  191. t.Errorf("Should only update selected relationships")
  192. }
  193. }
  194. func TestSelectWithUpdateWithMap(t *testing.T) {
  195. user := getPreparedUser("select_user", "select_with_update_map")
  196. DB.Create(user)
  197. updateValues := map[string]interface{}{
  198. "Name": "new_name",
  199. "Age": 50,
  200. "BillingAddress": Address{Address1: "New Billing Address"},
  201. "ShippingAddress": Address{Address1: "New ShippingAddress Address"},
  202. "CreditCard": CreditCard{Number: "987654321"},
  203. "Emails": []Email{
  204. {Email: "new_user_1@example1.com"}, {Email: "new_user_2@example2.com"}, {Email: "new_user_3@example2.com"},
  205. },
  206. "Company": Company{Name: "new company"},
  207. }
  208. var reloadUser User
  209. DB.First(&reloadUser, user.Id)
  210. DB.Model(&reloadUser).Select("Name", "BillingAddress", "CreditCard", "Company", "Emails").Update(updateValues)
  211. var queryUser User
  212. DB.Preload("BillingAddress").Preload("ShippingAddress").
  213. Preload("CreditCard").Preload("Emails").Preload("Company").First(&queryUser, user.Id)
  214. if queryUser.Name == user.Name || queryUser.Age != user.Age {
  215. t.Errorf("Should only update users with name column")
  216. }
  217. if queryUser.BillingAddressID.Int64 == user.BillingAddressID.Int64 ||
  218. queryUser.ShippingAddressId != user.ShippingAddressId ||
  219. queryUser.CreditCard.ID == user.CreditCard.ID ||
  220. len(queryUser.Emails) == len(user.Emails) || queryUser.Company.Id == user.Company.Id {
  221. t.Errorf("Should only update selected relationships")
  222. }
  223. }
  224. func TestOmitWithUpdate(t *testing.T) {
  225. user := getPreparedUser("omit_user", "omit_with_update")
  226. DB.Create(user)
  227. var reloadUser User
  228. DB.First(&reloadUser, user.Id)
  229. reloadUser.Name = "new_name"
  230. reloadUser.Age = 50
  231. reloadUser.BillingAddress = Address{Address1: "New Billing Address"}
  232. reloadUser.ShippingAddress = Address{Address1: "New ShippingAddress Address"}
  233. reloadUser.CreditCard = CreditCard{Number: "987654321"}
  234. reloadUser.Emails = []Email{
  235. {Email: "new_user_1@example1.com"}, {Email: "new_user_2@example2.com"}, {Email: "new_user_3@example2.com"},
  236. }
  237. reloadUser.Company = Company{Name: "new company"}
  238. DB.Omit("Name", "BillingAddress", "CreditCard", "Company", "Emails").Save(&reloadUser)
  239. var queryUser User
  240. DB.Preload("BillingAddress").Preload("ShippingAddress").
  241. Preload("CreditCard").Preload("Emails").Preload("Company").First(&queryUser, user.Id)
  242. if queryUser.Name != user.Name || queryUser.Age == user.Age {
  243. t.Errorf("Should only update users with name column")
  244. }
  245. if queryUser.BillingAddressID.Int64 != user.BillingAddressID.Int64 ||
  246. queryUser.ShippingAddressId == user.ShippingAddressId ||
  247. queryUser.CreditCard.ID != user.CreditCard.ID ||
  248. len(queryUser.Emails) != len(user.Emails) || queryUser.Company.Id != user.Company.Id {
  249. t.Errorf("Should only update relationships that not omitted")
  250. }
  251. }
  252. func TestOmitWithUpdateWithMap(t *testing.T) {
  253. user := getPreparedUser("select_user", "select_with_update_map")
  254. DB.Create(user)
  255. updateValues := map[string]interface{}{
  256. "Name": "new_name",
  257. "Age": 50,
  258. "BillingAddress": Address{Address1: "New Billing Address"},
  259. "ShippingAddress": Address{Address1: "New ShippingAddress Address"},
  260. "CreditCard": CreditCard{Number: "987654321"},
  261. "Emails": []Email{
  262. {Email: "new_user_1@example1.com"}, {Email: "new_user_2@example2.com"}, {Email: "new_user_3@example2.com"},
  263. },
  264. "Company": Company{Name: "new company"},
  265. }
  266. var reloadUser User
  267. DB.First(&reloadUser, user.Id)
  268. DB.Model(&reloadUser).Omit("Name", "BillingAddress", "CreditCard", "Company", "Emails").Update(updateValues)
  269. var queryUser User
  270. DB.Preload("BillingAddress").Preload("ShippingAddress").
  271. Preload("CreditCard").Preload("Emails").Preload("Company").First(&queryUser, user.Id)
  272. if queryUser.Name != user.Name || queryUser.Age == user.Age {
  273. t.Errorf("Should only update users with name column")
  274. }
  275. if queryUser.BillingAddressID.Int64 != user.BillingAddressID.Int64 ||
  276. queryUser.ShippingAddressId == user.ShippingAddressId ||
  277. queryUser.CreditCard.ID != user.CreditCard.ID ||
  278. len(queryUser.Emails) != len(user.Emails) || queryUser.Company.Id != user.Company.Id {
  279. t.Errorf("Should only update relationships not omitted")
  280. }
  281. }
  282. func TestSelectWithUpdateColumn(t *testing.T) {
  283. user := getPreparedUser("select_user", "select_with_update_map")
  284. DB.Create(user)
  285. updateValues := map[string]interface{}{"Name": "new_name", "Age": 50}
  286. var reloadUser User
  287. DB.First(&reloadUser, user.Id)
  288. DB.Model(&reloadUser).Select("Name").UpdateColumn(updateValues)
  289. var queryUser User
  290. DB.First(&queryUser, user.Id)
  291. if queryUser.Name == user.Name || queryUser.Age != user.Age {
  292. t.Errorf("Should only update users with name column")
  293. }
  294. }
  295. func TestOmitWithUpdateColumn(t *testing.T) {
  296. user := getPreparedUser("select_user", "select_with_update_map")
  297. DB.Create(user)
  298. updateValues := map[string]interface{}{"Name": "new_name", "Age": 50}
  299. var reloadUser User
  300. DB.First(&reloadUser, user.Id)
  301. DB.Model(&reloadUser).Omit("Name").UpdateColumn(updateValues)
  302. var queryUser User
  303. DB.First(&queryUser, user.Id)
  304. if queryUser.Name != user.Name || queryUser.Age == user.Age {
  305. t.Errorf("Should omit name column when update user")
  306. }
  307. }
  308. func TestUpdateColumnsSkipsAssociations(t *testing.T) {
  309. user := getPreparedUser("update_columns_user", "special_role")
  310. user.Age = 99
  311. address1 := "first street"
  312. user.BillingAddress = Address{Address1: address1}
  313. DB.Save(user)
  314. // Update a single field of the user and verify that the changed address is not stored.
  315. newAge := int64(100)
  316. user.BillingAddress.Address1 = "second street"
  317. db := DB.Model(user).UpdateColumns(User{Age: newAge})
  318. if db.RowsAffected != 1 {
  319. t.Errorf("Expected RowsAffected=1 but instead RowsAffected=%v", DB.RowsAffected)
  320. }
  321. // Verify that Age now=`newAge`.
  322. freshUser := &User{Id: user.Id}
  323. DB.First(freshUser)
  324. if freshUser.Age != newAge {
  325. t.Errorf("Expected freshly queried user to have Age=%v but instead found Age=%v", newAge, freshUser.Age)
  326. }
  327. // Verify that user's BillingAddress.Address1 is not changed and is still "first street".
  328. DB.First(&freshUser.BillingAddress, freshUser.BillingAddressID)
  329. if freshUser.BillingAddress.Address1 != address1 {
  330. t.Errorf("Expected user's BillingAddress.Address1=%s to remain unchanged after UpdateColumns invocation, but BillingAddress.Address1=%s", address1, freshUser.BillingAddress.Address1)
  331. }
  332. }
  333. func TestUpdatesWithBlankValues(t *testing.T) {
  334. product := Product{Code: "product1", Price: 10}
  335. DB.Save(&product)
  336. DB.Model(&Product{Id: product.Id}).Updates(&Product{Price: 100})
  337. var product1 Product
  338. DB.First(&product1, product.Id)
  339. if product1.Code != "product1" || product1.Price != 100 {
  340. t.Errorf("product's code should not be updated")
  341. }
  342. }
  343. type ElementWithIgnoredField struct {
  344. Id int64
  345. Value string
  346. IgnoredField int64 `sql:"-"`
  347. }
  348. func (e ElementWithIgnoredField) TableName() string {
  349. return "element_with_ignored_field"
  350. }
  351. func TestUpdatesTableWithIgnoredValues(t *testing.T) {
  352. elem := ElementWithIgnoredField{Value: "foo", IgnoredField: 10}
  353. DB.Save(&elem)
  354. DB.Table(elem.TableName()).
  355. Where("id = ?", elem.Id).
  356. // DB.Model(&ElementWithIgnoredField{Id: elem.Id}).
  357. Updates(&ElementWithIgnoredField{Value: "bar", IgnoredField: 100})
  358. var elem1 ElementWithIgnoredField
  359. err := DB.First(&elem1, elem.Id).Error
  360. if err != nil {
  361. t.Errorf("error getting an element from database: %s", err.Error())
  362. }
  363. if elem1.IgnoredField != 0 {
  364. t.Errorf("element's ignored field should not be updated")
  365. }
  366. }
  367. func TestUpdateDecodeVirtualAttributes(t *testing.T) {
  368. var user = User{
  369. Name: "jinzhu",
  370. IgnoreMe: 88,
  371. }
  372. DB.Save(&user)
  373. DB.Model(&user).Updates(User{Name: "jinzhu2", IgnoreMe: 100})
  374. if user.IgnoreMe != 100 {
  375. t.Errorf("should decode virtual attributes to struct, so it could be used in callbacks")
  376. }
  377. }