customize_column_test.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. package gorm_test
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/jinzhu/gorm"
  6. )
  7. type CustomizeColumn struct {
  8. ID int64 `gorm:"column:mapped_id; primary_key:yes"`
  9. Name string `gorm:"column:mapped_name"`
  10. Date *time.Time `gorm:"column:mapped_time"`
  11. }
  12. // Make sure an ignored field does not interfere with another field's custom
  13. // column name that matches the ignored field.
  14. type CustomColumnAndIgnoredFieldClash struct {
  15. Body string `sql:"-"`
  16. RawBody string `gorm:"column:body"`
  17. }
  18. func TestCustomizeColumn(t *testing.T) {
  19. col := "mapped_name"
  20. DB.DropTable(&CustomizeColumn{})
  21. DB.AutoMigrate(&CustomizeColumn{})
  22. scope := DB.NewScope(&CustomizeColumn{})
  23. if !scope.Dialect().HasColumn(scope.TableName(), col) {
  24. t.Errorf("CustomizeColumn should have column %s", col)
  25. }
  26. col = "mapped_id"
  27. if scope.PrimaryKey() != col {
  28. t.Errorf("CustomizeColumn should have primary key %s, but got %q", col, scope.PrimaryKey())
  29. }
  30. expected := "foo"
  31. now := time.Now()
  32. cc := CustomizeColumn{ID: 666, Name: expected, Date: &now}
  33. if count := DB.Create(&cc).RowsAffected; count != 1 {
  34. t.Error("There should be one record be affected when create record")
  35. }
  36. var cc1 CustomizeColumn
  37. DB.First(&cc1, 666)
  38. if cc1.Name != expected {
  39. t.Errorf("Failed to query CustomizeColumn")
  40. }
  41. cc.Name = "bar"
  42. DB.Save(&cc)
  43. var cc2 CustomizeColumn
  44. DB.First(&cc2, 666)
  45. if cc2.Name != "bar" {
  46. t.Errorf("Failed to query CustomizeColumn")
  47. }
  48. }
  49. func TestCustomColumnAndIgnoredFieldClash(t *testing.T) {
  50. DB.DropTable(&CustomColumnAndIgnoredFieldClash{})
  51. if err := DB.AutoMigrate(&CustomColumnAndIgnoredFieldClash{}).Error; err != nil {
  52. t.Errorf("Should not raise error: %s", err)
  53. }
  54. }
  55. type CustomizePerson struct {
  56. IdPerson string `gorm:"column:idPerson;primary_key:true"`
  57. Accounts []CustomizeAccount `gorm:"many2many:PersonAccount;associationforeignkey:idAccount;foreignkey:idPerson"`
  58. }
  59. type CustomizeAccount struct {
  60. IdAccount string `gorm:"column:idAccount;primary_key:true"`
  61. Name string
  62. }
  63. func TestManyToManyWithCustomizedColumn(t *testing.T) {
  64. DB.DropTable(&CustomizePerson{}, &CustomizeAccount{}, "PersonAccount")
  65. DB.AutoMigrate(&CustomizePerson{}, &CustomizeAccount{})
  66. account := CustomizeAccount{IdAccount: "account", Name: "id1"}
  67. person := CustomizePerson{
  68. IdPerson: "person",
  69. Accounts: []CustomizeAccount{account},
  70. }
  71. if err := DB.Create(&account).Error; err != nil {
  72. t.Errorf("no error should happen, but got %v", err)
  73. }
  74. if err := DB.Create(&person).Error; err != nil {
  75. t.Errorf("no error should happen, but got %v", err)
  76. }
  77. var person1 CustomizePerson
  78. scope := DB.NewScope(nil)
  79. if err := DB.Preload("Accounts").First(&person1, scope.Quote("idPerson")+" = ?", person.IdPerson).Error; err != nil {
  80. t.Errorf("no error should happen when preloading customized column many2many relations, but got %v", err)
  81. }
  82. if len(person1.Accounts) != 1 || person1.Accounts[0].IdAccount != "account" {
  83. t.Errorf("should preload correct accounts")
  84. }
  85. }
  86. type CustomizeUser struct {
  87. gorm.Model
  88. Email string `sql:"column:email_address"`
  89. }
  90. type CustomizeInvitation struct {
  91. gorm.Model
  92. Address string `sql:"column:invitation"`
  93. Person *CustomizeUser `gorm:"foreignkey:Email;associationforeignkey:invitation"`
  94. }
  95. func TestOneToOneWithCustomizedColumn(t *testing.T) {
  96. DB.DropTable(&CustomizeUser{}, &CustomizeInvitation{})
  97. DB.AutoMigrate(&CustomizeUser{}, &CustomizeInvitation{})
  98. user := CustomizeUser{
  99. Email: "hello@example.com",
  100. }
  101. invitation := CustomizeInvitation{
  102. Address: "hello@example.com",
  103. }
  104. DB.Create(&user)
  105. DB.Create(&invitation)
  106. var invitation2 CustomizeInvitation
  107. if err := DB.Preload("Person").Find(&invitation2, invitation.ID).Error; err != nil {
  108. t.Errorf("no error should happen, but got %v", err)
  109. }
  110. if invitation2.Person.Email != user.Email {
  111. t.Errorf("Should preload one to one relation with customize foreign keys")
  112. }
  113. }
  114. type PromotionDiscount struct {
  115. gorm.Model
  116. Name string
  117. Coupons []*PromotionCoupon `gorm:"ForeignKey:discount_id"`
  118. Rule *PromotionRule `gorm:"ForeignKey:discount_id"`
  119. Benefits []PromotionBenefit `gorm:"ForeignKey:promotion_id"`
  120. }
  121. type PromotionBenefit struct {
  122. gorm.Model
  123. Name string
  124. PromotionID uint
  125. Discount PromotionDiscount `gorm:"ForeignKey:promotion_id"`
  126. }
  127. type PromotionCoupon struct {
  128. gorm.Model
  129. Code string
  130. DiscountID uint
  131. Discount PromotionDiscount
  132. }
  133. type PromotionRule struct {
  134. gorm.Model
  135. Name string
  136. Begin *time.Time
  137. End *time.Time
  138. DiscountID uint
  139. Discount *PromotionDiscount
  140. }
  141. func TestOneToManyWithCustomizedColumn(t *testing.T) {
  142. DB.DropTable(&PromotionDiscount{}, &PromotionCoupon{})
  143. DB.AutoMigrate(&PromotionDiscount{}, &PromotionCoupon{})
  144. discount := PromotionDiscount{
  145. Name: "Happy New Year",
  146. Coupons: []*PromotionCoupon{
  147. {Code: "newyear1"},
  148. {Code: "newyear2"},
  149. },
  150. }
  151. if err := DB.Create(&discount).Error; err != nil {
  152. t.Errorf("no error should happen but got %v", err)
  153. }
  154. var discount1 PromotionDiscount
  155. if err := DB.Preload("Coupons").First(&discount1, "id = ?", discount.ID).Error; err != nil {
  156. t.Errorf("no error should happen but got %v", err)
  157. }
  158. if len(discount.Coupons) != 2 {
  159. t.Errorf("should find two coupons")
  160. }
  161. var coupon PromotionCoupon
  162. if err := DB.Preload("Discount").First(&coupon, "code = ?", "newyear1").Error; err != nil {
  163. t.Errorf("no error should happen but got %v", err)
  164. }
  165. if coupon.Discount.Name != "Happy New Year" {
  166. t.Errorf("should preload discount from coupon")
  167. }
  168. }
  169. func TestHasOneWithPartialCustomizedColumn(t *testing.T) {
  170. DB.DropTable(&PromotionDiscount{}, &PromotionRule{})
  171. DB.AutoMigrate(&PromotionDiscount{}, &PromotionRule{})
  172. var begin = time.Now()
  173. var end = time.Now().Add(24 * time.Hour)
  174. discount := PromotionDiscount{
  175. Name: "Happy New Year 2",
  176. Rule: &PromotionRule{
  177. Name: "time_limited",
  178. Begin: &begin,
  179. End: &end,
  180. },
  181. }
  182. if err := DB.Create(&discount).Error; err != nil {
  183. t.Errorf("no error should happen but got %v", err)
  184. }
  185. var discount1 PromotionDiscount
  186. if err := DB.Preload("Rule").First(&discount1, "id = ?", discount.ID).Error; err != nil {
  187. t.Errorf("no error should happen but got %v", err)
  188. }
  189. if discount.Rule.Begin.Format(time.RFC3339Nano) != begin.Format(time.RFC3339Nano) {
  190. t.Errorf("Should be able to preload Rule")
  191. }
  192. var rule PromotionRule
  193. if err := DB.Preload("Discount").First(&rule, "name = ?", "time_limited").Error; err != nil {
  194. t.Errorf("no error should happen but got %v", err)
  195. }
  196. if rule.Discount.Name != "Happy New Year 2" {
  197. t.Errorf("should preload discount from rule")
  198. }
  199. }
  200. func TestBelongsToWithPartialCustomizedColumn(t *testing.T) {
  201. DB.DropTable(&PromotionDiscount{}, &PromotionBenefit{})
  202. DB.AutoMigrate(&PromotionDiscount{}, &PromotionBenefit{})
  203. discount := PromotionDiscount{
  204. Name: "Happy New Year 3",
  205. Benefits: []PromotionBenefit{
  206. {Name: "free cod"},
  207. {Name: "free shipping"},
  208. },
  209. }
  210. if err := DB.Create(&discount).Error; err != nil {
  211. t.Errorf("no error should happen but got %v", err)
  212. }
  213. var discount1 PromotionDiscount
  214. if err := DB.Preload("Benefits").First(&discount1, "id = ?", discount.ID).Error; err != nil {
  215. t.Errorf("no error should happen but got %v", err)
  216. }
  217. if len(discount.Benefits) != 2 {
  218. t.Errorf("should find two benefits")
  219. }
  220. var benefit PromotionBenefit
  221. if err := DB.Preload("Discount").First(&benefit, "name = ?", "free cod").Error; err != nil {
  222. t.Errorf("no error should happen but got %v", err)
  223. }
  224. if benefit.Discount.Name != "Happy New Year 3" {
  225. t.Errorf("should preload discount from coupon")
  226. }
  227. }
  228. type SelfReferencingUser struct {
  229. gorm.Model
  230. Name string
  231. Friends []*SelfReferencingUser `gorm:"many2many:UserFriends;association_jointable_foreignkey:friend_id"`
  232. }
  233. func TestSelfReferencingMany2ManyColumn(t *testing.T) {
  234. DB.DropTable(&SelfReferencingUser{}, "UserFriends")
  235. DB.AutoMigrate(&SelfReferencingUser{})
  236. if !DB.HasTable("UserFriends") {
  237. t.Errorf("auto migrate error, table UserFriends should be created")
  238. }
  239. friend1 := SelfReferencingUser{Name: "friend1_m2m"}
  240. if err := DB.Create(&friend1).Error; err != nil {
  241. t.Errorf("no error should happen, but got %v", err)
  242. }
  243. friend2 := SelfReferencingUser{Name: "friend2_m2m"}
  244. if err := DB.Create(&friend2).Error; err != nil {
  245. t.Errorf("no error should happen, but got %v", err)
  246. }
  247. user := SelfReferencingUser{
  248. Name: "self_m2m",
  249. Friends: []*SelfReferencingUser{&friend1, &friend2},
  250. }
  251. if err := DB.Create(&user).Error; err != nil {
  252. t.Errorf("no error should happen, but got %v", err)
  253. }
  254. if DB.Model(&user).Association("Friends").Count() != 2 {
  255. t.Errorf("Should find created friends correctly")
  256. }
  257. var count int
  258. if err := DB.Table("UserFriends").Count(&count).Error; err != nil {
  259. t.Errorf("no error should happen, but got %v", err)
  260. }
  261. if count == 0 {
  262. t.Errorf("table UserFriends should have records")
  263. }
  264. var newUser = SelfReferencingUser{}
  265. if err := DB.Preload("Friends").First(&newUser, "id = ?", user.ID).Error; err != nil {
  266. t.Errorf("no error should happen, but got %v", err)
  267. }
  268. if len(newUser.Friends) != 2 {
  269. t.Errorf("Should preload created frineds for self reference m2m")
  270. }
  271. DB.Model(&newUser).Association("Friends").Append(&SelfReferencingUser{Name: "friend3_m2m"})
  272. if DB.Model(&user).Association("Friends").Count() != 3 {
  273. t.Errorf("Should find created friends correctly")
  274. }
  275. DB.Model(&newUser).Association("Friends").Replace(&SelfReferencingUser{Name: "friend4_m2m"})
  276. if DB.Model(&user).Association("Friends").Count() != 1 {
  277. t.Errorf("Should find created friends correctly")
  278. }
  279. friend := SelfReferencingUser{}
  280. DB.Model(&newUser).Association("Friends").Find(&friend)
  281. if friend.Name != "friend4_m2m" {
  282. t.Errorf("Should find created friends correctly")
  283. }
  284. DB.Model(&newUser).Association("Friends").Delete(friend)
  285. if DB.Model(&user).Association("Friends").Count() != 0 {
  286. t.Errorf("All friends should be deleted")
  287. }
  288. }