association_test.go 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
  1. package gorm_test
  2. import (
  3. "fmt"
  4. "os"
  5. "reflect"
  6. "sort"
  7. "testing"
  8. "github.com/jinzhu/gorm"
  9. )
  10. func TestBelongsTo(t *testing.T) {
  11. post := Post{
  12. Title: "post belongs to",
  13. Body: "body belongs to",
  14. Category: Category{Name: "Category 1"},
  15. MainCategory: Category{Name: "Main Category 1"},
  16. }
  17. if err := DB.Save(&post).Error; err != nil {
  18. t.Error("Got errors when save post", err)
  19. }
  20. if post.Category.ID == 0 || post.MainCategory.ID == 0 {
  21. t.Errorf("Category's primary key should be updated")
  22. }
  23. if post.CategoryId.Int64 == 0 || post.MainCategoryId == 0 {
  24. t.Errorf("post's foreign key should be updated")
  25. }
  26. // Query
  27. var category1 Category
  28. DB.Model(&post).Association("Category").Find(&category1)
  29. if category1.Name != "Category 1" {
  30. t.Errorf("Query belongs to relations with Association")
  31. }
  32. var mainCategory1 Category
  33. DB.Model(&post).Association("MainCategory").Find(&mainCategory1)
  34. if mainCategory1.Name != "Main Category 1" {
  35. t.Errorf("Query belongs to relations with Association")
  36. }
  37. var category11 Category
  38. DB.Model(&post).Related(&category11)
  39. if category11.Name != "Category 1" {
  40. t.Errorf("Query belongs to relations with Related")
  41. }
  42. if DB.Model(&post).Association("Category").Count() != 1 {
  43. t.Errorf("Post's category count should be 1")
  44. }
  45. if DB.Model(&post).Association("MainCategory").Count() != 1 {
  46. t.Errorf("Post's main category count should be 1")
  47. }
  48. // Append
  49. var category2 = Category{
  50. Name: "Category 2",
  51. }
  52. DB.Model(&post).Association("Category").Append(&category2)
  53. if category2.ID == 0 {
  54. t.Errorf("Category should has ID when created with Append")
  55. }
  56. var category21 Category
  57. DB.Model(&post).Related(&category21)
  58. if category21.Name != "Category 2" {
  59. t.Errorf("Category should be updated with Append")
  60. }
  61. if DB.Model(&post).Association("Category").Count() != 1 {
  62. t.Errorf("Post's category count should be 1")
  63. }
  64. // Replace
  65. var category3 = Category{
  66. Name: "Category 3",
  67. }
  68. DB.Model(&post).Association("Category").Replace(&category3)
  69. if category3.ID == 0 {
  70. t.Errorf("Category should has ID when created with Replace")
  71. }
  72. var category31 Category
  73. DB.Model(&post).Related(&category31)
  74. if category31.Name != "Category 3" {
  75. t.Errorf("Category should be updated with Replace")
  76. }
  77. if DB.Model(&post).Association("Category").Count() != 1 {
  78. t.Errorf("Post's category count should be 1")
  79. }
  80. // Delete
  81. DB.Model(&post).Association("Category").Delete(&category2)
  82. if DB.Model(&post).Related(&Category{}).RecordNotFound() {
  83. t.Errorf("Should not delete any category when Delete a unrelated Category")
  84. }
  85. if post.Category.Name == "" {
  86. t.Errorf("Post's category should not be reseted when Delete a unrelated Category")
  87. }
  88. DB.Model(&post).Association("Category").Delete(&category3)
  89. if post.Category.Name != "" {
  90. t.Errorf("Post's category should be reseted after Delete")
  91. }
  92. var category41 Category
  93. DB.Model(&post).Related(&category41)
  94. if category41.Name != "" {
  95. t.Errorf("Category should be deleted with Delete")
  96. }
  97. if count := DB.Model(&post).Association("Category").Count(); count != 0 {
  98. t.Errorf("Post's category count should be 0 after Delete, but got %v", count)
  99. }
  100. // Clear
  101. DB.Model(&post).Association("Category").Append(&Category{
  102. Name: "Category 2",
  103. })
  104. if DB.Model(&post).Related(&Category{}).RecordNotFound() {
  105. t.Errorf("Should find category after append")
  106. }
  107. if post.Category.Name == "" {
  108. t.Errorf("Post's category should has value after Append")
  109. }
  110. DB.Model(&post).Association("Category").Clear()
  111. if post.Category.Name != "" {
  112. t.Errorf("Post's category should be cleared after Clear")
  113. }
  114. if !DB.Model(&post).Related(&Category{}).RecordNotFound() {
  115. t.Errorf("Should not find any category after Clear")
  116. }
  117. if count := DB.Model(&post).Association("Category").Count(); count != 0 {
  118. t.Errorf("Post's category count should be 0 after Clear, but got %v", count)
  119. }
  120. // Check Association mode with soft delete
  121. category6 := Category{
  122. Name: "Category 6",
  123. }
  124. DB.Model(&post).Association("Category").Append(&category6)
  125. if count := DB.Model(&post).Association("Category").Count(); count != 1 {
  126. t.Errorf("Post's category count should be 1 after Append, but got %v", count)
  127. }
  128. DB.Delete(&category6)
  129. if count := DB.Model(&post).Association("Category").Count(); count != 0 {
  130. t.Errorf("Post's category count should be 0 after the category has been deleted, but got %v", count)
  131. }
  132. if err := DB.Model(&post).Association("Category").Find(&Category{}).Error; err == nil {
  133. t.Errorf("Post's category is not findable after Delete")
  134. }
  135. if count := DB.Unscoped().Model(&post).Association("Category").Count(); count != 1 {
  136. t.Errorf("Post's category count should be 1 when query with Unscoped, but got %v", count)
  137. }
  138. if err := DB.Unscoped().Model(&post).Association("Category").Find(&Category{}).Error; err != nil {
  139. t.Errorf("Post's category should be findable when query with Unscoped, got %v", err)
  140. }
  141. }
  142. func TestBelongsToOverrideForeignKey1(t *testing.T) {
  143. type Profile struct {
  144. gorm.Model
  145. Name string
  146. }
  147. type User struct {
  148. gorm.Model
  149. Profile Profile `gorm:"ForeignKey:ProfileRefer"`
  150. ProfileRefer int
  151. }
  152. if relation, ok := DB.NewScope(&User{}).FieldByName("Profile"); ok {
  153. if relation.Relationship.Kind != "belongs_to" ||
  154. !reflect.DeepEqual(relation.Relationship.ForeignFieldNames, []string{"ProfileRefer"}) ||
  155. !reflect.DeepEqual(relation.Relationship.AssociationForeignFieldNames, []string{"ID"}) {
  156. t.Errorf("Override belongs to foreign key with tag")
  157. }
  158. }
  159. }
  160. func TestBelongsToOverrideForeignKey2(t *testing.T) {
  161. type Profile struct {
  162. gorm.Model
  163. Refer string
  164. Name string
  165. }
  166. type User struct {
  167. gorm.Model
  168. Profile Profile `gorm:"ForeignKey:ProfileID;AssociationForeignKey:Refer"`
  169. ProfileID int
  170. }
  171. if relation, ok := DB.NewScope(&User{}).FieldByName("Profile"); ok {
  172. if relation.Relationship.Kind != "belongs_to" ||
  173. !reflect.DeepEqual(relation.Relationship.ForeignFieldNames, []string{"ProfileID"}) ||
  174. !reflect.DeepEqual(relation.Relationship.AssociationForeignFieldNames, []string{"Refer"}) {
  175. t.Errorf("Override belongs to foreign key with tag")
  176. }
  177. }
  178. }
  179. func TestHasOne(t *testing.T) {
  180. user := User{
  181. Name: "has one",
  182. CreditCard: CreditCard{Number: "411111111111"},
  183. }
  184. if err := DB.Save(&user).Error; err != nil {
  185. t.Error("Got errors when save user", err.Error())
  186. }
  187. if user.CreditCard.UserId.Int64 == 0 {
  188. t.Errorf("CreditCard's foreign key should be updated")
  189. }
  190. // Query
  191. var creditCard1 CreditCard
  192. DB.Model(&user).Related(&creditCard1)
  193. if creditCard1.Number != "411111111111" {
  194. t.Errorf("Query has one relations with Related")
  195. }
  196. var creditCard11 CreditCard
  197. DB.Model(&user).Association("CreditCard").Find(&creditCard11)
  198. if creditCard11.Number != "411111111111" {
  199. t.Errorf("Query has one relations with Related")
  200. }
  201. if DB.Model(&user).Association("CreditCard").Count() != 1 {
  202. t.Errorf("User's credit card count should be 1")
  203. }
  204. // Append
  205. var creditcard2 = CreditCard{
  206. Number: "411111111112",
  207. }
  208. DB.Model(&user).Association("CreditCard").Append(&creditcard2)
  209. if creditcard2.ID == 0 {
  210. t.Errorf("Creditcard should has ID when created with Append")
  211. }
  212. var creditcard21 CreditCard
  213. DB.Model(&user).Related(&creditcard21)
  214. if creditcard21.Number != "411111111112" {
  215. t.Errorf("CreditCard should be updated with Append")
  216. }
  217. if DB.Model(&user).Association("CreditCard").Count() != 1 {
  218. t.Errorf("User's credit card count should be 1")
  219. }
  220. // Replace
  221. var creditcard3 = CreditCard{
  222. Number: "411111111113",
  223. }
  224. DB.Model(&user).Association("CreditCard").Replace(&creditcard3)
  225. if creditcard3.ID == 0 {
  226. t.Errorf("Creditcard should has ID when created with Replace")
  227. }
  228. var creditcard31 CreditCard
  229. DB.Model(&user).Related(&creditcard31)
  230. if creditcard31.Number != "411111111113" {
  231. t.Errorf("CreditCard should be updated with Replace")
  232. }
  233. if DB.Model(&user).Association("CreditCard").Count() != 1 {
  234. t.Errorf("User's credit card count should be 1")
  235. }
  236. // Delete
  237. DB.Model(&user).Association("CreditCard").Delete(&creditcard2)
  238. var creditcard4 CreditCard
  239. DB.Model(&user).Related(&creditcard4)
  240. if creditcard4.Number != "411111111113" {
  241. t.Errorf("Should not delete credit card when Delete a unrelated CreditCard")
  242. }
  243. if DB.Model(&user).Association("CreditCard").Count() != 1 {
  244. t.Errorf("User's credit card count should be 1")
  245. }
  246. DB.Model(&user).Association("CreditCard").Delete(&creditcard3)
  247. if !DB.Model(&user).Related(&CreditCard{}).RecordNotFound() {
  248. t.Errorf("Should delete credit card with Delete")
  249. }
  250. if DB.Model(&user).Association("CreditCard").Count() != 0 {
  251. t.Errorf("User's credit card count should be 0 after Delete")
  252. }
  253. // Clear
  254. var creditcard5 = CreditCard{
  255. Number: "411111111115",
  256. }
  257. DB.Model(&user).Association("CreditCard").Append(&creditcard5)
  258. if DB.Model(&user).Related(&CreditCard{}).RecordNotFound() {
  259. t.Errorf("Should added credit card with Append")
  260. }
  261. if DB.Model(&user).Association("CreditCard").Count() != 1 {
  262. t.Errorf("User's credit card count should be 1")
  263. }
  264. DB.Model(&user).Association("CreditCard").Clear()
  265. if !DB.Model(&user).Related(&CreditCard{}).RecordNotFound() {
  266. t.Errorf("Credit card should be deleted with Clear")
  267. }
  268. if DB.Model(&user).Association("CreditCard").Count() != 0 {
  269. t.Errorf("User's credit card count should be 0 after Clear")
  270. }
  271. // Check Association mode with soft delete
  272. var creditcard6 = CreditCard{
  273. Number: "411111111116",
  274. }
  275. DB.Model(&user).Association("CreditCard").Append(&creditcard6)
  276. if count := DB.Model(&user).Association("CreditCard").Count(); count != 1 {
  277. t.Errorf("User's credit card count should be 1 after Append, but got %v", count)
  278. }
  279. DB.Delete(&creditcard6)
  280. if count := DB.Model(&user).Association("CreditCard").Count(); count != 0 {
  281. t.Errorf("User's credit card count should be 0 after credit card deleted, but got %v", count)
  282. }
  283. if err := DB.Model(&user).Association("CreditCard").Find(&CreditCard{}).Error; err == nil {
  284. t.Errorf("User's creditcard is not findable after Delete")
  285. }
  286. if count := DB.Unscoped().Model(&user).Association("CreditCard").Count(); count != 1 {
  287. t.Errorf("User's credit card count should be 1 when query with Unscoped, but got %v", count)
  288. }
  289. if err := DB.Unscoped().Model(&user).Association("CreditCard").Find(&CreditCard{}).Error; err != nil {
  290. t.Errorf("User's creditcard should be findable when query with Unscoped, got %v", err)
  291. }
  292. }
  293. func TestHasOneOverrideForeignKey1(t *testing.T) {
  294. type Profile struct {
  295. gorm.Model
  296. Name string
  297. UserRefer uint
  298. }
  299. type User struct {
  300. gorm.Model
  301. Profile Profile `gorm:"ForeignKey:UserRefer"`
  302. }
  303. if relation, ok := DB.NewScope(&User{}).FieldByName("Profile"); ok {
  304. if relation.Relationship.Kind != "has_one" ||
  305. !reflect.DeepEqual(relation.Relationship.ForeignFieldNames, []string{"UserRefer"}) ||
  306. !reflect.DeepEqual(relation.Relationship.AssociationForeignFieldNames, []string{"ID"}) {
  307. t.Errorf("Override belongs to foreign key with tag")
  308. }
  309. }
  310. }
  311. func TestHasOneOverrideForeignKey2(t *testing.T) {
  312. type Profile struct {
  313. gorm.Model
  314. Name string
  315. UserID uint
  316. }
  317. type User struct {
  318. gorm.Model
  319. Refer string
  320. Profile Profile `gorm:"ForeignKey:UserID;AssociationForeignKey:Refer"`
  321. }
  322. if relation, ok := DB.NewScope(&User{}).FieldByName("Profile"); ok {
  323. if relation.Relationship.Kind != "has_one" ||
  324. !reflect.DeepEqual(relation.Relationship.ForeignFieldNames, []string{"UserID"}) ||
  325. !reflect.DeepEqual(relation.Relationship.AssociationForeignFieldNames, []string{"Refer"}) {
  326. t.Errorf("Override belongs to foreign key with tag")
  327. }
  328. }
  329. }
  330. func TestHasMany(t *testing.T) {
  331. post := Post{
  332. Title: "post has many",
  333. Body: "body has many",
  334. Comments: []*Comment{{Content: "Comment 1"}, {Content: "Comment 2"}},
  335. }
  336. if err := DB.Save(&post).Error; err != nil {
  337. t.Error("Got errors when save post", err)
  338. }
  339. for _, comment := range post.Comments {
  340. if comment.PostId == 0 {
  341. t.Errorf("comment's PostID should be updated")
  342. }
  343. }
  344. var compareComments = func(comments []Comment, contents []string) bool {
  345. var commentContents []string
  346. for _, comment := range comments {
  347. commentContents = append(commentContents, comment.Content)
  348. }
  349. sort.Strings(commentContents)
  350. sort.Strings(contents)
  351. return reflect.DeepEqual(commentContents, contents)
  352. }
  353. // Query
  354. if DB.First(&Comment{}, "content = ?", "Comment 1").Error != nil {
  355. t.Errorf("Comment 1 should be saved")
  356. }
  357. var comments1 []Comment
  358. DB.Model(&post).Association("Comments").Find(&comments1)
  359. if !compareComments(comments1, []string{"Comment 1", "Comment 2"}) {
  360. t.Errorf("Query has many relations with Association")
  361. }
  362. var comments11 []Comment
  363. DB.Model(&post).Related(&comments11)
  364. if !compareComments(comments11, []string{"Comment 1", "Comment 2"}) {
  365. t.Errorf("Query has many relations with Related")
  366. }
  367. if DB.Model(&post).Association("Comments").Count() != 2 {
  368. t.Errorf("Post's comments count should be 2")
  369. }
  370. // Append
  371. DB.Model(&post).Association("Comments").Append(&Comment{Content: "Comment 3"})
  372. var comments2 []Comment
  373. DB.Model(&post).Related(&comments2)
  374. if !compareComments(comments2, []string{"Comment 1", "Comment 2", "Comment 3"}) {
  375. t.Errorf("Append new record to has many relations")
  376. }
  377. if DB.Model(&post).Association("Comments").Count() != 3 {
  378. t.Errorf("Post's comments count should be 3 after Append")
  379. }
  380. // Delete
  381. DB.Model(&post).Association("Comments").Delete(comments11)
  382. var comments3 []Comment
  383. DB.Model(&post).Related(&comments3)
  384. if !compareComments(comments3, []string{"Comment 3"}) {
  385. t.Errorf("Delete an existing resource for has many relations")
  386. }
  387. if DB.Model(&post).Association("Comments").Count() != 1 {
  388. t.Errorf("Post's comments count should be 1 after Delete 2")
  389. }
  390. // Replace
  391. DB.Model(&Post{Id: 999}).Association("Comments").Replace()
  392. var comments4 []Comment
  393. DB.Model(&post).Related(&comments4)
  394. if len(comments4) == 0 {
  395. t.Errorf("Replace for other resource should not clear all comments")
  396. }
  397. DB.Model(&post).Association("Comments").Replace(&Comment{Content: "Comment 4"}, &Comment{Content: "Comment 5"})
  398. var comments41 []Comment
  399. DB.Model(&post).Related(&comments41)
  400. if !compareComments(comments41, []string{"Comment 4", "Comment 5"}) {
  401. t.Errorf("Replace has many relations")
  402. }
  403. // Clear
  404. DB.Model(&Post{Id: 999}).Association("Comments").Clear()
  405. var comments5 []Comment
  406. DB.Model(&post).Related(&comments5)
  407. if len(comments5) == 0 {
  408. t.Errorf("Clear should not clear all comments")
  409. }
  410. DB.Model(&post).Association("Comments").Clear()
  411. var comments51 []Comment
  412. DB.Model(&post).Related(&comments51)
  413. if len(comments51) != 0 {
  414. t.Errorf("Clear has many relations")
  415. }
  416. // Check Association mode with soft delete
  417. var comment6 = Comment{
  418. Content: "comment 6",
  419. }
  420. DB.Model(&post).Association("Comments").Append(&comment6)
  421. if count := DB.Model(&post).Association("Comments").Count(); count != 1 {
  422. t.Errorf("post's comments count should be 1 after Append, but got %v", count)
  423. }
  424. DB.Delete(&comment6)
  425. if count := DB.Model(&post).Association("Comments").Count(); count != 0 {
  426. t.Errorf("post's comments count should be 0 after comment been deleted, but got %v", count)
  427. }
  428. var comments6 []Comment
  429. if DB.Model(&post).Association("Comments").Find(&comments6); len(comments6) != 0 {
  430. t.Errorf("post's comments count should be 0 when find with Find, but got %v", len(comments6))
  431. }
  432. if count := DB.Unscoped().Model(&post).Association("Comments").Count(); count != 1 {
  433. t.Errorf("post's comments count should be 1 when query with Unscoped, but got %v", count)
  434. }
  435. var comments61 []Comment
  436. if DB.Unscoped().Model(&post).Association("Comments").Find(&comments61); len(comments61) != 1 {
  437. t.Errorf("post's comments count should be 1 when query with Unscoped, but got %v", len(comments61))
  438. }
  439. }
  440. func TestHasManyOverrideForeignKey1(t *testing.T) {
  441. type Profile struct {
  442. gorm.Model
  443. Name string
  444. UserRefer uint
  445. }
  446. type User struct {
  447. gorm.Model
  448. Profile []Profile `gorm:"ForeignKey:UserRefer"`
  449. }
  450. if relation, ok := DB.NewScope(&User{}).FieldByName("Profile"); ok {
  451. if relation.Relationship.Kind != "has_many" ||
  452. !reflect.DeepEqual(relation.Relationship.ForeignFieldNames, []string{"UserRefer"}) ||
  453. !reflect.DeepEqual(relation.Relationship.AssociationForeignFieldNames, []string{"ID"}) {
  454. t.Errorf("Override belongs to foreign key with tag")
  455. }
  456. }
  457. }
  458. func TestHasManyOverrideForeignKey2(t *testing.T) {
  459. type Profile struct {
  460. gorm.Model
  461. Name string
  462. UserID uint
  463. }
  464. type User struct {
  465. gorm.Model
  466. Refer string
  467. Profile []Profile `gorm:"ForeignKey:UserID;AssociationForeignKey:Refer"`
  468. }
  469. if relation, ok := DB.NewScope(&User{}).FieldByName("Profile"); ok {
  470. if relation.Relationship.Kind != "has_many" ||
  471. !reflect.DeepEqual(relation.Relationship.ForeignFieldNames, []string{"UserID"}) ||
  472. !reflect.DeepEqual(relation.Relationship.AssociationForeignFieldNames, []string{"Refer"}) {
  473. t.Errorf("Override belongs to foreign key with tag")
  474. }
  475. }
  476. }
  477. func TestManyToMany(t *testing.T) {
  478. DB.Raw("delete from languages")
  479. var languages = []Language{{Name: "ZH"}, {Name: "EN"}}
  480. user := User{Name: "Many2Many", Languages: languages}
  481. DB.Save(&user)
  482. // Query
  483. var newLanguages []Language
  484. DB.Model(&user).Related(&newLanguages, "Languages")
  485. if len(newLanguages) != len([]string{"ZH", "EN"}) {
  486. t.Errorf("Query many to many relations")
  487. }
  488. DB.Model(&user).Association("Languages").Find(&newLanguages)
  489. if len(newLanguages) != len([]string{"ZH", "EN"}) {
  490. t.Errorf("Should be able to find many to many relations")
  491. }
  492. if DB.Model(&user).Association("Languages").Count() != len([]string{"ZH", "EN"}) {
  493. t.Errorf("Count should return correct result")
  494. }
  495. // Append
  496. DB.Model(&user).Association("Languages").Append(&Language{Name: "DE"})
  497. if DB.Where("name = ?", "DE").First(&Language{}).RecordNotFound() {
  498. t.Errorf("New record should be saved when append")
  499. }
  500. languageA := Language{Name: "AA"}
  501. DB.Save(&languageA)
  502. DB.Model(&User{Id: user.Id}).Association("Languages").Append(&languageA)
  503. languageC := Language{Name: "CC"}
  504. DB.Save(&languageC)
  505. DB.Model(&user).Association("Languages").Append(&[]Language{{Name: "BB"}, languageC})
  506. DB.Model(&User{Id: user.Id}).Association("Languages").Append(&[]Language{{Name: "DD"}, {Name: "EE"}})
  507. totalLanguages := []string{"ZH", "EN", "DE", "AA", "BB", "CC", "DD", "EE"}
  508. if DB.Model(&user).Association("Languages").Count() != len(totalLanguages) {
  509. t.Errorf("All appended languages should be saved")
  510. }
  511. // Delete
  512. user.Languages = []Language{}
  513. DB.Model(&user).Association("Languages").Find(&user.Languages)
  514. var language Language
  515. DB.Where("name = ?", "EE").First(&language)
  516. DB.Model(&user).Association("Languages").Delete(language, &language)
  517. if DB.Model(&user).Association("Languages").Count() != len(totalLanguages)-1 || len(user.Languages) != len(totalLanguages)-1 {
  518. t.Errorf("Relations should be deleted with Delete")
  519. }
  520. if DB.Where("name = ?", "EE").First(&Language{}).RecordNotFound() {
  521. t.Errorf("Language EE should not be deleted")
  522. }
  523. DB.Where("name IN (?)", []string{"CC", "DD"}).Find(&languages)
  524. user2 := User{Name: "Many2Many_User2", Languages: languages}
  525. DB.Save(&user2)
  526. DB.Model(&user).Association("Languages").Delete(languages, &languages)
  527. if DB.Model(&user).Association("Languages").Count() != len(totalLanguages)-3 || len(user.Languages) != len(totalLanguages)-3 {
  528. t.Errorf("Relations should be deleted with Delete")
  529. }
  530. if DB.Model(&user2).Association("Languages").Count() == 0 {
  531. t.Errorf("Other user's relations should not be deleted")
  532. }
  533. // Replace
  534. var languageB Language
  535. DB.Where("name = ?", "BB").First(&languageB)
  536. DB.Model(&user).Association("Languages").Replace(languageB)
  537. if len(user.Languages) != 1 || DB.Model(&user).Association("Languages").Count() != 1 {
  538. t.Errorf("Relations should be replaced")
  539. }
  540. DB.Model(&user).Association("Languages").Replace()
  541. if len(user.Languages) != 0 || DB.Model(&user).Association("Languages").Count() != 0 {
  542. t.Errorf("Relations should be replaced with empty")
  543. }
  544. DB.Model(&user).Association("Languages").Replace(&[]Language{{Name: "FF"}, {Name: "JJ"}})
  545. if len(user.Languages) != 2 || DB.Model(&user).Association("Languages").Count() != len([]string{"FF", "JJ"}) {
  546. t.Errorf("Relations should be replaced")
  547. }
  548. // Clear
  549. DB.Model(&user).Association("Languages").Clear()
  550. if len(user.Languages) != 0 || DB.Model(&user).Association("Languages").Count() != 0 {
  551. t.Errorf("Relations should be cleared")
  552. }
  553. // Check Association mode with soft delete
  554. var language6 = Language{
  555. Name: "language 6",
  556. }
  557. DB.Model(&user).Association("Languages").Append(&language6)
  558. if count := DB.Model(&user).Association("Languages").Count(); count != 1 {
  559. t.Errorf("user's languages count should be 1 after Append, but got %v", count)
  560. }
  561. DB.Delete(&language6)
  562. if count := DB.Model(&user).Association("Languages").Count(); count != 0 {
  563. t.Errorf("user's languages count should be 0 after language been deleted, but got %v", count)
  564. }
  565. var languages6 []Language
  566. if DB.Model(&user).Association("Languages").Find(&languages6); len(languages6) != 0 {
  567. t.Errorf("user's languages count should be 0 when find with Find, but got %v", len(languages6))
  568. }
  569. if count := DB.Unscoped().Model(&user).Association("Languages").Count(); count != 1 {
  570. t.Errorf("user's languages count should be 1 when query with Unscoped, but got %v", count)
  571. }
  572. var languages61 []Language
  573. if DB.Unscoped().Model(&user).Association("Languages").Find(&languages61); len(languages61) != 1 {
  574. t.Errorf("user's languages count should be 1 when query with Unscoped, but got %v", len(languages61))
  575. }
  576. }
  577. func TestRelated(t *testing.T) {
  578. user := User{
  579. Name: "jinzhu",
  580. BillingAddress: Address{Address1: "Billing Address - Address 1"},
  581. ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
  582. Emails: []Email{{Email: "jinzhu@example.com"}, {Email: "jinzhu-2@example@example.com"}},
  583. CreditCard: CreditCard{Number: "1234567890"},
  584. Company: Company{Name: "company1"},
  585. }
  586. if err := DB.Save(&user).Error; err != nil {
  587. t.Errorf("No error should happen when saving user")
  588. }
  589. if user.CreditCard.ID == 0 {
  590. t.Errorf("After user save, credit card should have id")
  591. }
  592. if user.BillingAddress.ID == 0 {
  593. t.Errorf("After user save, billing address should have id")
  594. }
  595. if user.Emails[0].Id == 0 {
  596. t.Errorf("After user save, billing address should have id")
  597. }
  598. var emails []Email
  599. DB.Model(&user).Related(&emails)
  600. if len(emails) != 2 {
  601. t.Errorf("Should have two emails")
  602. }
  603. var emails2 []Email
  604. DB.Model(&user).Where("email = ?", "jinzhu@example.com").Related(&emails2)
  605. if len(emails2) != 1 {
  606. t.Errorf("Should have two emails")
  607. }
  608. var emails3 []*Email
  609. DB.Model(&user).Related(&emails3)
  610. if len(emails3) != 2 {
  611. t.Errorf("Should have two emails")
  612. }
  613. var user1 User
  614. DB.Model(&user).Related(&user1.Emails)
  615. if len(user1.Emails) != 2 {
  616. t.Errorf("Should have only one email match related condition")
  617. }
  618. var address1 Address
  619. DB.Model(&user).Related(&address1, "BillingAddressId")
  620. if address1.Address1 != "Billing Address - Address 1" {
  621. t.Errorf("Should get billing address from user correctly")
  622. }
  623. user1 = User{}
  624. DB.Model(&address1).Related(&user1, "BillingAddressId")
  625. if DB.NewRecord(user1) {
  626. t.Errorf("Should get user from address correctly")
  627. }
  628. var user2 User
  629. DB.Model(&emails[0]).Related(&user2)
  630. if user2.Id != user.Id || user2.Name != user.Name {
  631. t.Errorf("Should get user from email correctly")
  632. }
  633. var creditcard CreditCard
  634. var user3 User
  635. DB.First(&creditcard, "number = ?", "1234567890")
  636. DB.Model(&creditcard).Related(&user3)
  637. if user3.Id != user.Id || user3.Name != user.Name {
  638. t.Errorf("Should get user from credit card correctly")
  639. }
  640. if !DB.Model(&CreditCard{}).Related(&User{}).RecordNotFound() {
  641. t.Errorf("RecordNotFound for Related")
  642. }
  643. var company Company
  644. if DB.Model(&user).Related(&company, "Company").RecordNotFound() || company.Name != "company1" {
  645. t.Errorf("RecordNotFound for Related")
  646. }
  647. }
  648. func TestForeignKey(t *testing.T) {
  649. for _, structField := range DB.NewScope(&User{}).GetStructFields() {
  650. for _, foreignKey := range []string{"BillingAddressID", "ShippingAddressId", "CompanyID"} {
  651. if structField.Name == foreignKey && !structField.IsForeignKey {
  652. t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
  653. }
  654. }
  655. }
  656. for _, structField := range DB.NewScope(&Email{}).GetStructFields() {
  657. for _, foreignKey := range []string{"UserId"} {
  658. if structField.Name == foreignKey && !structField.IsForeignKey {
  659. t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
  660. }
  661. }
  662. }
  663. for _, structField := range DB.NewScope(&Post{}).GetStructFields() {
  664. for _, foreignKey := range []string{"CategoryId", "MainCategoryId"} {
  665. if structField.Name == foreignKey && !structField.IsForeignKey {
  666. t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
  667. }
  668. }
  669. }
  670. for _, structField := range DB.NewScope(&Comment{}).GetStructFields() {
  671. for _, foreignKey := range []string{"PostId"} {
  672. if structField.Name == foreignKey && !structField.IsForeignKey {
  673. t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
  674. }
  675. }
  676. }
  677. }
  678. func testForeignKey(t *testing.T, source interface{}, sourceFieldName string, target interface{}, targetFieldName string) {
  679. if dialect := os.Getenv("GORM_DIALECT"); dialect == "" || dialect == "sqlite" {
  680. // sqlite does not support ADD CONSTRAINT in ALTER TABLE
  681. return
  682. }
  683. targetScope := DB.NewScope(target)
  684. targetTableName := targetScope.TableName()
  685. modelScope := DB.NewScope(source)
  686. modelField, ok := modelScope.FieldByName(sourceFieldName)
  687. if !ok {
  688. t.Fatalf(fmt.Sprintf("Failed to get field by name: %v", sourceFieldName))
  689. }
  690. targetField, ok := targetScope.FieldByName(targetFieldName)
  691. if !ok {
  692. t.Fatalf(fmt.Sprintf("Failed to get field by name: %v", targetFieldName))
  693. }
  694. dest := fmt.Sprintf("%v(%v)", targetTableName, targetField.DBName)
  695. err := DB.Model(source).AddForeignKey(modelField.DBName, dest, "CASCADE", "CASCADE").Error
  696. if err != nil {
  697. t.Fatalf(fmt.Sprintf("Failed to create foreign key: %v", err))
  698. }
  699. }
  700. func TestLongForeignKey(t *testing.T) {
  701. testForeignKey(t, &NotSoLongTableName{}, "ReallyLongThingID", &ReallyLongTableNameToTestMySQLNameLengthLimit{}, "ID")
  702. }
  703. func TestLongForeignKeyWithShortDest(t *testing.T) {
  704. testForeignKey(t, &ReallyLongThingThatReferencesShort{}, "ShortID", &Short{}, "ID")
  705. }
  706. func TestHasManyChildrenWithOneStruct(t *testing.T) {
  707. category := Category{
  708. Name: "main",
  709. Categories: []Category{
  710. {Name: "sub1"},
  711. {Name: "sub2"},
  712. },
  713. }
  714. DB.Save(&category)
  715. }
  716. func TestAutoSaveBelongsToAssociation(t *testing.T) {
  717. type Company struct {
  718. gorm.Model
  719. Name string
  720. }
  721. type User struct {
  722. gorm.Model
  723. Name string
  724. CompanyID uint
  725. Company Company `gorm:"association_autoupdate:false;association_autocreate:false;"`
  726. }
  727. DB.Where("name = ?", "auto_save_association").Delete(&Company{})
  728. DB.AutoMigrate(&Company{}, &User{})
  729. DB.Save(&User{Name: "jinzhu", Company: Company{Name: "auto_save_association"}})
  730. if !DB.Where("name = ?", "auto_save_association").First(&Company{}).RecordNotFound() {
  731. t.Errorf("Company auto_save_association should not have been saved when autosave is false")
  732. }
  733. // if foreign key is set, this should be saved even if association isn't
  734. company := Company{Name: "auto_save_association"}
  735. DB.Save(&company)
  736. company.Name = "auto_save_association_new_name"
  737. user := User{Name: "jinzhu", Company: company}
  738. DB.Save(&user)
  739. if !DB.Where("name = ?", "auto_save_association_new_name").First(&Company{}).RecordNotFound() {
  740. t.Errorf("Company should not have been updated")
  741. }
  742. if DB.Where("id = ? AND company_id = ?", user.ID, company.ID).First(&User{}).RecordNotFound() {
  743. t.Errorf("User's foreign key should have been saved")
  744. }
  745. user2 := User{Name: "jinzhu_2", Company: Company{Name: "auto_save_association_2"}}
  746. DB.Set("gorm:association_autocreate", true).Save(&user2)
  747. if DB.Where("name = ?", "auto_save_association_2").First(&Company{}).RecordNotFound() {
  748. t.Errorf("Company auto_save_association_2 should been created when autocreate is true")
  749. }
  750. user2.Company.Name = "auto_save_association_2_newname"
  751. DB.Set("gorm:association_autoupdate", true).Save(&user2)
  752. if DB.Where("name = ?", "auto_save_association_2_newname").First(&Company{}).RecordNotFound() {
  753. t.Errorf("Company should been updated")
  754. }
  755. }
  756. func TestAutoSaveHasOneAssociation(t *testing.T) {
  757. type Company struct {
  758. gorm.Model
  759. UserID uint
  760. Name string
  761. }
  762. type User struct {
  763. gorm.Model
  764. Name string
  765. Company Company `gorm:"association_autoupdate:false;association_autocreate:false;"`
  766. }
  767. DB.Where("name = ?", "auto_save_has_one_association").Delete(&Company{})
  768. DB.AutoMigrate(&Company{}, &User{})
  769. DB.Save(&User{Name: "jinzhu", Company: Company{Name: "auto_save_has_one_association"}})
  770. if !DB.Where("name = ?", "auto_save_has_one_association").First(&Company{}).RecordNotFound() {
  771. t.Errorf("Company auto_save_has_one_association should not have been saved when autosave is false")
  772. }
  773. company := Company{Name: "auto_save_has_one_association"}
  774. DB.Save(&company)
  775. company.Name = "auto_save_has_one_association_new_name"
  776. user := User{Name: "jinzhu", Company: company}
  777. DB.Save(&user)
  778. if !DB.Where("name = ?", "auto_save_has_one_association_new_name").First(&Company{}).RecordNotFound() {
  779. t.Errorf("Company should not have been updated")
  780. }
  781. if !DB.Where("name = ? AND user_id = ?", "auto_save_has_one_association", user.ID).First(&Company{}).RecordNotFound() {
  782. t.Errorf("Company should not have been updated")
  783. }
  784. if user.Company.UserID == 0 {
  785. t.Errorf("UserID should be assigned")
  786. }
  787. company.Name = "auto_save_has_one_association_2_new_name"
  788. DB.Set("gorm:association_autoupdate", true).Save(&user)
  789. if DB.Where("name = ? AND user_id = ?", "auto_save_has_one_association_new_name", user.ID).First(&Company{}).RecordNotFound() {
  790. t.Errorf("Company should been updated")
  791. }
  792. user2 := User{Name: "jinzhu_2", Company: Company{Name: "auto_save_has_one_association_2"}}
  793. DB.Set("gorm:association_autocreate", true).Save(&user2)
  794. if DB.Where("name = ?", "auto_save_has_one_association_2").First(&Company{}).RecordNotFound() {
  795. t.Errorf("Company auto_save_has_one_association_2 should been created when autocreate is true")
  796. }
  797. }
  798. func TestAutoSaveMany2ManyAssociation(t *testing.T) {
  799. type Company struct {
  800. gorm.Model
  801. Name string
  802. }
  803. type User struct {
  804. gorm.Model
  805. Name string
  806. Companies []Company `gorm:"many2many:user_companies;association_autoupdate:false;association_autocreate:false;"`
  807. }
  808. DB.AutoMigrate(&Company{}, &User{})
  809. DB.Save(&User{Name: "jinzhu", Companies: []Company{{Name: "auto_save_m2m_association"}}})
  810. if !DB.Where("name = ?", "auto_save_m2m_association").First(&Company{}).RecordNotFound() {
  811. t.Errorf("Company auto_save_m2m_association should not have been saved when autosave is false")
  812. }
  813. company := Company{Name: "auto_save_m2m_association"}
  814. DB.Save(&company)
  815. company.Name = "auto_save_m2m_association_new_name"
  816. user := User{Name: "jinzhu", Companies: []Company{company, {Name: "auto_save_m2m_association_new_name_2"}}}
  817. DB.Save(&user)
  818. if !DB.Where("name = ?", "auto_save_m2m_association_new_name").First(&Company{}).RecordNotFound() {
  819. t.Errorf("Company should not have been updated")
  820. }
  821. if !DB.Where("name = ?", "auto_save_m2m_association_new_name_2").First(&Company{}).RecordNotFound() {
  822. t.Errorf("Company should not been created")
  823. }
  824. if DB.Model(&user).Association("Companies").Count() != 1 {
  825. t.Errorf("Relationship should been saved")
  826. }
  827. DB.Set("gorm:association_autoupdate", true).Set("gorm:association_autocreate", true).Save(&user)
  828. if DB.Where("name = ?", "auto_save_m2m_association_new_name").First(&Company{}).RecordNotFound() {
  829. t.Errorf("Company should been updated")
  830. }
  831. if DB.Where("name = ?", "auto_save_m2m_association_new_name_2").First(&Company{}).RecordNotFound() {
  832. t.Errorf("Company should been created")
  833. }
  834. if DB.Model(&user).Association("Companies").Count() != 2 {
  835. t.Errorf("Relationship should been updated")
  836. }
  837. }