2026-03-07 19:27:44 +08:00
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" )
}
2026-03-20 13:36:59 +08:00
qb7 := qb . Join ( "LEFT JOIN orders o ON o.user_id = users.id" )
if qb != qb7 {
t . Error ( "Join should return the same builder instance" )
}
qb8 := qb . GroupBy ( "users.id" )
if qb != qb8 {
t . Error ( "GroupBy should return the same builder instance" )
}
qb9 := qb . Having ( "COUNT(o.id) > ?" , 1 )
if qb != qb9 {
t . Error ( "Having should return the same builder instance" )
}
2026-03-07 19:27:44 +08:00
}
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 ] )
}
}
2026-03-20 13:36:59 +08:00
func TestQueryBuilder_Build_WithJoinGroupByHaving ( t * testing . T ) {
qb := NewQueryBuilder ( "users u" ) .
Select ( "u.id" , "u.name" , "COUNT(o.id) AS order_count" ) .
Join ( "LEFT JOIN orders o ON o.user_id = u.id" ) .
Where ( "u.active = ?" , true ) .
GroupBy ( "u.id" , "u.name" ) .
Having ( "COUNT(o.id) > ?" , 2 ) .
OrderBy ( "order_count DESC" )
query , args := qb . Build ( )
expectedQuery := "SELECT u.id, u.name, COUNT(o.id) AS order_count FROM users u LEFT JOIN orders o ON o.user_id = u.id WHERE u.active = ? GROUP BY u.id, u.name HAVING COUNT(o.id) > ? ORDER BY order_count DESC"
if query != expectedQuery {
t . Errorf ( "Expected query:\n%s\nGot:\n%s" , expectedQuery , query )
}
expectedArgs := [ ] interface { } { true , 2 }
if len ( args ) != len ( expectedArgs ) {
t . Fatalf ( "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_HavingWithoutWhere ( t * testing . T ) {
qb := NewQueryBuilder ( "orders" ) .
Select ( "user_id" , "COUNT(*) AS cnt" ) .
GroupBy ( "user_id" ) .
Having ( "COUNT(*) >= ?" , 3 )
query , args := qb . Build ( )
expectedQuery := "SELECT user_id, COUNT(*) AS cnt FROM orders GROUP BY user_id HAVING COUNT(*) >= ?"
if query != expectedQuery {
t . Errorf ( "Expected query '%s', got '%s'" , expectedQuery , query )
}
if len ( args ) != 1 || args [ 0 ] != 3 {
t . Errorf ( "Expected args [3], got %v" , args )
}
}
2026-03-07 19:27:44 +08:00
// 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 ( )
}
}