forked from mirror/gorm
261 lines
6.7 KiB
Go
261 lines
6.7 KiB
Go
package tests_test
|
||
|
||
import (
|
||
"encoding/json"
|
||
"regexp"
|
||
"sort"
|
||
"strconv"
|
||
"sync"
|
||
"testing"
|
||
|
||
"github.com/stretchr/testify/assert"
|
||
|
||
"gorm.io/gorm"
|
||
"gorm.io/gorm/clause"
|
||
. "gorm.io/gorm/utils/tests"
|
||
)
|
||
|
||
func TestPreloadWithAssociations(t *testing.T) {
|
||
var user = *GetUser("preload_with_associations", Config{
|
||
Account: true,
|
||
Pets: 2,
|
||
Toys: 3,
|
||
Company: true,
|
||
Manager: true,
|
||
Team: 4,
|
||
Languages: 3,
|
||
Friends: 1,
|
||
})
|
||
|
||
if err := DB.Create(&user).Error; err != nil {
|
||
t.Fatalf("errors happened when create: %v", err)
|
||
}
|
||
|
||
CheckUser(t, user, user)
|
||
|
||
var user2 User
|
||
DB.Preload(clause.Associations).Find(&user2, "id = ?", user.ID)
|
||
CheckUser(t, user2, user)
|
||
|
||
var user3 = *GetUser("preload_with_associations_new", Config{
|
||
Account: true,
|
||
Pets: 2,
|
||
Toys: 3,
|
||
Company: true,
|
||
Manager: true,
|
||
Team: 4,
|
||
Languages: 3,
|
||
Friends: 1,
|
||
})
|
||
|
||
DB.Preload(clause.Associations).Find(&user3, "id = ?", user.ID)
|
||
CheckUser(t, user3, user)
|
||
}
|
||
|
||
func TestNestedPreload(t *testing.T) {
|
||
var user = *GetUser("nested_preload", Config{Pets: 2})
|
||
|
||
for idx, pet := range user.Pets {
|
||
pet.Toy = Toy{Name: "toy_nested_preload_" + strconv.Itoa(idx+1)}
|
||
}
|
||
|
||
if err := DB.Create(&user).Error; err != nil {
|
||
t.Fatalf("errors happened when create: %v", err)
|
||
}
|
||
|
||
var user2 User
|
||
DB.Preload("Pets.Toy").Find(&user2, "id = ?", user.ID)
|
||
|
||
CheckUser(t, user2, user)
|
||
}
|
||
|
||
func TestNestedPreloadForSlice(t *testing.T) {
|
||
var users = []User{
|
||
*GetUser("slice_nested_preload_1", Config{Pets: 2}),
|
||
*GetUser("slice_nested_preload_2", Config{Pets: 0}),
|
||
*GetUser("slice_nested_preload_3", Config{Pets: 3}),
|
||
}
|
||
|
||
for _, user := range users {
|
||
for idx, pet := range user.Pets {
|
||
pet.Toy = Toy{Name: user.Name + "_toy_nested_preload_" + strconv.Itoa(idx+1)}
|
||
}
|
||
}
|
||
|
||
if err := DB.Create(&users).Error; err != nil {
|
||
t.Fatalf("errors happened when create: %v", err)
|
||
}
|
||
|
||
var userIDs []uint
|
||
for _, user := range users {
|
||
userIDs = append(userIDs, user.ID)
|
||
}
|
||
|
||
var users2 []User
|
||
DB.Preload("Pets.Toy").Find(&users2, "id IN ?", userIDs)
|
||
|
||
for idx, user := range users2 {
|
||
CheckUser(t, user, users[idx])
|
||
}
|
||
}
|
||
|
||
func TestPreloadWithConds(t *testing.T) {
|
||
var users = []User{
|
||
*GetUser("slice_nested_preload_1", Config{Account: true}),
|
||
*GetUser("slice_nested_preload_2", Config{Account: false}),
|
||
*GetUser("slice_nested_preload_3", Config{Account: true}),
|
||
}
|
||
|
||
if err := DB.Create(&users).Error; err != nil {
|
||
t.Fatalf("errors happened when create: %v", err)
|
||
}
|
||
|
||
var userIDs []uint
|
||
for _, user := range users {
|
||
userIDs = append(userIDs, user.ID)
|
||
}
|
||
|
||
var users2 []User
|
||
DB.Preload("Account", clause.Eq{Column: "number", Value: users[0].Account.Number}).Find(&users2, "id IN ?", userIDs)
|
||
sort.Slice(users2, func(i, j int) bool {
|
||
return users2[i].ID < users2[j].ID
|
||
})
|
||
|
||
for idx, user := range users2[1:2] {
|
||
if user.Account.Number != "" {
|
||
t.Errorf("No account should found for user %v but got %v", idx+2, user.Account.Number)
|
||
}
|
||
}
|
||
|
||
CheckUser(t, users2[0], users[0])
|
||
|
||
var users3 []User
|
||
if err := DB.Preload("Account", func(tx *gorm.DB) *gorm.DB {
|
||
return tx.Table("accounts AS a").Select("a.*")
|
||
}).Find(&users3, "id IN ?", userIDs).Error; err != nil {
|
||
t.Errorf("failed to query, got error %v", err)
|
||
}
|
||
sort.Slice(users3, func(i, j int) bool {
|
||
return users2[i].ID < users2[j].ID
|
||
})
|
||
|
||
for i, u := range users3 {
|
||
CheckUser(t, u, users[i])
|
||
}
|
||
}
|
||
|
||
func TestNestedPreloadWithConds(t *testing.T) {
|
||
var users = []User{
|
||
*GetUser("slice_nested_preload_1", Config{Pets: 2}),
|
||
*GetUser("slice_nested_preload_2", Config{Pets: 0}),
|
||
*GetUser("slice_nested_preload_3", Config{Pets: 3}),
|
||
}
|
||
|
||
for _, user := range users {
|
||
for idx, pet := range user.Pets {
|
||
pet.Toy = Toy{Name: user.Name + "_toy_nested_preload_" + strconv.Itoa(idx+1)}
|
||
}
|
||
}
|
||
|
||
if err := DB.Create(&users).Error; err != nil {
|
||
t.Fatalf("errors happened when create: %v", err)
|
||
}
|
||
|
||
var userIDs []uint
|
||
for _, user := range users {
|
||
userIDs = append(userIDs, user.ID)
|
||
}
|
||
|
||
var users2 []User
|
||
DB.Preload("Pets.Toy", "name like ?", `%preload_3`).Find(&users2, "id IN ?", userIDs)
|
||
|
||
for idx, user := range users2[0:2] {
|
||
for _, pet := range user.Pets {
|
||
if pet.Toy.Name != "" {
|
||
t.Errorf("No toy should for user %v's pet %v but got %v", idx+1, pet.Name, pet.Toy.Name)
|
||
}
|
||
}
|
||
}
|
||
|
||
if len(users2[2].Pets) != 3 {
|
||
t.Errorf("Invalid pet toys found for user 3 got %v", len(users2[2].Pets))
|
||
} else {
|
||
sort.Slice(users2[2].Pets, func(i, j int) bool {
|
||
return users2[2].Pets[i].ID < users2[2].Pets[j].ID
|
||
})
|
||
|
||
for _, pet := range users2[2].Pets[0:2] {
|
||
if pet.Toy.Name != "" {
|
||
t.Errorf("No toy should for user %v's pet %v but got %v", 3, pet.Name, pet.Toy.Name)
|
||
}
|
||
}
|
||
|
||
CheckPet(t, *users2[2].Pets[2], *users[2].Pets[2])
|
||
}
|
||
}
|
||
|
||
func TestPreloadEmptyData(t *testing.T) {
|
||
var user = *GetUser("user_without_associations", Config{})
|
||
DB.Create(&user)
|
||
|
||
DB.Preload("Team").Preload("Languages").Preload("Friends").First(&user, "name = ?", user.Name)
|
||
|
||
if r, err := json.Marshal(&user); err != nil {
|
||
t.Errorf("failed to marshal users, got error %v", err)
|
||
} else if !regexp.MustCompile(`"Team":\[\],"Languages":\[\],"Friends":\[\]`).MatchString(string(r)) {
|
||
t.Errorf("json marshal is not empty slice, got %v", string(r))
|
||
}
|
||
|
||
var results []User
|
||
DB.Preload("Team").Preload("Languages").Preload("Friends").Find(&results, "name = ?", user.Name)
|
||
|
||
if r, err := json.Marshal(&results); err != nil {
|
||
t.Errorf("failed to marshal users, got error %v", err)
|
||
} else if !regexp.MustCompile(`"Team":\[\],"Languages":\[\],"Friends":\[\]`).MatchString(string(r)) {
|
||
t.Errorf("json marshal is not empty slice, got %v", string(r))
|
||
}
|
||
}
|
||
|
||
// TestPreloadGoroutine goroutine中在没有缓存的情况下使用Preload
|
||
func TestPreloadGoroutine(t *testing.T) {
|
||
// 这里不要用Create,因为会缓存relations
|
||
// 把tests_test.go中init()函数中的RunMigrations()注释掉,数据库中保留一些数据来触发Preload
|
||
var wg sync.WaitGroup
|
||
|
||
DB = DB.Where("id = ?", 1)
|
||
tx := DB.Session(&gorm.Session{})
|
||
|
||
wg.Add(2)
|
||
for i := 0; i < 2; i++ {
|
||
go func() {
|
||
defer wg.Done()
|
||
var user2 []User
|
||
tx = tx.Preload("Team")
|
||
err := tx.Find(&user2).Error
|
||
|
||
ast := assert.New(t)
|
||
// 这里会报错,Team: unsupported relations
|
||
// relations是空的
|
||
ast.Equal(err, nil)
|
||
}()
|
||
}
|
||
wg.Wait()
|
||
}
|
||
|
||
// TestPreloadNotGoroutine 正常情况在没有缓存的时候下使用Preload
|
||
func TestPreloadNotGoroutine(t *testing.T) {
|
||
// 这里不要用Create,因为会缓存relations
|
||
// 把tests_test.go中init()函数中的RunMigrations()注释掉,数据库中保留一些数据来触发Preload
|
||
DB = DB.Where("id = ?", 1)
|
||
tx := DB.Session(&gorm.Session{})
|
||
|
||
var user2 []User
|
||
tx = tx.Preload("Team")
|
||
err := tx.Find(&user2).Error
|
||
|
||
ast := assert.New(t)
|
||
// 这里不会报错
|
||
// relations不是空的
|
||
ast.Equal(err, nil)
|
||
}
|