
use golangci/golangci-lint-action instead of reviewdog/action-golangci-lint as the second was not reporting any failures even if there was some. Report code coverage with codecov/codecov-action I have set some flags per dialect and go version Several linters has been fixed, some disabled so the build can pass
449 lines
13 KiB
Go
449 lines
13 KiB
Go
package tests_test
|
|
|
|
import (
|
|
"reflect"
|
|
"sort"
|
|
"testing"
|
|
|
|
"gorm.io/gorm"
|
|
. "gorm.io/gorm/utils/tests"
|
|
)
|
|
|
|
type Blog struct {
|
|
ID uint `gorm:"primary_key"`
|
|
Locale string `gorm:"primary_key"`
|
|
Subject string
|
|
Body string
|
|
Tags []Tag `gorm:"many2many:blog_tags;"`
|
|
SharedTags []Tag `gorm:"many2many:shared_blog_tags;ForeignKey:id;References:id"`
|
|
LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;References:id"`
|
|
}
|
|
|
|
type Tag struct {
|
|
ID uint `gorm:"primary_key"`
|
|
Locale string `gorm:"primary_key"`
|
|
Value string
|
|
Blogs []*Blog `gorm:"many2many:blog_tags"`
|
|
}
|
|
|
|
func compareTags(tags []Tag, contents []string) bool {
|
|
var tagContents []string
|
|
for _, tag := range tags {
|
|
tagContents = append(tagContents, tag.Value)
|
|
}
|
|
sort.Strings(tagContents)
|
|
sort.Strings(contents)
|
|
return reflect.DeepEqual(tagContents, contents)
|
|
}
|
|
|
|
func TestManyToManyWithMultiPrimaryKeys(t *testing.T) {
|
|
if name := DB.Dialector.Name(); name == "sqlite" || name == "sqlserver" {
|
|
t.Skip("skip sqlite, sqlserver due to it doesn't support multiple primary keys with auto increment")
|
|
}
|
|
|
|
if name := DB.Dialector.Name(); name == "postgres" {
|
|
stmt := gorm.Statement{DB: DB}
|
|
stmt.Parse(&Blog{})
|
|
stmt.Schema.LookUpField("ID").Unique = true
|
|
stmt.Parse(&Tag{})
|
|
stmt.Schema.LookUpField("ID").Unique = true
|
|
// postgers only allow unique constraint matching given keys
|
|
}
|
|
|
|
DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags")
|
|
if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil {
|
|
t.Fatalf("Failed to auto migrate, got error: %v", err)
|
|
}
|
|
|
|
blog := Blog{
|
|
Locale: "ZH",
|
|
Subject: "subject",
|
|
Body: "body",
|
|
Tags: []Tag{
|
|
{Locale: "ZH", Value: "tag1"},
|
|
{Locale: "ZH", Value: "tag2"},
|
|
},
|
|
}
|
|
|
|
DB.Save(&blog)
|
|
if !compareTags(blog.Tags, []string{"tag1", "tag2"}) {
|
|
t.Fatalf("Blog should has two tags")
|
|
}
|
|
|
|
// Append
|
|
tag3 := &Tag{Locale: "ZH", Value: "tag3"}
|
|
DB.Model(&blog).Association("Tags").Append([]*Tag{tag3})
|
|
|
|
if !compareTags(blog.Tags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("Blog should has three tags after Append")
|
|
}
|
|
|
|
if count := DB.Model(&blog).Association("Tags").Count(); count != 3 {
|
|
t.Fatalf("Blog should has 3 tags after Append, got %v", count)
|
|
}
|
|
|
|
var tags []Tag
|
|
DB.Model(&blog).Association("Tags").Find(&tags)
|
|
if !compareTags(tags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("Should find 3 tags")
|
|
}
|
|
|
|
var blog1 Blog
|
|
DB.Preload("Tags").Find(&blog1)
|
|
if !compareTags(blog1.Tags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("Preload many2many relations")
|
|
}
|
|
|
|
// Replace
|
|
tag5 := &Tag{Locale: "ZH", Value: "tag5"}
|
|
tag6 := &Tag{Locale: "ZH", Value: "tag6"}
|
|
DB.Model(&blog).Association("Tags").Replace(tag5, tag6)
|
|
var tags2 []Tag
|
|
DB.Model(&blog).Association("Tags").Find(&tags2)
|
|
if !compareTags(tags2, []string{"tag5", "tag6"}) {
|
|
t.Fatalf("Should find 2 tags after Replace")
|
|
}
|
|
|
|
if DB.Model(&blog).Association("Tags").Count() != 2 {
|
|
t.Fatalf("Blog should has three tags after Replace")
|
|
}
|
|
|
|
// Delete
|
|
DB.Model(&blog).Association("Tags").Delete(tag5)
|
|
var tags3 []Tag
|
|
DB.Model(&blog).Association("Tags").Find(&tags3)
|
|
if !compareTags(tags3, []string{"tag6"}) {
|
|
t.Fatalf("Should find 1 tags after Delete")
|
|
}
|
|
|
|
if DB.Model(&blog).Association("Tags").Count() != 1 {
|
|
t.Fatalf("Blog should has three tags after Delete")
|
|
}
|
|
|
|
DB.Model(&blog).Association("Tags").Delete(tag3)
|
|
var tags4 []Tag
|
|
DB.Model(&blog).Association("Tags").Find(&tags4)
|
|
if !compareTags(tags4, []string{"tag6"}) {
|
|
t.Fatalf("Tag should not be deleted when Delete with a unrelated tag")
|
|
}
|
|
|
|
// Clear
|
|
DB.Model(&blog).Association("Tags").Clear()
|
|
if DB.Model(&blog).Association("Tags").Count() != 0 {
|
|
t.Fatalf("All tags should be cleared")
|
|
}
|
|
}
|
|
|
|
func TestManyToManyWithCustomizedForeignKeys(t *testing.T) {
|
|
if name := DB.Dialector.Name(); name == "sqlite" || name == "sqlserver" {
|
|
t.Skip("skip sqlite, sqlserver due to it doesn't support multiple primary keys with auto increment")
|
|
}
|
|
|
|
if name := DB.Dialector.Name(); name == "postgres" {
|
|
t.Skip("skip postgres due to it only allow unique constraint matching given keys")
|
|
}
|
|
|
|
DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags")
|
|
if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil {
|
|
t.Fatalf("Failed to auto migrate, got error: %v", err)
|
|
}
|
|
|
|
blog := Blog{
|
|
Locale: "ZH",
|
|
Subject: "subject",
|
|
Body: "body",
|
|
SharedTags: []Tag{
|
|
{Locale: "ZH", Value: "tag1"},
|
|
{Locale: "ZH", Value: "tag2"},
|
|
},
|
|
}
|
|
DB.Save(&blog)
|
|
|
|
blog2 := Blog{
|
|
ID: blog.ID,
|
|
Locale: "EN",
|
|
}
|
|
DB.Create(&blog2)
|
|
|
|
if !compareTags(blog.SharedTags, []string{"tag1", "tag2"}) {
|
|
t.Fatalf("Blog should has two tags")
|
|
}
|
|
|
|
// Append
|
|
tag3 := &Tag{Locale: "ZH", Value: "tag3"}
|
|
DB.Model(&blog).Association("SharedTags").Append([]*Tag{tag3})
|
|
if !compareTags(blog.SharedTags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("Blog should has three tags after Append")
|
|
}
|
|
|
|
if DB.Model(&blog).Association("SharedTags").Count() != 3 {
|
|
t.Fatalf("Blog should has three tags after Append")
|
|
}
|
|
|
|
if DB.Model(&blog2).Association("SharedTags").Count() != 3 {
|
|
t.Fatalf("Blog should has three tags after Append")
|
|
}
|
|
|
|
var tags []Tag
|
|
DB.Model(&blog).Association("SharedTags").Find(&tags)
|
|
if !compareTags(tags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("Should find 3 tags")
|
|
}
|
|
|
|
DB.Model(&blog2).Association("SharedTags").Find(&tags)
|
|
if !compareTags(tags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("Should find 3 tags")
|
|
}
|
|
|
|
var blog1 Blog
|
|
DB.Preload("SharedTags").Find(&blog1)
|
|
if !compareTags(blog1.SharedTags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("Preload many2many relations")
|
|
}
|
|
|
|
tag4 := &Tag{Locale: "ZH", Value: "tag4"}
|
|
DB.Model(&blog2).Association("SharedTags").Append(tag4)
|
|
|
|
DB.Model(&blog).Association("SharedTags").Find(&tags)
|
|
if !compareTags(tags, []string{"tag1", "tag2", "tag3", "tag4"}) {
|
|
t.Fatalf("Should find 3 tags")
|
|
}
|
|
|
|
DB.Model(&blog2).Association("SharedTags").Find(&tags)
|
|
if !compareTags(tags, []string{"tag1", "tag2", "tag3", "tag4"}) {
|
|
t.Fatalf("Should find 3 tags")
|
|
}
|
|
|
|
// Replace
|
|
tag5 := &Tag{Locale: "ZH", Value: "tag5"}
|
|
tag6 := &Tag{Locale: "ZH", Value: "tag6"}
|
|
DB.Model(&blog2).Association("SharedTags").Replace(tag5, tag6)
|
|
var tags2 []Tag
|
|
DB.Model(&blog).Association("SharedTags").Find(&tags2)
|
|
if !compareTags(tags2, []string{"tag5", "tag6"}) {
|
|
t.Fatalf("Should find 2 tags after Replace")
|
|
}
|
|
|
|
DB.Model(&blog2).Association("SharedTags").Find(&tags2)
|
|
if !compareTags(tags2, []string{"tag5", "tag6"}) {
|
|
t.Fatalf("Should find 2 tags after Replace")
|
|
}
|
|
|
|
if DB.Model(&blog).Association("SharedTags").Count() != 2 {
|
|
t.Fatalf("Blog should has three tags after Replace")
|
|
}
|
|
|
|
// Delete
|
|
DB.Model(&blog).Association("SharedTags").Delete(tag5)
|
|
var tags3 []Tag
|
|
DB.Model(&blog).Association("SharedTags").Find(&tags3)
|
|
if !compareTags(tags3, []string{"tag6"}) {
|
|
t.Fatalf("Should find 1 tags after Delete")
|
|
}
|
|
|
|
if DB.Model(&blog).Association("SharedTags").Count() != 1 {
|
|
t.Fatalf("Blog should has three tags after Delete")
|
|
}
|
|
|
|
DB.Model(&blog2).Association("SharedTags").Delete(tag3)
|
|
var tags4 []Tag
|
|
DB.Model(&blog).Association("SharedTags").Find(&tags4)
|
|
if !compareTags(tags4, []string{"tag6"}) {
|
|
t.Fatalf("Tag should not be deleted when Delete with a unrelated tag")
|
|
}
|
|
|
|
// Clear
|
|
DB.Model(&blog2).Association("SharedTags").Clear()
|
|
if DB.Model(&blog).Association("SharedTags").Count() != 0 {
|
|
t.Fatalf("All tags should be cleared")
|
|
}
|
|
}
|
|
|
|
func TestManyToManyWithCustomizedForeignKeys2(t *testing.T) {
|
|
if name := DB.Dialector.Name(); name == "sqlite" || name == "sqlserver" {
|
|
t.Skip("skip sqlite, sqlserver due to it doesn't support multiple primary keys with auto increment")
|
|
}
|
|
|
|
if name := DB.Dialector.Name(); name == "postgres" {
|
|
t.Skip("skip postgres due to it only allow unique constraint matching given keys")
|
|
}
|
|
|
|
DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags")
|
|
if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil {
|
|
t.Fatalf("Failed to auto migrate, got error: %v", err)
|
|
}
|
|
|
|
blog := Blog{
|
|
Locale: "ZH",
|
|
Subject: "subject",
|
|
Body: "body",
|
|
LocaleTags: []Tag{
|
|
{Locale: "ZH", Value: "tag1"},
|
|
{Locale: "ZH", Value: "tag2"},
|
|
},
|
|
}
|
|
DB.Save(&blog)
|
|
|
|
blog2 := Blog{
|
|
ID: blog.ID,
|
|
Locale: "EN",
|
|
}
|
|
DB.Create(&blog2)
|
|
|
|
// Append
|
|
tag3 := &Tag{Locale: "ZH", Value: "tag3"}
|
|
DB.Model(&blog).Association("LocaleTags").Append([]*Tag{tag3})
|
|
if !compareTags(blog.LocaleTags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("Blog should has three tags after Append")
|
|
}
|
|
|
|
if DB.Model(&blog).Association("LocaleTags").Count() != 3 {
|
|
t.Fatalf("Blog should has three tags after Append")
|
|
}
|
|
|
|
if DB.Model(&blog2).Association("LocaleTags").Count() != 0 {
|
|
t.Fatalf("EN Blog should has 0 tags after ZH Blog Append")
|
|
}
|
|
|
|
var tags []Tag
|
|
DB.Model(&blog).Association("LocaleTags").Find(&tags)
|
|
if !compareTags(tags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("Should find 3 tags")
|
|
}
|
|
|
|
DB.Model(&blog2).Association("LocaleTags").Find(&tags)
|
|
if len(tags) != 0 {
|
|
t.Fatalf("Should find 0 tags for EN Blog")
|
|
}
|
|
|
|
var blog1 Blog
|
|
DB.Preload("LocaleTags").Find(&blog1, "locale = ? AND id = ?", "ZH", blog.ID)
|
|
if !compareTags(blog1.LocaleTags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("Preload many2many relations")
|
|
}
|
|
|
|
tag4 := &Tag{Locale: "ZH", Value: "tag4"}
|
|
DB.Model(&blog2).Association("LocaleTags").Append(tag4)
|
|
|
|
DB.Model(&blog).Association("LocaleTags").Find(&tags)
|
|
if !compareTags(tags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("Should find 3 tags for EN Blog")
|
|
}
|
|
|
|
DB.Model(&blog2).Association("LocaleTags").Find(&tags)
|
|
if !compareTags(tags, []string{"tag4"}) {
|
|
t.Fatalf("Should find 1 tags for EN Blog")
|
|
}
|
|
|
|
// Replace
|
|
tag5 := &Tag{Locale: "ZH", Value: "tag5"}
|
|
tag6 := &Tag{Locale: "ZH", Value: "tag6"}
|
|
DB.Model(&blog2).Association("LocaleTags").Replace(tag5, tag6)
|
|
|
|
var tags2 []Tag
|
|
DB.Model(&blog).Association("LocaleTags").Find(&tags2)
|
|
if !compareTags(tags2, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("CN Blog's tags should not be changed after EN Blog Replace")
|
|
}
|
|
|
|
var blog11 Blog
|
|
DB.Preload("LocaleTags").First(&blog11, "id = ? AND locale = ?", blog.ID, blog.Locale)
|
|
if !compareTags(blog11.LocaleTags, []string{"tag1", "tag2", "tag3"}) {
|
|
t.Fatalf("CN Blog's tags should not be changed after EN Blog Replace")
|
|
}
|
|
|
|
DB.Model(&blog2).Association("LocaleTags").Find(&tags2)
|
|
if !compareTags(tags2, []string{"tag5", "tag6"}) {
|
|
t.Fatalf("Should find 2 tags after Replace")
|
|
}
|
|
|
|
var blog21 Blog
|
|
DB.Preload("LocaleTags").First(&blog21, "id = ? AND locale = ?", blog2.ID, blog2.Locale)
|
|
if !compareTags(blog21.LocaleTags, []string{"tag5", "tag6"}) {
|
|
t.Fatalf("EN Blog's tags should be changed after Replace")
|
|
}
|
|
|
|
if DB.Model(&blog).Association("LocaleTags").Count() != 3 {
|
|
t.Fatalf("ZH Blog should has three tags after Replace")
|
|
}
|
|
|
|
if DB.Model(&blog2).Association("LocaleTags").Count() != 2 {
|
|
t.Fatalf("EN Blog should has two tags after Replace")
|
|
}
|
|
|
|
// Delete
|
|
DB.Model(&blog).Association("LocaleTags").Delete(tag5)
|
|
|
|
if DB.Model(&blog).Association("LocaleTags").Count() != 3 {
|
|
t.Fatalf("ZH Blog should has three tags after Delete with EN's tag")
|
|
}
|
|
|
|
if DB.Model(&blog2).Association("LocaleTags").Count() != 2 {
|
|
t.Fatalf("EN Blog should has two tags after ZH Blog Delete with EN's tag")
|
|
}
|
|
|
|
DB.Model(&blog2).Association("LocaleTags").Delete(tag5)
|
|
|
|
if DB.Model(&blog).Association("LocaleTags").Count() != 3 {
|
|
t.Fatalf("ZH Blog should has three tags after EN Blog Delete with EN's tag")
|
|
}
|
|
|
|
if DB.Model(&blog2).Association("LocaleTags").Count() != 1 {
|
|
t.Fatalf("EN Blog should has 1 tags after EN Blog Delete with EN's tag")
|
|
}
|
|
|
|
// Clear
|
|
DB.Model(&blog2).Association("LocaleTags").Clear()
|
|
if DB.Model(&blog).Association("LocaleTags").Count() != 3 {
|
|
t.Fatalf("ZH Blog's tags should not be cleared when clear EN Blog's tags")
|
|
}
|
|
|
|
if DB.Model(&blog2).Association("LocaleTags").Count() != 0 {
|
|
t.Fatalf("EN Blog's tags should be cleared when clear EN Blog's tags")
|
|
}
|
|
|
|
DB.Model(&blog).Association("LocaleTags").Clear()
|
|
if DB.Model(&blog).Association("LocaleTags").Count() != 0 {
|
|
t.Fatalf("ZH Blog's tags should be cleared when clear ZH Blog's tags")
|
|
}
|
|
|
|
if DB.Model(&blog2).Association("LocaleTags").Count() != 0 {
|
|
t.Fatalf("EN Blog's tags should be cleared")
|
|
}
|
|
}
|
|
|
|
func TestCompositePrimaryKeysAssociations(t *testing.T) {
|
|
type Label struct {
|
|
BookID *uint `gorm:"primarykey"`
|
|
Name string `gorm:"primarykey"`
|
|
Value string
|
|
}
|
|
|
|
type Book struct {
|
|
ID int
|
|
Name string
|
|
Labels []Label
|
|
}
|
|
|
|
DB.Migrator().DropTable(&Label{}, &Book{})
|
|
if err := DB.AutoMigrate(&Label{}, &Book{}); err != nil {
|
|
t.Fatalf("failed to migrate, got %v", err)
|
|
}
|
|
|
|
book := Book{
|
|
Name: "my book",
|
|
Labels: []Label{
|
|
{Name: "region", Value: "emea"},
|
|
},
|
|
}
|
|
|
|
DB.Create(&book)
|
|
|
|
var result Book
|
|
if err := DB.Preload("Labels").First(&result, book.ID).Error; err != nil {
|
|
t.Fatalf("failed to preload, got error %v", err)
|
|
}
|
|
|
|
AssertEqual(t, book, result)
|
|
}
|