Back to Documentation

Go SDK

High-performance Go client for entropyDB with goroutine support

Overview

The Go SDK provides:

  • High Performance: Optimized for concurrency
  • Context Support: Cancellation and timeouts
  • Connection Pooling: Efficient resource management
  • Query Builder: Type-safe query construction
  • Zero-Copy: Memory-efficient operations

Installation

# Install the SDK
go get github.com/entropydb/entropydb-go

# Import in your code
import (
    "github.com/entropydb/entropydb-go"
    "github.com/entropydb/entropydb-go/query"
)

Basic Usage

package main

import (
    "context"
    "fmt"
    "log"
    "time"
    
    "github.com/entropydb/entropydb-go"
)

type User struct {
    ID        int64     `db:"id"`
    Username  string    `db:"username"`
    Email     string    `db:"email"`
    CreatedAt time.Time `db:"created_at"`
}

func main() {
    // Connect to entropyDB
    config := entropydb.Config{
        Host:     "localhost",
        Port:     5432,
        Database: "mydb",
        User:     "admin",
        Password: "password",
        PoolSize: 20,
    }
    
    client, err := entropydb.NewClient(config)
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
    
    ctx := context.Background()
    
    // Create table
    _, err = client.Exec(ctx, `
        CREATE TABLE IF NOT EXISTS users (
            id SERIAL PRIMARY KEY,
            username TEXT NOT NULL,
            email TEXT UNIQUE,
            created_at TIMESTAMP DEFAULT NOW()
        )
    `)
    if err != nil {
        log.Fatal(err)
    }
    
    // Insert data
    result, err := client.Exec(ctx,
        "INSERT INTO users (username, email) VALUES ($1, $2)",
        "alice", "alice@example.com")
    if err != nil {
        log.Fatal(err)
    }
    
    rowsAffected := result.RowsAffected()
    fmt.Printf("Inserted %d row(s)\n", rowsAffected)
    
    // Query single row
    var user User
    err = client.QueryRow(ctx,
        "SELECT id, username, email, created_at FROM users WHERE username = $1",
        "alice").Scan(&user.ID, &user.Username, &user.Email, &user.CreatedAt)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("User: %+v\n", user)
    
    // Query multiple rows
    rows, err := client.Query(ctx,
        "SELECT id, username, email FROM users WHERE email LIKE $1",
        "%@example.com")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()
    
    var users []User
    for rows.Next() {
        var u User
        if err := rows.Scan(&u.ID, &u.Username, &u.Email); err != nil {
            log.Fatal(err)
        }
        users = append(users, u)
    }
    
    fmt.Printf("Found %d users\n", len(users))
}

Connection Pooling

package main

import (
    "context"
    "time"
    "github.com/entropydb/entropydb-go"
)

func main() {
    config := entropydb.Config{
        Host:     "localhost",
        Port:     5432,
        Database: "mydb",
        User:     "admin",
        Password: "password",
        
        // Pool configuration
        PoolSize:        20,              // Maximum connections
        MinConns:        5,               // Minimum idle connections
        MaxConnLifetime: 30 * time.Minute,
        MaxConnIdleTime: 5 * time.Minute,
        ConnectTimeout:  10 * time.Second,
        
        // Performance tuning
        PreferSimpleProtocol: false,
        StatementCacheSize:   100,
    }
    
    client, err := entropydb.NewClient(config)
    if err != nil {
        panic(err)
    }
    defer client.Close()
    
    // Get pool stats
    stats := client.Stats()
    fmt.Printf("Acquired connections: %d\n", stats.AcquiredConns)
    fmt.Printf("Idle connections: %d\n", stats.IdleConns)
    fmt.Printf("Total connections: %d\n", stats.TotalConns)
}

Query Builder

package main

import (
    "github.com/entropydb/entropydb-go/query"
)

func main() {
    // Build SELECT query
    q := query.Select("id", "username", "email").
        From("users").
        Where("email LIKE ?", "%@example.com").
        And("created_at > ?", time.Now().AddDate(0, 0, -7)).
        OrderBy("created_at DESC").
        Limit(10)
    
    sql, args := q.Build()
    // sql: SELECT id, username, email FROM users WHERE email LIKE $1 AND created_at > $2 ORDER BY created_at DESC LIMIT 10
    
    rows, err := client.Query(ctx, sql, args...)
    
    // Build INSERT query
    q = query.Insert("users").
        Columns("username", "email").
        Values("bob", "bob@example.com").
        Returning("id")
    
    var id int64
    err = client.QueryRow(ctx, q.Build()).Scan(&id)
    
    // Build UPDATE query
    q = query.Update("users").
        Set("email", "newemail@example.com").
        Where("username = ?", "bob").
        Returning("*")
    
    // Build DELETE query
    q = query.Delete("users").
        Where("created_at < ?", time.Now().AddDate(0, 0, -365))
    
    result, err := client.Exec(ctx, q.Build())
    
    // Complex queries with joins
    q = query.Select("u.username", "o.total").
        From("users u").
        Join("orders o", "u.id = o.user_id").
        Where("o.status = ?", "completed").
        GroupBy("u.username", "o.total").
        Having("o.total > ?", 100)
}

Transactions

package main

import (
    "context"
    "github.com/entropydb/entropydb-go"
)

func transferFunds(ctx context.Context, client *entropydb.Client, fromID, toID int64, amount float64) error {
    // Begin transaction
    tx, err := client.BeginTx(ctx, &entropydb.TxOptions{
        IsolationLevel: entropydb.Serializable,
    })
    if err != nil {
        return err
    }
    defer tx.Rollback(ctx)
    
    // Debit from source account
    _, err = tx.Exec(ctx,
        "UPDATE accounts SET balance = balance - $1 WHERE id = $2",
        amount, fromID)
    if err != nil {
        return err
    }
    
    // Credit to destination account
    _, err = tx.Exec(ctx,
        "UPDATE accounts SET balance = balance + $1 WHERE id = $2",
        amount, toID)
    if err != nil {
        return err
    }
    
    // Record transaction
    _, err = tx.Exec(ctx,
        "INSERT INTO transfers (from_account, to_account, amount) VALUES ($1, $2, $3)",
        fromID, toID, amount)
    if err != nil {
        return err
    }
    
    // Commit transaction
    return tx.Commit(ctx)
}

// Using context timeout
func queryWithTimeout() {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    rows, err := client.Query(ctx, "SELECT * FROM large_table")
    if err != nil {
        if ctx.Err() == context.DeadlineExceeded {
            log.Println("Query timed out")
        }
    }
}

Concurrency with Goroutines

package main

import (
    "context"
    "sync"
)

func concurrentInserts(client *entropydb.Client, records []User) error {
    ctx := context.Background()
    var wg sync.WaitGroup
    errChan := make(chan error, len(records))
    
    // Process records concurrently
    for _, user := range records {
        wg.Add(1)
        go func(u User) {
            defer wg.Done()
            
            _, err := client.Exec(ctx,
                "INSERT INTO users (username, email) VALUES ($1, $2)",
                u.Username, u.Email)
            if err != nil {
                errChan <- err
            }
        }(user)
    }
    
    // Wait for all goroutines
    wg.Wait()
    close(errChan)
    
    // Check for errors
    for err := range errChan {
        if err != nil {
            return err
        }
    }
    
    return nil
}

// Worker pool pattern
func workerPool(client *entropydb.Client) {
    ctx := context.Background()
    jobs := make(chan int, 100)
    results := make(chan string, 100)
    
    // Start workers
    var wg sync.WaitGroup
    for w := 0; w < 10; w++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for id := range jobs {
                var username string
                err := client.QueryRow(ctx,
                    "SELECT username FROM users WHERE id = $1",
                    id).Scan(&username)
                if err == nil {
                    results <- username
                }
            }
        }()
    }
    
    // Send jobs
    for i := 1; i <= 100; i++ {
        jobs <- i
    }
    close(jobs)
    
    // Wait for completion
    go func() {
        wg.Wait()
        close(results)
    }()
    
    // Collect results
    for username := range results {
        fmt.Println(username)
    }
}

Best Practices

Performance

  • • Use connection pooling
  • • Enable statement caching
  • • Use context for cancellation
  • • Batch operations when possible

Concurrency

  • • Share client, not connections
  • • Use worker pools for bulk operations
  • • Handle errors from goroutines
  • • Set appropriate timeouts

Next Steps