stardb/testing/orm_test.go
2026-03-07 19:27:44 +08:00

692 lines
14 KiB
Go

package testing
import (
"context"
"testing"
"time"
)
type User struct {
ID int64 `db:"id"`
Name string `db:"name"`
Email string `db:"email"`
Age int `db:"age"`
Balance float64 `db:"balance"`
Active bool `db:"active"`
CreatedAt time.Time `db:"created_at"`
}
type Profile struct {
UserID int `db:"user_id"`
Bio string `db:"bio"`
Avatar string `db:"avatar"`
}
type NestedUser struct {
ID int64 `db:"id"`
Name string `db:"name"`
Profile `db:"---"`
}
func TestStarRows_Orm_Single(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
rows, err := db.Query("SELECT * FROM users WHERE name = ?", "Alice")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
var user User
err = rows.Orm(&user)
if err != nil {
t.Fatalf("Orm failed: %v", err)
}
if user.Name != "Alice" {
t.Errorf("Expected name 'Alice', got '%s'", user.Name)
}
if user.Email != "alice@example.com" {
t.Errorf("Expected email 'alice@example.com', got '%s'", user.Email)
}
if user.Age != 25 {
t.Errorf("Expected age 25, got %d", user.Age)
}
if user.Balance != 100.50 {
t.Errorf("Expected balance 100.50, got %f", user.Balance)
}
if !user.Active {
t.Errorf("Expected user to be active")
}
}
func TestStarRows_Orm_Multiple(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
rows, err := db.Query("SELECT * FROM users ORDER BY name")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
var users []User
err = rows.Orm(&users)
if err != nil {
t.Fatalf("Orm failed: %v", err)
}
if len(users) != 3 {
t.Fatalf("Expected 3 users, got %d", len(users))
}
expectedNames := []string{"Alice", "Bob", "Charlie"}
for i, user := range users {
if user.Name != expectedNames[i] {
t.Errorf("Expected name '%s', got '%s'", expectedNames[i], user.Name)
}
}
}
func TestStarRows_Orm_Empty(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
rows, err := db.Query("SELECT * FROM users WHERE name = ?", "NonExistent")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
var users []User
err = rows.Orm(&users)
if err != nil {
t.Fatalf("Orm failed: %v", err)
}
if len(users) != 0 {
t.Errorf("Expected 0 users, got %d", len(users))
}
}
func TestStarRows_Orm_NotPointer(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
rows, err := db.Query("SELECT * FROM users WHERE name = ?", "Alice")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
var user User
err = rows.Orm(user) // Not a pointer
if err == nil {
t.Errorf("Expected error when passing non-pointer, got nil")
}
}
func TestStarDB_Insert(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
user := User{
Name: "David",
Email: "david@example.com",
Age: 40,
Balance: 400.00,
Active: true,
CreatedAt: time.Now(),
}
result, err := db.Insert(&user, "users", "id")
if err != nil {
t.Fatalf("Insert failed: %v", err)
}
lastID, err := result.LastInsertId()
if err != nil {
t.Fatalf("LastInsertId failed: %v", err)
}
if lastID <= 0 {
t.Errorf("Expected positive last insert ID, got %d", lastID)
}
// Verify insertion
rows, err := db.Query("SELECT * FROM users WHERE name = ?", "David")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
var insertedUser User
err = rows.Orm(&insertedUser)
if err != nil {
t.Fatalf("Orm failed: %v", err)
}
if insertedUser.Name != "David" {
t.Errorf("Expected name 'David', got '%s'", insertedUser.Name)
}
if insertedUser.Email != "david@example.com" {
t.Errorf("Expected email 'david@example.com', got '%s'", insertedUser.Email)
}
if insertedUser.Age != 40 {
t.Errorf("Expected age 40, got %d", insertedUser.Age)
}
}
func TestStarDB_InsertContext(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
ctx := context.Background()
user := User{
Name: "Eve",
Email: "eve@example.com",
Age: 28,
Balance: 250.00,
Active: true,
CreatedAt: time.Now(),
}
result, err := db.InsertContext(ctx, &user, "users", "id")
if err != nil {
t.Fatalf("InsertContext failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 1 {
t.Errorf("Expected 1 row affected, got %d", affected)
}
}
func TestStarDB_Update(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
// First, get the user
rows, err := db.Query("SELECT * FROM users WHERE name = ?", "Alice")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
var user User
err = rows.Orm(&user)
if err != nil {
t.Fatalf("Orm failed: %v", err)
}
// Update the user
user.Age = 26
user.Balance = 150.75
result, err := db.Update(&user, "users", "id")
if err != nil {
t.Fatalf("Update failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 1 {
t.Errorf("Expected 1 row affected, got %d", affected)
}
// Verify the update
rows2, err := db.Query("SELECT * FROM users WHERE id = ?", user.ID)
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows2.Close()
var updatedUser User
err = rows2.Orm(&updatedUser)
if err != nil {
t.Fatalf("Orm failed: %v", err)
}
if updatedUser.Age != 26 {
t.Errorf("Expected age 26, got %d", updatedUser.Age)
}
if updatedUser.Balance != 150.75 {
t.Errorf("Expected balance 150.75, got %f", updatedUser.Balance)
}
}
func TestStarDB_UpdateContext(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
ctx := context.Background()
// Get user
rows, err := db.Query("SELECT * FROM users WHERE name = ?", "Bob")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
var user User
err = rows.Orm(&user)
if err != nil {
t.Fatalf("Orm failed: %v", err)
}
// Update
user.Active = false
result, err := db.UpdateContext(ctx, &user, "users", "id")
if err != nil {
t.Fatalf("UpdateContext failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 1 {
t.Errorf("Expected 1 row affected, got %d", affected)
}
}
func TestStarDB_QueryX(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
user := User{
Name: "Alice",
}
rows, err := db.QueryX(&user, "SELECT * FROM users WHERE name = ?", ":name")
if err != nil {
t.Fatalf("QueryX failed: %v", err)
}
defer rows.Close()
if rows.Length() != 1 {
t.Errorf("Expected 1 row, got %d", rows.Length())
}
var result User
err = rows.Orm(&result)
if err != nil {
t.Fatalf("Orm failed: %v", err)
}
if result.Name != "Alice" {
t.Errorf("Expected name 'Alice', got '%s'", result.Name)
}
}
func TestStarDB_QueryXContext(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
ctx := context.Background()
user := User{
Age: 30,
}
rows, err := db.QueryXContext(ctx, &user, "SELECT * FROM users WHERE age = ?", ":age")
if err != nil {
t.Fatalf("QueryXContext failed: %v", err)
}
defer rows.Close()
if rows.Length() != 1 {
t.Errorf("Expected 1 row, got %d", rows.Length())
}
}
func TestStarDB_QueryXS(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
users := []User{
{Name: "Alice"},
{Name: "Bob"},
}
results, err := db.QueryXS(&users, "SELECT * FROM users WHERE name = ?", ":name")
if err != nil {
t.Fatalf("QueryXS failed: %v", err)
}
if len(results) != 2 {
t.Errorf("Expected 2 results, got %d", len(results))
}
for i, rows := range results {
if rows.Length() != 1 {
t.Errorf("Expected 1 row in result %d, got %d", i, rows.Length())
}
}
}
func TestStarDB_ExecX(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
user := User{
Name: "Alice",
Age: 99,
}
result, err := db.ExecX(&user, "UPDATE users SET age = ? WHERE name = ?", ":age", ":name")
if err != nil {
t.Fatalf("ExecX failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 1 {
t.Errorf("Expected 1 row affected, got %d", affected)
}
// Verify
rows, err := db.Query("SELECT age FROM users WHERE name = ?", "Alice")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
age := rows.Row(0).MustInt("age")
if age != 99 {
t.Errorf("Expected age 99, got %d", age)
}
}
func TestStarDB_ExecXContext(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
ctx := context.Background()
user := User{
Name: "Bob",
Active: false,
}
result, err := db.ExecXContext(ctx, &user, "UPDATE users SET active = ? WHERE name = ?", ":active", ":name")
if err != nil {
t.Fatalf("ExecXContext failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 1 {
t.Errorf("Expected 1 row affected, got %d", affected)
}
}
func TestStarDB_ExecXS(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
users := []User{
{Name: "Alice", Age: 26},
{Name: "Bob", Age: 31},
}
results, err := db.ExecXS(&users, "UPDATE users SET age = ? WHERE name = ?", ":age", ":name")
if err != nil {
t.Fatalf("ExecXS failed: %v", err)
}
if len(results) != 2 {
t.Errorf("Expected 2 results, got %d", len(results))
}
for i, result := range results {
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed for result %d: %v", i, err)
}
if affected != 1 {
t.Errorf("Expected 1 row affected in result %d, got %d", i, affected)
}
}
}
func TestStarTx_Insert(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
tx, err := db.Begin()
if err != nil {
t.Fatalf("Begin failed: %v", err)
}
user := User{
Name: "Frank",
Email: "frank@example.com",
Age: 45,
Balance: 500.00,
Active: true,
CreatedAt: time.Now(),
}
result, err := tx.Insert(&user, "users", "id")
if err != nil {
tx.Rollback()
t.Fatalf("Tx.Insert failed: %v", err)
}
err = tx.Commit()
if err != nil {
t.Fatalf("Commit failed: %v", err)
}
lastID, err := result.LastInsertId()
if err != nil {
t.Fatalf("LastInsertId failed: %v", err)
}
if lastID <= 0 {
t.Errorf("Expected positive last insert ID, got %d", lastID)
}
// Verify
rows, err := db.Query("SELECT * FROM users WHERE name = ?", "Frank")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
if rows.Length() != 1 {
t.Errorf("Expected 1 row, got %d", rows.Length())
}
}
func TestStarTx_Update(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
tx, err := db.Begin()
if err != nil {
t.Fatalf("Begin failed: %v", err)
}
// Get user
rows, err := tx.Query("SELECT * FROM users WHERE name = ?", "Alice")
if err != nil {
tx.Rollback()
t.Fatalf("Query failed: %v", err)
}
var user User
err = rows.Orm(&user)
rows.Close()
if err != nil {
tx.Rollback()
t.Fatalf("Orm failed: %v", err)
}
// Update
user.Age = 27
result, err := tx.Update(&user, "users", "id")
if err != nil {
tx.Rollback()
t.Fatalf("Tx.Update failed: %v", err)
}
err = tx.Commit()
if err != nil {
t.Fatalf("Commit failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 1 {
t.Errorf("Expected 1 row affected, got %d", affected)
}
}
func TestStarTx_QueryX(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
tx, err := db.Begin()
if err != nil {
t.Fatalf("Begin failed: %v", err)
}
defer tx.Rollback()
user := User{
Name: "Charlie",
}
rows, err := tx.QueryX(&user, "SELECT * FROM users WHERE name = ?", ":name")
if err != nil {
t.Fatalf("Tx.QueryX failed: %v", err)
}
defer rows.Close()
if rows.Length() != 1 {
t.Errorf("Expected 1 row, got %d", rows.Length())
}
}
func TestStarTx_ExecX(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
tx, err := db.Begin()
if err != nil {
t.Fatalf("Begin failed: %v", err)
}
user := User{
Name: "Charlie",
Age: 36,
}
result, err := tx.ExecX(&user, "UPDATE users SET age = ? WHERE name = ?", ":age", ":name")
if err != nil {
tx.Rollback()
t.Fatalf("Tx.ExecX failed: %v", err)
}
err = tx.Commit()
if err != nil {
t.Fatalf("Commit failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 1 {
t.Errorf("Expected 1 row affected, got %d", affected)
}
}
func TestStarTx_Rollback(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
tx, err := db.Begin()
if err != nil {
t.Fatalf("Begin failed: %v", err)
}
user := User{
Name: "Rollback User",
Email: "rollback@example.com",
Age: 50,
Balance: 600.00,
Active: true,
CreatedAt: time.Now(),
}
_, err = tx.Insert(&user, "users", "id")
if err != nil {
tx.Rollback()
t.Fatalf("Tx.Insert failed: %v", err)
}
// Rollback instead of commit
err = tx.Rollback()
if err != nil {
t.Fatalf("Rollback failed: %v", err)
}
// Verify the insert was rolled back
rows, err := db.Query("SELECT * FROM users WHERE name = ?", "Rollback User")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
if rows.Length() != 0 {
t.Errorf("Expected 0 rows after rollback, got %d", rows.Length())
}
}
func TestNamedParameterEscape(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
user := User{
Name: "Alice",
}
// Test escaped colon
rows, err := db.QueryX(&user, "SELECT * FROM users WHERE name = ?", `\:name`)
if err != nil {
t.Fatalf("QueryX with escaped parameter failed: %v", err)
}
defer rows.Close()
// Should use literal ":name" string, not the field value
if rows.Length() != 0 {
t.Errorf("Expected 0 rows with literal ':name', got %d", rows.Length())
}
}