889 lines
22 KiB
Go
889 lines
22 KiB
Go
package testing
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"b612.me/stardb"
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
type TestUser struct {
|
|
ID int64 `db:"id"`
|
|
Name string `db:"name"`
|
|
Email string `db:"email"`
|
|
Age int `db:"age"`
|
|
CreatedAt time.Time `db:"created_at"`
|
|
}
|
|
|
|
func setupBatchTestDB(t *testing.T) *stardb.StarDB {
|
|
db := stardb.NewStarDB()
|
|
err := db.Open("sqlite", ":memory:")
|
|
if err != nil {
|
|
t.Fatalf("Failed to open database: %v", err)
|
|
}
|
|
|
|
_, err = db.Exec(`
|
|
CREATE TABLE users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
email TEXT NOT NULL,
|
|
age INTEGER,
|
|
created_at DATETIME
|
|
)
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create table: %v", err)
|
|
}
|
|
|
|
return db
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_Basic(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
{"Bob", "bob@example.com", 30},
|
|
{"Charlie", "charlie@example.com", 35},
|
|
}
|
|
|
|
result, err := db.BatchInsert("users", columns, values)
|
|
if err != nil {
|
|
t.Fatalf("BatchInsert failed: %v", err)
|
|
}
|
|
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
t.Fatalf("RowsAffected failed: %v", err)
|
|
}
|
|
|
|
if affected != 3 {
|
|
t.Errorf("Expected 3 rows affected, got %d", affected)
|
|
}
|
|
|
|
// Verify insertion
|
|
rows, err := db.Query("SELECT COUNT(*) as count FROM users")
|
|
if err != nil {
|
|
t.Fatalf("Query failed: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
count := rows.Row(0).MustInt("count")
|
|
if count != 3 {
|
|
t.Errorf("Expected 3 rows in database, got %d", count)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_Single(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
}
|
|
|
|
result, err := db.BatchInsert("users", columns, values)
|
|
if err != nil {
|
|
t.Fatalf("BatchInsert 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_BatchInsert_Empty(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{}
|
|
|
|
_, err := db.BatchInsert("users", columns, values)
|
|
if !errors.Is(err, stardb.ErrNoInsertValues) {
|
|
t.Errorf("Expected ErrNoInsertValues, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_EmptyColumns(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
values := [][]interface{}{
|
|
{"Alice"},
|
|
}
|
|
|
|
_, err := db.BatchInsert("users", nil, values)
|
|
if !errors.Is(err, stardb.ErrNoInsertColumns) {
|
|
t.Errorf("Expected ErrNoInsertColumns, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_EmptyTableName(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
}
|
|
|
|
_, err := db.BatchInsert("", columns, values)
|
|
if !errors.Is(err, stardb.ErrTableNameEmpty) {
|
|
t.Errorf("Expected ErrTableNameEmpty, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_RowLengthMismatch(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
{"Bob", "bob@example.com"},
|
|
}
|
|
|
|
_, err := db.BatchInsert("users", columns, values)
|
|
if !errors.Is(err, stardb.ErrBatchRowValueCountMismatch) {
|
|
t.Errorf("Expected ErrBatchRowValueCountMismatch, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_Large(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
var values [][]interface{}
|
|
|
|
// Insert 100 rows
|
|
for i := 0; i < 100; i++ {
|
|
values = append(values, []interface{}{
|
|
"User" + string(rune(i)),
|
|
"user" + string(rune(i)) + "@example.com",
|
|
20 + i%50,
|
|
})
|
|
}
|
|
|
|
result, err := db.BatchInsert("users", columns, values)
|
|
if err != nil {
|
|
t.Fatalf("BatchInsert failed: %v", err)
|
|
}
|
|
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
t.Fatalf("RowsAffected failed: %v", err)
|
|
}
|
|
|
|
if affected != 100 {
|
|
t.Errorf("Expected 100 rows affected, got %d", affected)
|
|
}
|
|
|
|
// Verify
|
|
rows, err := db.Query("SELECT COUNT(*) as count FROM users")
|
|
if err != nil {
|
|
t.Fatalf("Query failed: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
count := rows.Row(0).MustInt("count")
|
|
if count != 100 {
|
|
t.Errorf("Expected 100 rows in database, got %d", count)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertContext(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
ctx := context.Background()
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
{"Bob", "bob@example.com", 30},
|
|
}
|
|
|
|
result, err := db.BatchInsertContext(ctx, "users", columns, values)
|
|
if err != nil {
|
|
t.Fatalf("BatchInsertContext failed: %v", err)
|
|
}
|
|
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
t.Fatalf("RowsAffected failed: %v", err)
|
|
}
|
|
|
|
if affected != 2 {
|
|
t.Errorf("Expected 2 rows affected, got %d", affected)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertContext_Timeout(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
|
|
defer cancel()
|
|
|
|
time.Sleep(10 * time.Millisecond) // Ensure timeout
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
}
|
|
|
|
_, err := db.BatchInsertContext(ctx, "users", columns, values)
|
|
if err == nil {
|
|
t.Error("Expected timeout error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertMaxRows_Config(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
if got := db.BatchInsertMaxRows(); got != 0 {
|
|
t.Fatalf("Expected default chunk size 0, got %d", got)
|
|
}
|
|
|
|
db.SetBatchInsertMaxRows(3)
|
|
if got := db.BatchInsertMaxRows(); got != 3 {
|
|
t.Fatalf("Expected chunk size 3, got %d", got)
|
|
}
|
|
|
|
db.SetBatchInsertMaxRows(-10)
|
|
if got := db.BatchInsertMaxRows(); got != 0 {
|
|
t.Fatalf("Expected chunk size reset to 0, got %d", got)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertMaxParams_Config(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
if got := db.BatchInsertMaxParams(); got != 0 {
|
|
t.Fatalf("Expected default max params 0, got %d", got)
|
|
}
|
|
|
|
db.SetBatchInsertMaxParams(100)
|
|
if got := db.BatchInsertMaxParams(); got != 100 {
|
|
t.Fatalf("Expected max params 100, got %d", got)
|
|
}
|
|
|
|
db.SetBatchInsertMaxParams(-1)
|
|
if got := db.BatchInsertMaxParams(); got != 0 {
|
|
t.Fatalf("Expected max params reset to 0, got %d", got)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_Chunked(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
db.SetBatchInsertMaxRows(2)
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
{"Bob", "bob@example.com", 30},
|
|
{"Charlie", "charlie@example.com", 35},
|
|
{"David", "david@example.com", 40},
|
|
{"Eva", "eva@example.com", 28},
|
|
}
|
|
|
|
result, err := db.BatchInsert("users", columns, values)
|
|
if err != nil {
|
|
t.Fatalf("Chunked BatchInsert failed: %v", err)
|
|
}
|
|
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
t.Fatalf("RowsAffected failed: %v", err)
|
|
}
|
|
if affected != int64(len(values)) {
|
|
t.Fatalf("Expected %d affected rows, got %d", len(values), affected)
|
|
}
|
|
|
|
rows, err := db.Query("SELECT COUNT(*) as count FROM users")
|
|
if err != nil {
|
|
t.Fatalf("Query failed: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
if count := rows.Row(0).MustInt("count"); count != len(values) {
|
|
t.Fatalf("Expected %d rows in db, got %d", len(values), count)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_ChunkedRollbackOnError(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
db.SetBatchInsertMaxRows(2)
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
{"Bob", "bob@example.com", 30},
|
|
{"Charlie", nil, 35}, // email NOT NULL, forces second chunk failure
|
|
}
|
|
|
|
if _, err := db.BatchInsert("users", columns, values); err == nil {
|
|
t.Fatal("Expected chunked BatchInsert to fail, got nil")
|
|
}
|
|
|
|
rows, err := db.Query("SELECT COUNT(*) as count FROM users")
|
|
if err != nil {
|
|
t.Fatalf("Query failed: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
if count := rows.Row(0).MustInt("count"); count != 0 {
|
|
t.Fatalf("Expected rollback to keep table empty, got %d rows", count)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_ChunkedByMaxParams(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
db.SetBatchInsertMaxRows(0) // disabled
|
|
db.SetBatchInsertMaxParams(4) // 3 columns -> 1 row per chunk
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
{"Bob", "bob@example.com", 30},
|
|
{"Charlie", "charlie@example.com", 35},
|
|
}
|
|
|
|
result, err := db.BatchInsert("users", columns, values)
|
|
if err != nil {
|
|
t.Fatalf("BatchInsert by max params failed: %v", err)
|
|
}
|
|
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
t.Fatalf("RowsAffected failed: %v", err)
|
|
}
|
|
if affected != int64(len(values)) {
|
|
t.Fatalf("Expected %d affected rows, got %d", len(values), affected)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_MaxParamsTooLow(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
db.SetBatchInsertMaxRows(0)
|
|
db.SetBatchInsertMaxParams(2) // columns=3 -> invalid
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
}
|
|
|
|
_, err := db.BatchInsert("users", columns, values)
|
|
if !errors.Is(err, stardb.ErrBatchInsertMaxParamsTooLow) {
|
|
t.Fatalf("Expected ErrBatchInsertMaxParamsTooLow, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_ChunkedHookMeta(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
db.SetBatchInsertMaxRows(2)
|
|
db.SetBatchInsertMaxParams(0)
|
|
|
|
var metas []stardb.BatchExecMeta
|
|
db.SetSQLHooks(nil, func(ctx context.Context, query string, args []interface{}, d time.Duration, err error) {
|
|
if meta, ok := stardb.BatchExecMetaFromContext(ctx); ok {
|
|
metas = append(metas, meta)
|
|
}
|
|
})
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
{"Bob", "bob@example.com", 30},
|
|
{"Charlie", "charlie@example.com", 35},
|
|
{"David", "david@example.com", 40},
|
|
{"Eva", "eva@example.com", 28},
|
|
}
|
|
|
|
_, err := db.BatchInsertContext(context.Background(), "users", columns, values)
|
|
if err != nil {
|
|
t.Fatalf("BatchInsertContext failed: %v", err)
|
|
}
|
|
|
|
if len(metas) != 3 {
|
|
t.Fatalf("Expected 3 chunk metas, got %d", len(metas))
|
|
}
|
|
|
|
wantRows := []int{2, 2, 1}
|
|
for i, meta := range metas {
|
|
if meta.ChunkIndex != i+1 {
|
|
t.Fatalf("Chunk %d: expected index %d, got %d", i, i+1, meta.ChunkIndex)
|
|
}
|
|
if meta.ChunkCount != 3 {
|
|
t.Fatalf("Chunk %d: expected count 3, got %d", i, meta.ChunkCount)
|
|
}
|
|
if meta.ChunkRows != wantRows[i] {
|
|
t.Fatalf("Chunk %d: expected rows %d, got %d", i, wantRows[i], meta.ChunkRows)
|
|
}
|
|
if meta.TotalRows != len(values) {
|
|
t.Fatalf("Chunk %d: expected total rows %d, got %d", i, len(values), meta.TotalRows)
|
|
}
|
|
if meta.ColumnCount != len(columns) {
|
|
t.Fatalf("Chunk %d: expected column count %d, got %d", i, len(columns), meta.ColumnCount)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_HookMetaAbsentWithoutChunking(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
db.SetBatchInsertMaxRows(0)
|
|
db.SetBatchInsertMaxParams(0)
|
|
|
|
metaFound := false
|
|
db.SetSQLHooks(nil, func(ctx context.Context, query string, args []interface{}, d time.Duration, err error) {
|
|
if _, ok := stardb.BatchExecMetaFromContext(ctx); ok {
|
|
metaFound = true
|
|
}
|
|
})
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
{"Bob", "bob@example.com", 30},
|
|
}
|
|
|
|
_, err := db.BatchInsertContext(context.Background(), "users", columns, values)
|
|
if err != nil {
|
|
t.Fatalf("BatchInsertContext failed: %v", err)
|
|
}
|
|
if metaFound {
|
|
t.Fatal("Expected no batch meta for non-chunked execution")
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertStructs_Basic(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
users := []TestUser{
|
|
{Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: time.Now()},
|
|
{Name: "Bob", Email: "bob@example.com", Age: 30, CreatedAt: time.Now()},
|
|
{Name: "Charlie", Email: "charlie@example.com", Age: 35, CreatedAt: time.Now()},
|
|
}
|
|
|
|
result, err := db.BatchInsertStructs("users", users, "id")
|
|
if err != nil {
|
|
t.Fatalf("BatchInsertStructs failed: %v", err)
|
|
}
|
|
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
t.Fatalf("RowsAffected failed: %v", err)
|
|
}
|
|
|
|
if affected != 3 {
|
|
t.Errorf("Expected 3 rows affected, got %d", affected)
|
|
}
|
|
|
|
// Verify insertion
|
|
rows, err := db.Query("SELECT * FROM users ORDER BY name")
|
|
if err != nil {
|
|
t.Fatalf("Query failed: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
if rows.Length() != 3 {
|
|
t.Errorf("Expected 3 rows, got %d", rows.Length())
|
|
}
|
|
|
|
// Verify first user
|
|
name := rows.Row(0).MustString("name")
|
|
if name != "Alice" {
|
|
t.Errorf("Expected first user 'Alice', got '%s'", name)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertStructs_Chunked(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
db.SetBatchInsertMaxRows(2)
|
|
|
|
users := []TestUser{
|
|
{Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: time.Now()},
|
|
{Name: "Bob", Email: "bob@example.com", Age: 30, CreatedAt: time.Now()},
|
|
{Name: "Charlie", Email: "charlie@example.com", Age: 35, CreatedAt: time.Now()},
|
|
{Name: "David", Email: "david@example.com", Age: 40, CreatedAt: time.Now()},
|
|
{Name: "Eva", Email: "eva@example.com", Age: 28, CreatedAt: time.Now()},
|
|
}
|
|
|
|
result, err := db.BatchInsertStructs("users", users, "id")
|
|
if err != nil {
|
|
t.Fatalf("Chunked BatchInsertStructs failed: %v", err)
|
|
}
|
|
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
t.Fatalf("RowsAffected failed: %v", err)
|
|
}
|
|
if affected != int64(len(users)) {
|
|
t.Fatalf("Expected %d affected rows, got %d", len(users), affected)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertStructs_Single(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
users := []TestUser{
|
|
{Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: time.Now()},
|
|
}
|
|
|
|
result, err := db.BatchInsertStructs("users", users, "id")
|
|
if err != nil {
|
|
t.Fatalf("BatchInsertStructs 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_BatchInsertStructs_Empty(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
users := []TestUser{}
|
|
|
|
_, err := db.BatchInsertStructs("users", users, "id")
|
|
if !errors.Is(err, stardb.ErrNoStructsToInsert) {
|
|
t.Errorf("Expected ErrNoStructsToInsert, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertStructs_NotSlice(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
user := TestUser{Name: "Alice", Email: "alice@example.com", Age: 25}
|
|
|
|
_, err := db.BatchInsertStructs("users", user, "id")
|
|
if !errors.Is(err, stardb.ErrStructsNotSlice) {
|
|
t.Errorf("Expected ErrStructsNotSlice, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertStructs_Nil(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
_, err := db.BatchInsertStructs("users", nil, "id")
|
|
if !errors.Is(err, stardb.ErrStructsNil) {
|
|
t.Errorf("Expected ErrStructsNil, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertStructs_NilPointer(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
var users *[]TestUser
|
|
_, err := db.BatchInsertStructs("users", users, "id")
|
|
if !errors.Is(err, stardb.ErrStructsPointerNil) {
|
|
t.Errorf("Expected ErrStructsPointerNil, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertStructs_Pointer(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
users := []TestUser{
|
|
{Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: time.Now()},
|
|
{Name: "Bob", Email: "bob@example.com", Age: 30, CreatedAt: time.Now()},
|
|
}
|
|
|
|
result, err := db.BatchInsertStructs("users", &users, "id")
|
|
if err != nil {
|
|
t.Fatalf("BatchInsertStructs with pointer failed: %v", err)
|
|
}
|
|
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
t.Fatalf("RowsAffected failed: %v", err)
|
|
}
|
|
|
|
if affected != 2 {
|
|
t.Errorf("Expected 2 rows affected, got %d", affected)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertStructsContext(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
ctx := context.Background()
|
|
users := []TestUser{
|
|
{Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: time.Now()},
|
|
{Name: "Bob", Email: "bob@example.com", Age: 30, CreatedAt: time.Now()},
|
|
}
|
|
|
|
result, err := db.BatchInsertStructsContext(ctx, "users", users, "id")
|
|
if err != nil {
|
|
t.Fatalf("BatchInsertStructsContext failed: %v", err)
|
|
}
|
|
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
t.Fatalf("RowsAffected failed: %v", err)
|
|
}
|
|
|
|
if affected != 2 {
|
|
t.Errorf("Expected 2 rows affected, got %d", affected)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertStructs_Large(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
var users []TestUser
|
|
for i := 0; i < 50; i++ {
|
|
users = append(users, TestUser{
|
|
Name: "User" + string(rune(i)),
|
|
Email: "user" + string(rune(i)) + "@example.com",
|
|
Age: 20 + i%30,
|
|
CreatedAt: time.Now(),
|
|
})
|
|
}
|
|
|
|
result, err := db.BatchInsertStructs("users", users, "id")
|
|
if err != nil {
|
|
t.Fatalf("BatchInsertStructs failed: %v", err)
|
|
}
|
|
|
|
affected, err := result.RowsAffected()
|
|
if err != nil {
|
|
t.Fatalf("RowsAffected failed: %v", err)
|
|
}
|
|
|
|
if affected != 50 {
|
|
t.Errorf("Expected 50 rows affected, got %d", affected)
|
|
}
|
|
|
|
// Verify
|
|
rows, err := db.Query("SELECT COUNT(*) as count FROM users")
|
|
if err != nil {
|
|
t.Fatalf("Query failed: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
count := rows.Row(0).MustInt("count")
|
|
if count != 50 {
|
|
t.Errorf("Expected 50 rows in database, got %d", count)
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsert_VerifyData(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
values := [][]interface{}{
|
|
{"Alice", "alice@example.com", 25},
|
|
{"Bob", "bob@example.com", 30},
|
|
}
|
|
|
|
_, err := db.BatchInsert("users", columns, values)
|
|
if err != nil {
|
|
t.Fatalf("BatchInsert failed: %v", err)
|
|
}
|
|
|
|
// Verify data integrity
|
|
rows, err := db.Query("SELECT name, email, age FROM users ORDER BY name")
|
|
if err != nil {
|
|
t.Fatalf("Query failed: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
// Check Alice
|
|
row0 := rows.Row(0)
|
|
if row0.MustString("name") != "Alice" {
|
|
t.Errorf("Expected name 'Alice', got '%s'", row0.MustString("name"))
|
|
}
|
|
if row0.MustString("email") != "alice@example.com" {
|
|
t.Errorf("Expected email 'alice@example.com', got '%s'", row0.MustString("email"))
|
|
}
|
|
if row0.MustInt("age") != 25 {
|
|
t.Errorf("Expected age 25, got %d", row0.MustInt("age"))
|
|
}
|
|
|
|
// Check Bob
|
|
row1 := rows.Row(1)
|
|
if row1.MustString("name") != "Bob" {
|
|
t.Errorf("Expected name 'Bob', got '%s'", row1.MustString("name"))
|
|
}
|
|
if row1.MustString("email") != "bob@example.com" {
|
|
t.Errorf("Expected email 'bob@example.com', got '%s'", row1.MustString("email"))
|
|
}
|
|
if row1.MustInt("age") != 30 {
|
|
t.Errorf("Expected age 30, got %d", row1.MustInt("age"))
|
|
}
|
|
}
|
|
|
|
func TestStarDB_BatchInsertStructs_VerifyData(t *testing.T) {
|
|
db := setupBatchTestDB(t)
|
|
defer db.Close()
|
|
|
|
now := time.Now()
|
|
users := []TestUser{
|
|
{Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: now},
|
|
{Name: "Bob", Email: "bob@example.com", Age: 30, CreatedAt: now},
|
|
}
|
|
|
|
_, err := db.BatchInsertStructs("users", users, "id")
|
|
if err != nil {
|
|
t.Fatalf("BatchInsertStructs failed: %v", err)
|
|
}
|
|
|
|
// Query and verify with ORM
|
|
rows, err := db.Query("SELECT * FROM users ORDER BY name")
|
|
if err != nil {
|
|
t.Fatalf("Query failed: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var resultUsers []TestUser
|
|
err = rows.Orm(&resultUsers)
|
|
if err != nil {
|
|
t.Fatalf("Orm failed: %v", err)
|
|
}
|
|
|
|
if len(resultUsers) != 2 {
|
|
t.Fatalf("Expected 2 users, got %d", len(resultUsers))
|
|
}
|
|
|
|
// Verify Alice
|
|
if resultUsers[0].Name != "Alice" {
|
|
t.Errorf("Expected name 'Alice', got '%s'", resultUsers[0].Name)
|
|
}
|
|
if resultUsers[0].Email != "alice@example.com" {
|
|
t.Errorf("Expected email 'alice@example.com', got '%s'", resultUsers[0].Email)
|
|
}
|
|
if resultUsers[0].Age != 25 {
|
|
t.Errorf("Expected age 25, got %d", resultUsers[0].Age)
|
|
}
|
|
|
|
// Verify Bob
|
|
if resultUsers[1].Name != "Bob" {
|
|
t.Errorf("Expected name 'Bob', got '%s'", resultUsers[1].Name)
|
|
}
|
|
if resultUsers[1].Email != "bob@example.com" {
|
|
t.Errorf("Expected email 'bob@example.com', got '%s'", resultUsers[1].Email)
|
|
}
|
|
if resultUsers[1].Age != 30 {
|
|
t.Errorf("Expected age 30, got %d", resultUsers[1].Age)
|
|
}
|
|
}
|
|
|
|
// Benchmark tests
|
|
func BenchmarkBatchInsert_10(b *testing.B) {
|
|
db := setupBatchTestDB(&testing.T{})
|
|
defer db.Close()
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
var values [][]interface{}
|
|
for i := 0; i < 10; i++ {
|
|
values = append(values, []interface{}{"User", "user@example.com", 25})
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
db.BatchInsert("users", columns, values)
|
|
db.Exec("DELETE FROM users")
|
|
}
|
|
}
|
|
|
|
func BenchmarkBatchInsert_100(b *testing.B) {
|
|
db := setupBatchTestDB(&testing.T{})
|
|
defer db.Close()
|
|
|
|
columns := []string{"name", "email", "age"}
|
|
var values [][]interface{}
|
|
for i := 0; i < 100; i++ {
|
|
values = append(values, []interface{}{"User", "user@example.com", 25})
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
db.BatchInsert("users", columns, values)
|
|
db.Exec("DELETE FROM users")
|
|
}
|
|
}
|
|
|
|
func BenchmarkBatchInsertStructs_10(b *testing.B) {
|
|
db := setupBatchTestDB(&testing.T{})
|
|
defer db.Close()
|
|
|
|
var users []TestUser
|
|
for i := 0; i < 10; i++ {
|
|
users = append(users, TestUser{
|
|
Name: "User",
|
|
Email: "user@example.com",
|
|
Age: 25,
|
|
CreatedAt: time.Now(),
|
|
})
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
db.BatchInsertStructs("users", users, "id")
|
|
db.Exec("DELETE FROM users")
|
|
}
|
|
}
|
|
|
|
func BenchmarkBatchInsertStructs_100(b *testing.B) {
|
|
db := setupBatchTestDB(&testing.T{})
|
|
defer db.Close()
|
|
|
|
var users []TestUser
|
|
for i := 0; i < 100; i++ {
|
|
users = append(users, TestUser{
|
|
Name: "User",
|
|
Email: "user@example.com",
|
|
Age: 25,
|
|
CreatedAt: time.Now(),
|
|
})
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
db.BatchInsertStructs("users", users, "id")
|
|
db.Exec("DELETE FROM users")
|
|
}
|
|
}
|