gorm/tests/preload_test.go

261 lines
6.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}