multi_primary_keys_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. package gorm_test
  2. import (
  3. "os"
  4. "reflect"
  5. "sort"
  6. "testing"
  7. )
  8. type Blog struct {
  9. ID uint `gorm:"primary_key"`
  10. Locale string `gorm:"primary_key"`
  11. Subject string
  12. Body string
  13. Tags []Tag `gorm:"many2many:blog_tags;"`
  14. SharedTags []Tag `gorm:"many2many:shared_blog_tags;ForeignKey:id;AssociationForeignKey:id"`
  15. LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;AssociationForeignKey:id"`
  16. }
  17. type Tag struct {
  18. ID uint `gorm:"primary_key"`
  19. Locale string `gorm:"primary_key"`
  20. Value string
  21. Blogs []*Blog `gorm:"many2many:blogs_tags"`
  22. }
  23. func compareTags(tags []Tag, contents []string) bool {
  24. var tagContents []string
  25. for _, tag := range tags {
  26. tagContents = append(tagContents, tag.Value)
  27. }
  28. sort.Strings(tagContents)
  29. sort.Strings(contents)
  30. return reflect.DeepEqual(tagContents, contents)
  31. }
  32. func TestManyToManyWithMultiPrimaryKeys(t *testing.T) {
  33. if dialect := os.Getenv("GORM_DIALECT"); dialect != "" && dialect != "sqlite" && dialect != "mssql" {
  34. DB.DropTable(&Blog{}, &Tag{})
  35. DB.DropTable("blog_tags")
  36. DB.CreateTable(&Blog{}, &Tag{})
  37. blog := Blog{
  38. Locale: "ZH",
  39. Subject: "subject",
  40. Body: "body",
  41. Tags: []Tag{
  42. {Locale: "ZH", Value: "tag1"},
  43. {Locale: "ZH", Value: "tag2"},
  44. },
  45. }
  46. DB.Save(&blog)
  47. if !compareTags(blog.Tags, []string{"tag1", "tag2"}) {
  48. t.Errorf("Blog should has two tags")
  49. }
  50. // Append
  51. var tag3 = &Tag{Locale: "ZH", Value: "tag3"}
  52. DB.Model(&blog).Association("Tags").Append([]*Tag{tag3})
  53. if !compareTags(blog.Tags, []string{"tag1", "tag2", "tag3"}) {
  54. t.Errorf("Blog should has three tags after Append")
  55. }
  56. if DB.Model(&blog).Association("Tags").Count() != 3 {
  57. t.Errorf("Blog should has three tags after Append")
  58. }
  59. var tags []Tag
  60. DB.Model(&blog).Related(&tags, "Tags")
  61. if !compareTags(tags, []string{"tag1", "tag2", "tag3"}) {
  62. t.Errorf("Should find 3 tags with Related")
  63. }
  64. var blog1 Blog
  65. DB.Preload("Tags").Find(&blog1)
  66. if !compareTags(blog1.Tags, []string{"tag1", "tag2", "tag3"}) {
  67. t.Errorf("Preload many2many relations")
  68. }
  69. // Replace
  70. var tag5 = &Tag{Locale: "ZH", Value: "tag5"}
  71. var tag6 = &Tag{Locale: "ZH", Value: "tag6"}
  72. DB.Model(&blog).Association("Tags").Replace(tag5, tag6)
  73. var tags2 []Tag
  74. DB.Model(&blog).Related(&tags2, "Tags")
  75. if !compareTags(tags2, []string{"tag5", "tag6"}) {
  76. t.Errorf("Should find 2 tags after Replace")
  77. }
  78. if DB.Model(&blog).Association("Tags").Count() != 2 {
  79. t.Errorf("Blog should has three tags after Replace")
  80. }
  81. // Delete
  82. DB.Model(&blog).Association("Tags").Delete(tag5)
  83. var tags3 []Tag
  84. DB.Model(&blog).Related(&tags3, "Tags")
  85. if !compareTags(tags3, []string{"tag6"}) {
  86. t.Errorf("Should find 1 tags after Delete")
  87. }
  88. if DB.Model(&blog).Association("Tags").Count() != 1 {
  89. t.Errorf("Blog should has three tags after Delete")
  90. }
  91. DB.Model(&blog).Association("Tags").Delete(tag3)
  92. var tags4 []Tag
  93. DB.Model(&blog).Related(&tags4, "Tags")
  94. if !compareTags(tags4, []string{"tag6"}) {
  95. t.Errorf("Tag should not be deleted when Delete with a unrelated tag")
  96. }
  97. // Clear
  98. DB.Model(&blog).Association("Tags").Clear()
  99. if DB.Model(&blog).Association("Tags").Count() != 0 {
  100. t.Errorf("All tags should be cleared")
  101. }
  102. }
  103. }
  104. func TestManyToManyWithCustomizedForeignKeys(t *testing.T) {
  105. if dialect := os.Getenv("GORM_DIALECT"); dialect != "" && dialect != "sqlite" && dialect != "mssql" {
  106. DB.DropTable(&Blog{}, &Tag{})
  107. DB.DropTable("shared_blog_tags")
  108. DB.CreateTable(&Blog{}, &Tag{})
  109. blog := Blog{
  110. Locale: "ZH",
  111. Subject: "subject",
  112. Body: "body",
  113. SharedTags: []Tag{
  114. {Locale: "ZH", Value: "tag1"},
  115. {Locale: "ZH", Value: "tag2"},
  116. },
  117. }
  118. DB.Save(&blog)
  119. blog2 := Blog{
  120. ID: blog.ID,
  121. Locale: "EN",
  122. }
  123. DB.Create(&blog2)
  124. if !compareTags(blog.SharedTags, []string{"tag1", "tag2"}) {
  125. t.Errorf("Blog should has two tags")
  126. }
  127. // Append
  128. var tag3 = &Tag{Locale: "ZH", Value: "tag3"}
  129. DB.Model(&blog).Association("SharedTags").Append([]*Tag{tag3})
  130. if !compareTags(blog.SharedTags, []string{"tag1", "tag2", "tag3"}) {
  131. t.Errorf("Blog should has three tags after Append")
  132. }
  133. if DB.Model(&blog).Association("SharedTags").Count() != 3 {
  134. t.Errorf("Blog should has three tags after Append")
  135. }
  136. if DB.Model(&blog2).Association("SharedTags").Count() != 3 {
  137. t.Errorf("Blog should has three tags after Append")
  138. }
  139. var tags []Tag
  140. DB.Model(&blog).Related(&tags, "SharedTags")
  141. if !compareTags(tags, []string{"tag1", "tag2", "tag3"}) {
  142. t.Errorf("Should find 3 tags with Related")
  143. }
  144. DB.Model(&blog2).Related(&tags, "SharedTags")
  145. if !compareTags(tags, []string{"tag1", "tag2", "tag3"}) {
  146. t.Errorf("Should find 3 tags with Related")
  147. }
  148. var blog1 Blog
  149. DB.Preload("SharedTags").Find(&blog1)
  150. if !compareTags(blog1.SharedTags, []string{"tag1", "tag2", "tag3"}) {
  151. t.Errorf("Preload many2many relations")
  152. }
  153. var tag4 = &Tag{Locale: "ZH", Value: "tag4"}
  154. DB.Model(&blog2).Association("SharedTags").Append(tag4)
  155. DB.Model(&blog).Related(&tags, "SharedTags")
  156. if !compareTags(tags, []string{"tag1", "tag2", "tag3", "tag4"}) {
  157. t.Errorf("Should find 3 tags with Related")
  158. }
  159. DB.Model(&blog2).Related(&tags, "SharedTags")
  160. if !compareTags(tags, []string{"tag1", "tag2", "tag3", "tag4"}) {
  161. t.Errorf("Should find 3 tags with Related")
  162. }
  163. // Replace
  164. var tag5 = &Tag{Locale: "ZH", Value: "tag5"}
  165. var tag6 = &Tag{Locale: "ZH", Value: "tag6"}
  166. DB.Model(&blog2).Association("SharedTags").Replace(tag5, tag6)
  167. var tags2 []Tag
  168. DB.Model(&blog).Related(&tags2, "SharedTags")
  169. if !compareTags(tags2, []string{"tag5", "tag6"}) {
  170. t.Errorf("Should find 2 tags after Replace")
  171. }
  172. DB.Model(&blog2).Related(&tags2, "SharedTags")
  173. if !compareTags(tags2, []string{"tag5", "tag6"}) {
  174. t.Errorf("Should find 2 tags after Replace")
  175. }
  176. if DB.Model(&blog).Association("SharedTags").Count() != 2 {
  177. t.Errorf("Blog should has three tags after Replace")
  178. }
  179. // Delete
  180. DB.Model(&blog).Association("SharedTags").Delete(tag5)
  181. var tags3 []Tag
  182. DB.Model(&blog).Related(&tags3, "SharedTags")
  183. if !compareTags(tags3, []string{"tag6"}) {
  184. t.Errorf("Should find 1 tags after Delete")
  185. }
  186. if DB.Model(&blog).Association("SharedTags").Count() != 1 {
  187. t.Errorf("Blog should has three tags after Delete")
  188. }
  189. DB.Model(&blog2).Association("SharedTags").Delete(tag3)
  190. var tags4 []Tag
  191. DB.Model(&blog).Related(&tags4, "SharedTags")
  192. if !compareTags(tags4, []string{"tag6"}) {
  193. t.Errorf("Tag should not be deleted when Delete with a unrelated tag")
  194. }
  195. // Clear
  196. DB.Model(&blog2).Association("SharedTags").Clear()
  197. if DB.Model(&blog).Association("SharedTags").Count() != 0 {
  198. t.Errorf("All tags should be cleared")
  199. }
  200. }
  201. }
  202. func TestManyToManyWithCustomizedForeignKeys2(t *testing.T) {
  203. if dialect := os.Getenv("GORM_DIALECT"); dialect != "" && dialect != "sqlite" && dialect != "mssql" {
  204. DB.DropTable(&Blog{}, &Tag{})
  205. DB.DropTable("locale_blog_tags")
  206. DB.CreateTable(&Blog{}, &Tag{})
  207. blog := Blog{
  208. Locale: "ZH",
  209. Subject: "subject",
  210. Body: "body",
  211. LocaleTags: []Tag{
  212. {Locale: "ZH", Value: "tag1"},
  213. {Locale: "ZH", Value: "tag2"},
  214. },
  215. }
  216. DB.Save(&blog)
  217. blog2 := Blog{
  218. ID: blog.ID,
  219. Locale: "EN",
  220. }
  221. DB.Create(&blog2)
  222. // Append
  223. var tag3 = &Tag{Locale: "ZH", Value: "tag3"}
  224. DB.Model(&blog).Association("LocaleTags").Append([]*Tag{tag3})
  225. if !compareTags(blog.LocaleTags, []string{"tag1", "tag2", "tag3"}) {
  226. t.Errorf("Blog should has three tags after Append")
  227. }
  228. if DB.Model(&blog).Association("LocaleTags").Count() != 3 {
  229. t.Errorf("Blog should has three tags after Append")
  230. }
  231. if DB.Model(&blog2).Association("LocaleTags").Count() != 0 {
  232. t.Errorf("EN Blog should has 0 tags after ZH Blog Append")
  233. }
  234. var tags []Tag
  235. DB.Model(&blog).Related(&tags, "LocaleTags")
  236. if !compareTags(tags, []string{"tag1", "tag2", "tag3"}) {
  237. t.Errorf("Should find 3 tags with Related")
  238. }
  239. DB.Model(&blog2).Related(&tags, "LocaleTags")
  240. if len(tags) != 0 {
  241. t.Errorf("Should find 0 tags with Related for EN Blog")
  242. }
  243. var blog1 Blog
  244. DB.Preload("LocaleTags").Find(&blog1, "locale = ? AND id = ?", "ZH", blog.ID)
  245. if !compareTags(blog1.LocaleTags, []string{"tag1", "tag2", "tag3"}) {
  246. t.Errorf("Preload many2many relations")
  247. }
  248. var tag4 = &Tag{Locale: "ZH", Value: "tag4"}
  249. DB.Model(&blog2).Association("LocaleTags").Append(tag4)
  250. DB.Model(&blog).Related(&tags, "LocaleTags")
  251. if !compareTags(tags, []string{"tag1", "tag2", "tag3"}) {
  252. t.Errorf("Should find 3 tags with Related for EN Blog")
  253. }
  254. DB.Model(&blog2).Related(&tags, "LocaleTags")
  255. if !compareTags(tags, []string{"tag4"}) {
  256. t.Errorf("Should find 1 tags with Related for EN Blog")
  257. }
  258. // Replace
  259. var tag5 = &Tag{Locale: "ZH", Value: "tag5"}
  260. var tag6 = &Tag{Locale: "ZH", Value: "tag6"}
  261. DB.Model(&blog2).Association("LocaleTags").Replace(tag5, tag6)
  262. var tags2 []Tag
  263. DB.Model(&blog).Related(&tags2, "LocaleTags")
  264. if !compareTags(tags2, []string{"tag1", "tag2", "tag3"}) {
  265. t.Errorf("CN Blog's tags should not be changed after EN Blog Replace")
  266. }
  267. var blog11 Blog
  268. DB.Preload("LocaleTags").First(&blog11, "id = ? AND locale = ?", blog.ID, blog.Locale)
  269. if !compareTags(blog11.LocaleTags, []string{"tag1", "tag2", "tag3"}) {
  270. t.Errorf("CN Blog's tags should not be changed after EN Blog Replace")
  271. }
  272. DB.Model(&blog2).Related(&tags2, "LocaleTags")
  273. if !compareTags(tags2, []string{"tag5", "tag6"}) {
  274. t.Errorf("Should find 2 tags after Replace")
  275. }
  276. var blog21 Blog
  277. DB.Preload("LocaleTags").First(&blog21, "id = ? AND locale = ?", blog2.ID, blog2.Locale)
  278. if !compareTags(blog21.LocaleTags, []string{"tag5", "tag6"}) {
  279. t.Errorf("EN Blog's tags should be changed after Replace")
  280. }
  281. if DB.Model(&blog).Association("LocaleTags").Count() != 3 {
  282. t.Errorf("ZH Blog should has three tags after Replace")
  283. }
  284. if DB.Model(&blog2).Association("LocaleTags").Count() != 2 {
  285. t.Errorf("EN Blog should has two tags after Replace")
  286. }
  287. // Delete
  288. DB.Model(&blog).Association("LocaleTags").Delete(tag5)
  289. if DB.Model(&blog).Association("LocaleTags").Count() != 3 {
  290. t.Errorf("ZH Blog should has three tags after Delete with EN's tag")
  291. }
  292. if DB.Model(&blog2).Association("LocaleTags").Count() != 2 {
  293. t.Errorf("EN Blog should has two tags after ZH Blog Delete with EN's tag")
  294. }
  295. DB.Model(&blog2).Association("LocaleTags").Delete(tag5)
  296. if DB.Model(&blog).Association("LocaleTags").Count() != 3 {
  297. t.Errorf("ZH Blog should has three tags after EN Blog Delete with EN's tag")
  298. }
  299. if DB.Model(&blog2).Association("LocaleTags").Count() != 1 {
  300. t.Errorf("EN Blog should has 1 tags after EN Blog Delete with EN's tag")
  301. }
  302. // Clear
  303. DB.Model(&blog2).Association("LocaleTags").Clear()
  304. if DB.Model(&blog).Association("LocaleTags").Count() != 3 {
  305. t.Errorf("ZH Blog's tags should not be cleared when clear EN Blog's tags")
  306. }
  307. if DB.Model(&blog2).Association("LocaleTags").Count() != 0 {
  308. t.Errorf("EN Blog's tags should be cleared when clear EN Blog's tags")
  309. }
  310. DB.Model(&blog).Association("LocaleTags").Clear()
  311. if DB.Model(&blog).Association("LocaleTags").Count() != 0 {
  312. t.Errorf("ZH Blog's tags should be cleared when clear ZH Blog's tags")
  313. }
  314. if DB.Model(&blog2).Association("LocaleTags").Count() != 0 {
  315. t.Errorf("EN Blog's tags should be cleared")
  316. }
  317. }
  318. }