463 lines
12 KiB
Go
463 lines
12 KiB
Go
|
|
package stardb
|
||
|
|
|
||
|
|
import (
|
||
|
|
"reflect"
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestNewQueryBuilder(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users")
|
||
|
|
|
||
|
|
if qb.table != "users" {
|
||
|
|
t.Errorf("Expected table 'users', got '%s'", qb.table)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(qb.columns) != 1 || qb.columns[0] != "*" {
|
||
|
|
t.Errorf("Expected default columns ['*'], got %v", qb.columns)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Select(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Select("id", "name", "email")
|
||
|
|
|
||
|
|
expected := []string{"id", "name", "email"}
|
||
|
|
if !reflect.DeepEqual(qb.columns, expected) {
|
||
|
|
t.Errorf("Expected columns %v, got %v", expected, qb.columns)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Where(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").
|
||
|
|
Where("age > ?", 18).
|
||
|
|
Where("active = ?", true)
|
||
|
|
|
||
|
|
if len(qb.where) != 2 {
|
||
|
|
t.Errorf("Expected 2 where conditions, got %d", len(qb.where))
|
||
|
|
}
|
||
|
|
|
||
|
|
if qb.where[0] != "age > ?" {
|
||
|
|
t.Errorf("Expected first where 'age > ?', got '%s'", qb.where[0])
|
||
|
|
}
|
||
|
|
|
||
|
|
if qb.where[1] != "active = ?" {
|
||
|
|
t.Errorf("Expected second where 'active = ?', got '%s'", qb.where[1])
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(qb.whereArgs) != 2 {
|
||
|
|
t.Errorf("Expected 2 where args, got %d", len(qb.whereArgs))
|
||
|
|
}
|
||
|
|
|
||
|
|
if qb.whereArgs[0] != 18 {
|
||
|
|
t.Errorf("Expected first arg 18, got %v", qb.whereArgs[0])
|
||
|
|
}
|
||
|
|
|
||
|
|
if qb.whereArgs[1] != true {
|
||
|
|
t.Errorf("Expected second arg true, got %v", qb.whereArgs[1])
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_OrderBy(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").OrderBy("name ASC")
|
||
|
|
|
||
|
|
if qb.orderBy != "name ASC" {
|
||
|
|
t.Errorf("Expected orderBy 'name ASC', got '%s'", qb.orderBy)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Limit(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Limit(10)
|
||
|
|
|
||
|
|
if qb.limit != 10 {
|
||
|
|
t.Errorf("Expected limit 10, got %d", qb.limit)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Offset(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Offset(20)
|
||
|
|
|
||
|
|
if qb.offset != 20 {
|
||
|
|
t.Errorf("Expected offset 20, got %d", qb.offset)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Build_Simple(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users")
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT * FROM users"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Build_WithSelect(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Select("id", "name", "email")
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT id, name, email FROM users"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Build_WithWhere(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").
|
||
|
|
Where("age > ?", 18).
|
||
|
|
Where("active = ?", true)
|
||
|
|
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT * FROM users WHERE age > ? AND active = ?"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 2 {
|
||
|
|
t.Errorf("Expected 2 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
|
||
|
|
if args[0] != 18 {
|
||
|
|
t.Errorf("Expected first arg 18, got %v", args[0])
|
||
|
|
}
|
||
|
|
|
||
|
|
if args[1] != true {
|
||
|
|
t.Errorf("Expected second arg true, got %v", args[1])
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Build_WithOrderBy(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").OrderBy("created_at DESC")
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT * FROM users ORDER BY created_at DESC"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Build_WithLimit(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Limit(10)
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT * FROM users LIMIT 10"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Build_WithOffset(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Offset(20)
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT * FROM users OFFSET 20"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Build_WithLimitAndOffset(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Limit(10).Offset(20)
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT * FROM users LIMIT 10 OFFSET 20"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Build_Complex(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").
|
||
|
|
Select("id", "name", "email", "age").
|
||
|
|
Where("age > ?", 18).
|
||
|
|
Where("active = ?", true).
|
||
|
|
Where("country = ?", "US").
|
||
|
|
OrderBy("name ASC").
|
||
|
|
Limit(10).
|
||
|
|
Offset(20)
|
||
|
|
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT id, name, email, age FROM users WHERE age > ? AND active = ? AND country = ? ORDER BY name ASC LIMIT 10 OFFSET 20"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query:\n%s\nGot:\n%s", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
expectedArgs := []interface{}{18, true, "US"}
|
||
|
|
if len(args) != len(expectedArgs) {
|
||
|
|
t.Errorf("Expected %d args, got %d", len(expectedArgs), len(args))
|
||
|
|
}
|
||
|
|
|
||
|
|
for i, expected := range expectedArgs {
|
||
|
|
if args[i] != expected {
|
||
|
|
t.Errorf("Expected arg[%d] = %v, got %v", i, expected, args[i])
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Build_MultipleWhere(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("orders").
|
||
|
|
Where("user_id = ?", 123).
|
||
|
|
Where("status IN (?, ?, ?)", "pending", "processing", "shipped").
|
||
|
|
Where("created_at > ?", "2024-01-01")
|
||
|
|
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT * FROM orders WHERE user_id = ? AND status IN (?, ?, ?) AND created_at > ?"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query:\n%s\nGot:\n%s", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 5 {
|
||
|
|
t.Errorf("Expected 5 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
|
||
|
|
expectedArgs := []interface{}{123, "pending", "processing", "shipped", "2024-01-01"}
|
||
|
|
for i, expected := range expectedArgs {
|
||
|
|
if args[i] != expected {
|
||
|
|
t.Errorf("Expected arg[%d] = %v, got %v", i, expected, args[i])
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_Chaining(t *testing.T) {
|
||
|
|
// Test method chaining returns the same builder
|
||
|
|
qb := NewQueryBuilder("users")
|
||
|
|
|
||
|
|
qb2 := qb.Select("id", "name")
|
||
|
|
if qb != qb2 {
|
||
|
|
t.Error("Select should return the same builder instance")
|
||
|
|
}
|
||
|
|
|
||
|
|
qb3 := qb.Where("age > ?", 18)
|
||
|
|
if qb != qb3 {
|
||
|
|
t.Error("Where should return the same builder instance")
|
||
|
|
}
|
||
|
|
|
||
|
|
qb4 := qb.OrderBy("name ASC")
|
||
|
|
if qb != qb4 {
|
||
|
|
t.Error("OrderBy should return the same builder instance")
|
||
|
|
}
|
||
|
|
|
||
|
|
qb5 := qb.Limit(10)
|
||
|
|
if qb != qb5 {
|
||
|
|
t.Error("Limit should return the same builder instance")
|
||
|
|
}
|
||
|
|
|
||
|
|
qb6 := qb.Offset(20)
|
||
|
|
if qb != qb6 {
|
||
|
|
t.Error("Offset should return the same builder instance")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_EmptyWhere(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Select("id", "name")
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT id, name FROM users"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_OnlyLimit(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Limit(5)
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT * FROM users LIMIT 5"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_OnlyOffset(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Offset(10)
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT * FROM users OFFSET 10"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_ZeroLimit(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Limit(0)
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
// Limit 0 should not be included
|
||
|
|
expectedQuery := "SELECT * FROM users"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_ZeroOffset(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Offset(0)
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
// Offset 0 should not be included
|
||
|
|
expectedQuery := "SELECT * FROM users"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_MultipleSelect(t *testing.T) {
|
||
|
|
// Last Select should override previous ones
|
||
|
|
qb := NewQueryBuilder("users").
|
||
|
|
Select("id", "name").
|
||
|
|
Select("email", "age")
|
||
|
|
|
||
|
|
query, _ := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT email, age FROM users"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_MultipleOrderBy(t *testing.T) {
|
||
|
|
// Last OrderBy should override previous ones
|
||
|
|
qb := NewQueryBuilder("users").
|
||
|
|
OrderBy("name ASC").
|
||
|
|
OrderBy("created_at DESC")
|
||
|
|
|
||
|
|
query, _ := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT * FROM users ORDER BY created_at DESC"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_ComplexWhereConditions(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("products").
|
||
|
|
Select("id", "name", "price").
|
||
|
|
Where("category_id = ?", 5).
|
||
|
|
Where("price BETWEEN ? AND ?", 10.0, 100.0).
|
||
|
|
Where("stock > ?", 0).
|
||
|
|
Where("name LIKE ?", "%phone%").
|
||
|
|
OrderBy("price DESC").
|
||
|
|
Limit(20)
|
||
|
|
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT id, name, price FROM products WHERE category_id = ? AND price BETWEEN ? AND ? AND stock > ? AND name LIKE ? ORDER BY price DESC LIMIT 20"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query:\n%s\nGot:\n%s", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
expectedArgs := []interface{}{5, 10.0, 100.0, 0, "%phone%"}
|
||
|
|
if len(args) != len(expectedArgs) {
|
||
|
|
t.Errorf("Expected %d args, got %d", len(expectedArgs), len(args))
|
||
|
|
}
|
||
|
|
|
||
|
|
for i, expected := range expectedArgs {
|
||
|
|
if args[i] != expected {
|
||
|
|
t.Errorf("Expected arg[%d] = %v, got %v", i, expected, args[i])
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_SingleColumn(t *testing.T) {
|
||
|
|
qb := NewQueryBuilder("users").Select("COUNT(*)")
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT COUNT(*) FROM users"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query '%s', got '%s'", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 0 {
|
||
|
|
t.Errorf("Expected 0 args, got %d", len(args))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestQueryBuilder_JoinLikeWhere(t *testing.T) {
|
||
|
|
// Test that WHERE can handle JOIN-like conditions
|
||
|
|
qb := NewQueryBuilder("users").
|
||
|
|
Select("users.id", "users.name", "orders.total").
|
||
|
|
Where("users.id = orders.user_id").
|
||
|
|
Where("orders.status = ?", "completed")
|
||
|
|
|
||
|
|
query, args := qb.Build()
|
||
|
|
|
||
|
|
expectedQuery := "SELECT users.id, users.name, orders.total FROM users WHERE users.id = orders.user_id AND orders.status = ?"
|
||
|
|
if query != expectedQuery {
|
||
|
|
t.Errorf("Expected query:\n%s\nGot:\n%s", expectedQuery, query)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(args) != 1 {
|
||
|
|
t.Errorf("Expected 1 arg, got %d", len(args))
|
||
|
|
}
|
||
|
|
|
||
|
|
if args[0] != "completed" {
|
||
|
|
t.Errorf("Expected arg 'completed', got %v", args[0])
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Benchmark tests
|
||
|
|
func BenchmarkQueryBuilder_Simple(b *testing.B) {
|
||
|
|
for i := 0; i < b.N; i++ {
|
||
|
|
qb := NewQueryBuilder("users")
|
||
|
|
qb.Build()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func BenchmarkQueryBuilder_Complex(b *testing.B) {
|
||
|
|
for i := 0; i < b.N; i++ {
|
||
|
|
qb := NewQueryBuilder("users").
|
||
|
|
Select("id", "name", "email", "age").
|
||
|
|
Where("age > ?", 18).
|
||
|
|
Where("active = ?", true).
|
||
|
|
Where("country = ?", "US").
|
||
|
|
OrderBy("name ASC").
|
||
|
|
Limit(10).
|
||
|
|
Offset(20)
|
||
|
|
qb.Build()
|
||
|
|
}
|
||
|
|
}
|