Toki is a fast and efficient SQL query builder for Go that helps you build SQL statements dynamically at runtime. It focuses on performance, safety, and ease of use.
- π High-performance query building
- π Automatic placeholder conversion (? to $1, $2, ...)
- πΎ Memory pooling for better performance
- π¦ Transaction support with automatic rollback
- π― Fluent interface for query construction
- π‘οΈ Secure parameter binding and SQL injection prevention
- π Structure binding support
- β‘ Memory efficient operations
- π Expression and Raw query support
go get github.com/zakirkun/toki
package main
import (
"database/sql"
"log"
"github.com/zakirkun/toki"
_ "github.com/lib/pq"
)
func main() {
db, err := sql.Open("postgres", "postgres://user:password@localhost/dbname?sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Create a new builder
builder := toki.New()
// Build a SELECT query
query := builder.
Select("id", "name", "email").
From("users").
Where("age > ?", 18).
OrderBy("created_at DESC")
// Prepare and execute
stmt, err := query.Prepare(db)
if err != nil {
log.Fatal(err)
}
rows, err := stmt.Query()
if err != nil {
log.Fatal(err)
}
defer rows.Close()
}
// SELECT query
builder.
Select("id", "name").
From("users").
Where("age > ?", 18).
AndWhere("status = ?", "active").
OrderBy("created_at DESC")
// INSERT query
builder.
Insert("users", "name", "email").
Values("John Doe", "[email protected]")
// UPDATE query
builder.
Update("users").
Set(map[string]interface{}{
"name": "Jane Doe",
"updated_at": "NOW()",
}).
Where("id = ?", 1)
// DELETE query
builder.
Delete("users").
Where("status = ?", "inactive")
builder.Raw(`
SELECT u.*, p.name as profile_name
FROM users u
LEFT JOIN profiles p ON p.user_id = u.id
WHERE u.created_at > $1
`, time.Now().AddDate(0, -1, 0))
// Start a transaction
tx, err := toki.Begin(db)
if err != nil {
log.Fatal(err)
}
defer tx.Rollback() // Rollback if not committed
// Use transaction in builder
builder := toki.New().WithTransaction(tx)
// Execute queries
stmt, err := builder.
Insert("users").
Values("John", "[email protected]").
Prepare(db)
if err != nil {
log.Fatal(err)
}
// Commit transaction
if err := tx.Commit(); err != nil {
log.Fatal(err)
}
type User struct {
ID int `db:"id"`
Name string `db:"name"`
Email string `db:"email"`
CreatedAt time.Time `db:"created_at"`
}
// Bind structure to query
user := User{
Name: "John Doe",
Email: "[email protected]",
}
bindings := builder.Bind(&user)
// Using raw SQL expressions
builder.
Update("counters").
Set(map[string]interface{}{
"counter": toki.Raw("counter + 1"),
"updated_at": toki.Raw("NOW()"),
}).
Where("id = ?", 1)
Toki uses sync.Pool to reuse allocated memory for string building, which significantly reduces garbage collection pressure under high load.
// Memory pooling is automatically handled
builder := toki.New() // Creates a builder with memory pool
Automatic and efficient conversion of SQL placeholders:
// Write queries with ? placeholders
query := builder.
Select("*").
From("users").
Where("age > ?", 18).
AndWhere("status = ?", "active")
// Automatically converts to $1, $2, etc. for PostgreSQL
// SELECT * FROM users WHERE age > $1 AND status = $2
-
Use Transactions for Multiple Operations
tx, _ := toki.Begin(db) defer tx.Rollback() // ... perform operations tx.Commit()
-
Always Close Rows
rows, err := stmt.Query() if err != nil { return err } defer rows.Close()
-
Use Parameter Binding
// Good Where("id = ?", id) // Bad Where(fmt.Sprintf("id = %d", id))
-
Utilize Structure Binding
type User struct { ID int `db:"id"` Name string `db:"name"` }
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
If you have any questions or need help, please open an issue in the GitHub repository.