OSDN Git Service

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