Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 154 additions & 7 deletions tests/generics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,25 @@ func TestGenericsCreateInBatches(t *testing.T) {
}

found, err := gorm.G[User](DB).Raw("SELECT * FROM \"users\" WHERE \"name\" LIKE ?", "GenericsCreateInBatches%").Find(ctx)
if err != nil {
t.Fatalf("Raw Find failed: %v", err)
}
if len(found) != len(batch) {
t.Errorf("expected %d from Raw Find, got %d", len(batch), len(found))
}

found, err = gorm.G[User](DB).Where("\"name\" like ?", "GenericsCreateInBatches%").Limit(2).Find(ctx)
if err != nil {
t.Fatalf("Raw Find failed: %v", err)
}
if len(found) != 2 {
t.Errorf("expected %d from Raw Find, got %d", 2, len(found))
}

found, err = gorm.G[User](DB).Where("\"name\" like ?", "GenericsCreateInBatches%").Offset(2).Limit(2).Find(ctx)
if err != nil {
t.Fatalf("Raw Find failed: %v", err)
}
if len(found) != 1 {
t.Errorf("expected %d from Raw Find, got %d", 1, len(found))
}
Expand All @@ -168,7 +177,9 @@ func TestGenericsExecAndUpdate(t *testing.T) {

name += "Update"
rows, err := gorm.G[User](DB).Where("\"id\" = ?", u.ID).Update(ctx, "name", name)
if rows != 1 {
if err != nil {
t.Fatalf("Update failed: %v", err)
} else if rows != 1 {
t.Fatalf("failed to get affected rows, got %d, should be %d", rows, 1)
}

Expand All @@ -180,7 +191,9 @@ func TestGenericsExecAndUpdate(t *testing.T) {
}

rows, err = gorm.G[User](DB).Where("\"id\" = ?", u.ID).Updates(ctx, User{Name: "GenericsExecUpdates", Age: 18})
if rows != 1 {
if err != nil {
t.Fatalf("Updates failed: %v", err)
} else if rows != 1 {
t.Fatalf("failed to get affected rows, got %d, should be %d", rows, 1)
}

Expand Down Expand Up @@ -251,6 +264,37 @@ func TestGenericsDelete(t *testing.T) {
if err != gorm.ErrRecordNotFound {
t.Fatalf("User after delete failed: %v", err)
}

u2 := User{Name: "GenericsDeleteCond"}
if err := gorm.G[User](DB).Create(ctx, &u2); err != nil {
t.Fatalf("Create failed: %v", err)
}
rows, err = gorm.G[User](DB).Where("\"name\" = ?", "GenericsDeleteCond").Delete(ctx)
if err != nil {
t.Fatalf("Conditional delete failed: %v", err)
}
if rows != 1 {
t.Fatalf("Conditional delete failed, err=%v, rows=%d", err, rows)
}
_, err = gorm.G[User](DB).Where("\"id\" = ?", u2.ID).First(ctx)
if err != gorm.ErrRecordNotFound {
t.Errorf("Expected deleted record to be gone, got: %v", err)
}

users := []User{
{Name: "GenericsBatchDel1"},
{Name: "GenericsBatchDel2"},
}
if err := gorm.G[User](DB).CreateInBatches(ctx, &users, 2); err != nil {
t.Fatalf("Batch create for delete failed: %v", err)
}
rows, err = gorm.G[User](DB).Where("\"name\" LIKE ?", "GenericsBatchDel%").Delete(ctx)
if err != nil {
t.Fatalf("Batch delete failed: %v", err)
}
if rows != 2 {
t.Errorf("batch delete expected 2 rows, got %d", rows)
}
}

func TestGenericsFindInBatches(t *testing.T) {
Expand Down Expand Up @@ -301,20 +345,23 @@ func TestGenericsScopes(t *testing.T) {
results, err := gorm.G[User](DB).Scopes(filterName1).Find(ctx)
if err != nil {
t.Fatalf("Scopes failed: %v", err)
}
if len(results) != 1 || results[0].Name != "GenericsScopes1" {
} else if len(results) != 1 || results[0].Name != "GenericsScopes1" {
t.Fatalf("Scopes expected 1, got %d", len(results))
}

notResult, err := gorm.G[User](DB).Where("\"name\" like ?", "GenericsScopes%").Not("\"name\" = ?", "GenericsScopes1").Order("\"name\"").Find(ctx)
if len(notResult) != 2 {
if err != nil {
t.Fatalf("Not failed: %v", err)
} else if len(notResult) != 2 {
t.Fatalf("expected 2 results, got %d", len(notResult))
} else if notResult[0].Name != "GenericsScopes2" || notResult[1].Name != "GenericsScopes3" {
t.Fatalf("expected names 'GenericsScopes2' and 'GenericsScopes3', got %s and %s", notResult[0].Name, notResult[1].Name)
}

orResult, err := gorm.G[User](DB).Or("\"name\" = ?", "GenericsScopes1").Or("\"name\" = ?", "GenericsScopes2").Order("\"name\"").Find(ctx)
if len(orResult) != 2 {
if err != nil {
t.Fatalf("Or failed: %v", err)
} else if len(orResult) != 2 {
t.Fatalf("expected 2 results, got %d", len(notResult))
} else if orResult[0].Name != "GenericsScopes1" || orResult[1].Name != "GenericsScopes2" {
t.Fatalf("expected names 'GenericsScopes2' and 'GenericsScopes3', got %s and %s", orResult[0].Name, orResult[1].Name)
Expand Down Expand Up @@ -554,6 +601,9 @@ func TestGenericsPreloads(t *testing.T) {
return nil
}).Where("\"name\" in ?", names).Find(ctx)

if err != nil {
t.Fatalf("Preload failed: %v", err)
}
for _, result := range results {
if result.Name == u.Name {
if len(result.Pets) != len(u.Pets) {
Expand All @@ -577,6 +627,9 @@ func TestGenericsPreloads(t *testing.T) {
return nil
}).Where("\"name\" in ?", names).Find(ctx)

if err != nil {
t.Fatalf("Preload failed: %v", err)
}
for _, result := range results {
if result.Name == u.Name {
if len(result.Pets) != len(u.Pets) {
Expand Down Expand Up @@ -608,6 +661,9 @@ func TestGenericsPreloads(t *testing.T) {
return nil
}).Where("\"name\" in ?", names).Find(ctx)

if err != nil {
t.Fatalf("Preload failed: %v", err)
}
for _, result := range results {
if result.Name == u.Name {
if len(result.Pets) != len(u.Pets) {
Expand Down Expand Up @@ -868,6 +924,9 @@ func TestGenericsWithTransaction(t *testing.T) {

users := []User{{Name: "TestGenericsTransaction", Age: 18}, {Name: "TestGenericsTransaction2", Age: 18}}
err := gorm.G[User](tx).CreateInBatches(ctx, &users, 2)
if err != nil {
t.Fatalf("CreateInBatches failed: %v", err)
}

count, err := gorm.G[User](tx).Where("\"name\" like ?", "TestGenericsTransaction%").Count(ctx, "*")
if err != nil {
Expand Down Expand Up @@ -897,7 +956,95 @@ func TestGenericsToSQL(t *testing.T) {
return tx
})

if !regexp.MustCompile("SELECT \\* FROM .users..* 10").MatchString(sql) {
if !regexp.MustCompile(`SELECT \* FROM .users..* 10`).MatchString(sql) {
t.Errorf("ToSQL: got wrong sql with Generics API %v", sql)
}
}

func TestGenericsCountOmitSelect(t *testing.T) {
ctx := context.Background()
users := []User{{Name: "GenericsCount1", Age: 5}, {Name: "GenericsCount2", Age: 7}}
err := gorm.G[User](DB).CreateInBatches(ctx, &users, 2)
if err != nil {
t.Fatalf("CreateInBatches failed: %v", err)
}
count, err := gorm.G[User](DB).Omit("age").Where("\"name\" LIKE ?", "GenericsCount%").Count(ctx, "*")
if err != nil {
t.Fatalf("Count failed: %v", err)
}
if count != 2 {
t.Errorf("Count with Omit: expected 2, got %d", count)
}
}

func TestGenericsSelectAndOmitFind(t *testing.T) {
ctx := context.Background()
u := User{Name: "GenericsSelectOmit", Age: 30}
err := gorm.G[User](DB).Create(ctx, &u)
if err != nil {
t.Fatalf("Create failed: %v", err)
}
result, err := gorm.G[User](DB).Select("id").Omit("age").Where("\"name\" = ?", u.Name).First(ctx)
if err != nil {
t.Fatalf("Select and Omit Find failed: %v", err)
}
if result.ID != u.ID || result.Name != "" || result.Age != 0 {
t.Errorf("SelectAndOmitFind expects partial zero values, got: %+v", result)
}
}

func TestGenericsSelectWithPreloadAssociations(t *testing.T) {
ctx := context.Background()
user := User{Name: "SelectPreloadCombo", Age: 40, Company: Company{Name: "ComboCompany"}}
for i := 1; i <= 2; i++ {
user.Pets = append(user.Pets, &Pet{Name: fmt.Sprintf("Pet-%d", i)})
}
if err := gorm.G[User](DB).Create(ctx, &user); err != nil {
t.Fatalf("Create failed: %v", err)
}
result, err := gorm.G[User](DB).Select("id", "name", "company_id").Preload("Company", nil).Preload("Pets", nil).Where("\"name\" = ?", user.Name).First(ctx)
if err != nil {
t.Fatalf("Select+Preload First failed: %v", err)
}
if result.ID == 0 || result.Name == "" {
t.Errorf("Expected user id/name; got: %+v", result)
}
if result.Age != 0 {
t.Errorf("Expected omitted Age=0, got %d", result.Age)
}
if result.Company.Name != user.Company.Name {
t.Errorf("Expected company %+v, got %+v", user.Company, result.Company)
}
if len(result.Pets) != len(user.Pets) {
t.Errorf("Expected %d pets, got %d", len(user.Pets), len(result.Pets))
}
}

func TestGenericsTransactionRollbackOnPreloadError(t *testing.T) {
ctx := context.Background()
tx := DB.Begin()
if tx.Error != nil {
t.Fatalf("Failed to begin transaction: %v", tx.Error)
}
user := User{Name: "TxRollbackPreload", Age: 25, Company: Company{Name: "TxCompany"}}
if err := gorm.G[User](tx).Create(ctx, &user); err != nil {
_ = tx.Rollback()
t.Fatalf("Failed to create user in tx: %v", err)
}
var gotErr error
_, gotErr = gorm.G[User](tx).
Preload("Company", func(db gorm.PreloadBuilder) error { return fmt.Errorf("bad preload") }).
Where("\"name\" = ?", user.Name).
First(ctx)
errRollback := tx.Rollback().Error
if gotErr == nil {
t.Errorf("Expected preload error, got nil")
}
if errRollback != nil {
t.Fatalf("Failed to rollback on Preload error: %v", errRollback)
}
_, err := gorm.G[User](DB).Where("\"name\" = ?", user.Name).First(ctx)
if err == nil {
t.Errorf("Expected no user after rollback, but found one")
}
}
128 changes: 124 additions & 4 deletions tests/gorm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,20 @@ import (
)

func TestOpen(t *testing.T) {
dsn := "gorm:gorm@tcp(localhost:9910)/gorm?loc=Asia%2FHongKong" // invalid loc
_, err := gorm.Open(oracle.Open(dsn), &gorm.Config{})
if err == nil {
t.Fatalf("should returns error but got nil")
dsns := []string{
"gorm@localhost:9910/invalid",
"gorm:gorm@localhost:9910",
"invalid_dsn_string",
"gorm:gorm@tcp(localhost:9910)/gorm?loc=Asia%2FHongKong",
"gorm@localhost:2300/invalid_service",
"gorm@localhost:invalid_port/cdb1_pdb1",
"gorm@invalid_host:1111/cdb1_pdb1",
}
for _, dsn := range dsns {
_, err := gorm.Open(oracle.Open(dsn), &gorm.Config{})
if err == nil {
t.Errorf("should return error for dsn=%q but got nil", dsn)
}
}
}

Expand Down Expand Up @@ -130,3 +140,113 @@ func TestReturningWithNullToZeroValues(t *testing.T) {
t.Fatalf("rows affected expects: %v, got %v", 1, results.RowsAffected)
}
}

func TestReturningWithNullAndAdditionalFields(t *testing.T) {
type userWithFields struct {
gorm.Model
Name string `gorm:"default:noname"`
Age int
Comment string
}

DB.Migrator().DropTable(&userWithFields{})
DB.Migrator().AutoMigrate(&userWithFields{})

// Insert a user and verify defaults
u := userWithFields{}
if results := DB.Create(&u); results.Error != nil {
t.Fatalf("errors happened on create: %v", results.Error)
} else if results.RowsAffected != 1 {
t.Fatalf("rows affected expects: %v, got %v", 1, results.RowsAffected)
} else if u.ID == 0 || u.Name != "noname" || u.Age != 0 || u.Comment != "" {
t.Fatalf("create expects ID!=0, Name='noname', Age=0, Comment='', got %+v", u)
}

// Update all fields and verify
u.Name = "TestName"
u.Age = 42
u.Comment = "Hello"
if results := DB.Save(&u); results.Error != nil {
t.Fatalf("errors happened on update: %v", results.Error)
} else if results.RowsAffected != 1 {
t.Fatalf("rows affected expects: %v, got %v", 1, results.RowsAffected)
} else if u.Name != "TestName" || u.Age != 42 || u.Comment != "Hello" {
t.Fatalf("update expects Name='TestName', Age=42, Comment='Hello', got %+v", u)
}

// Fetch and verify
got := userWithFields{}
results := DB.First(&got, "\"id\" = ?", u.ID)
if results.Error != nil {
t.Fatalf("errors happened on first: %v", results.Error)
} else if results.RowsAffected != 1 {
t.Fatalf("rows affected expects: %v, got %v", 1, results.RowsAffected)
} else if got.ID != u.ID || got.Name != "TestName" || got.Age != 42 || got.Comment != "Hello" {
t.Fatalf("first expects %+v, got %+v", u, got)
}

// Batch create and check
u1 := userWithFields{}
u2 := userWithFields{Name: "foo"}
u3 := userWithFields{Name: "bar", Age: 99, Comment: "bar-comment"}
db := DB.Session(&gorm.Session{CreateBatchSize: 10})
if results := db.Create([]*userWithFields{&u1, &u2, &u3}); results.Error != nil {
t.Fatalf("errors happened on create: %v", results.Error)
} else if results.RowsAffected != 3 {
t.Fatalf("rows affected expects: %v, got %v", 3, results.RowsAffected)
} else if u1.ID == 0 || u2.ID == 0 || u3.ID == 0 {
t.Fatalf("ID expects : not equal 0, got %v,%v,%v", u1.ID, u2.ID, u3.ID)
} else if u1.Name != "noname" || u2.Name != "foo" || u3.Name != "bar" {
t.Fatalf("names expect: noname, foo, bar, got: %q,%q,%q", u1.Name, u2.Name, u3.Name)
} else if u1.Age != 0 || u2.Age != 0 || u3.Age != 99 {
t.Fatalf("ages expect: 0,0,99, got: %v,%v,%v", u1.Age, u2.Age, u3.Age)
} else if u1.Comment != "" || u2.Comment != "" || u3.Comment != "bar-comment" {
t.Fatalf("comments expect: '', '', 'bar-comment', got: %q,%q,%q", u1.Comment, u2.Comment, u3.Comment)
}

// Batch update and check
u1.Name = "A"
u2.Name = "B"
u3.Comment = "updated"
if results := DB.Save([]*userWithFields{&u1, &u2, &u3}); results.Error != nil {
t.Fatalf("errors happened on update: %v", results.Error)
} else if results.RowsAffected != 3 {
t.Fatalf("rows affected expects: %v, got %v", 3, results.RowsAffected)
} else if u1.Name != "A" || u2.Name != "B" || u3.Name != "bar" {
t.Fatalf("names expect: A, B, bar, got: %q,%q,%q", u1.Name, u2.Name, u3.Name)
} else if u1.Age != 0 || u2.Age != 0 || u3.Age != 99 {
t.Fatalf("ages expect: 0,0,99, got: %v,%v,%v", u1.Age, u2.Age, u3.Age)
} else if u1.Comment != "" || u2.Comment != "" || u3.Comment != "updated" {
t.Fatalf("comments expect: '', '', 'updated', got: %q,%q,%q", u1.Comment, u2.Comment, u3.Comment)
}

// Batch fetch and verify
updated := []userWithFields{}
results = DB.Where("\"id\" in (?, ?, ?)", u1.ID, u2.ID, u3.ID).Order("\"id\" asc").Find(&updated)
if results.Error != nil {
t.Fatalf("errors happened on batch find: %v", results.Error)
} else if results.RowsAffected != 3 {
t.Fatalf("rows affected expects: %v, got %v", 3, results.RowsAffected)
} else if len(updated) != 3 {
t.Fatalf("batch find expects: %v records, got %v", 3, len(updated))
} else if updated[0].ID != u1.ID || updated[1].ID != u2.ID || updated[2].ID != u3.ID {
t.Fatalf("batch find expects IDs: %v,%v,%v, got: %v,%v,%v", u1.ID, u2.ID, u3.ID, updated[0].ID, updated[1].ID, updated[2].ID)
} else if updated[0].Name != "A" || updated[1].Name != "B" || updated[2].Name != "bar" {
t.Fatalf("batch find expects Names: A,B,bar, got: %q,%q,%q", updated[0].Name, updated[1].Name, updated[2].Name)
} else if updated[0].Age != 0 || updated[1].Age != 0 || updated[2].Age != 99 {
t.Fatalf("batch find expects Ages: 0,0,99, got: %v,%v,%v", updated[0].Age, updated[1].Age, updated[2].Age)
} else if updated[0].Comment != "" || updated[1].Comment != "" || updated[2].Comment != "updated" {
t.Fatalf("batch find expects Comments: '', '', 'updated', got: %q,%q,%q", updated[0].Comment, updated[1].Comment, updated[2].Comment)
}

// Delete and verify one user
if err := DB.Delete(&userWithFields{}, u2.ID).Error; err != nil {
t.Fatalf("Delete failed: %v", err)
}
var deleted userWithFields
if err := DB.First(&deleted, u2.ID).Error; err == nil {
t.Fatalf("Deleted user with ID=%d found", u2.ID)
}

DB.Migrator().DropTable(&userWithFields{})
}
Loading