package database import ( "testing" ) func TestQArgs_Postgres(t *testing.T) { // Force Postgres dialect for test CurrentDialect = DialectPostgres defer func() { CurrentDialect = DialectSQLite }() q, args := QArgs("SELECT * FROM t WHERE a = $1 AND b = $1", "val1") if q != "SELECT * FROM t WHERE a = $1 AND b = $1" { t.Errorf("Postgres: query should be unchanged, got %q", q) } if len(args) != 1 { t.Errorf("Postgres: args should be unchanged, got %d", len(args)) } } func TestQArgs_SQLite_ReusedPlaceholder(t *testing.T) { CurrentDialect = DialectSQLite defer func() { CurrentDialect = DialectPostgres }() // $1 appears twice — must be expanded to two ? with the same arg value q, args := QArgs( "SELECT COUNT(*) FROM channels c WHERE c.user_id = $1 OR c.id IN (SELECT channel_id FROM cp WHERE cp.user_id = $1) AND c.is_archived = $2", "user-123", false, ) // Should have 3 ? placeholders qCount := 0 for _, c := range q { if c == '?' { qCount++ } } if qCount != 3 { t.Errorf("expected 3 ? placeholders, got %d in %q", qCount, q) } // Should have 3 args: user-123, user-123, false if len(args) != 3 { t.Fatalf("expected 3 args, got %d: %v", len(args), args) } if args[0] != "user-123" { t.Errorf("args[0] = %v, want user-123", args[0]) } if args[1] != "user-123" { t.Errorf("args[1] = %v, want user-123 (expanded from reused $1)", args[1]) } if args[2] != false { t.Errorf("args[2] = %v, want false", args[2]) } // Should not contain $N if contains(q, "$") { t.Errorf("query still contains $: %q", q) } } func TestQArgs_SQLite_NoReuse(t *testing.T) { CurrentDialect = DialectSQLite defer func() { CurrentDialect = DialectPostgres }() q, args := QArgs("SELECT * FROM t WHERE a = $1 AND b = $2", "a", "b") qCount := 0 for _, c := range q { if c == '?' { qCount++ } } if qCount != 2 { t.Errorf("expected 2 ? placeholders, got %d", qCount) } if len(args) != 2 { t.Errorf("expected 2 args, got %d", len(args)) } } func TestQArgs_SQLite_ILIKE(t *testing.T) { CurrentDialect = DialectSQLite defer func() { CurrentDialect = DialectPostgres }() q, _ := QArgs("SELECT * FROM t WHERE name ILIKE $1", "%test%") if contains(q, "ILIKE") { t.Errorf("ILIKE should be rewritten to LIKE: %q", q) } if !contains(q, "LIKE") { t.Errorf("should contain LIKE: %q", q) } } func TestQArgs_SQLite_HighPlaceholders(t *testing.T) { CurrentDialect = DialectSQLite defer func() { CurrentDialect = DialectPostgres }() q, args := QArgs( "INSERT INTO t (a,b,c,d,e,f,g,h,i,j,k) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ) qCount := 0 for _, c := range q { if c == '?' { qCount++ } } if qCount != 11 { t.Errorf("expected 11 ?, got %d in %q", qCount, q) } if len(args) != 11 { t.Errorf("expected 11 args, got %d", len(args)) } // $10 and $11 should not be mangled if contains(q, "$") { t.Errorf("still contains $: %q", q) } } func contains(s, substr string) bool { for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return true } } return false }