sql

package
v0.0.0-...-7e3c669 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 7, 2026 License: MIT Imports: 10 Imported by: 0

README

SQL Package

The sql package provides utilities for working with SQL databases.

Modules

BatchInserter - Batch SQL Inserts

Efficiently insert large batches of data into SQL databases with automatic escaping support.

Pass values as a slice/array and they will be automatically escaped:

import hbsql "github.com/parf/homebase-go-lib/sql"

db, _ := sql.Open("mysql", "user:pass@tcp(host:3306)/dbname")
defer db.Close()

insert, flush := hbsql.BatchInserter(db, "users", "id, name, email", 1000)
defer flush()

for i := 0; i < 10000; i++ {
    // SAFE: Values are automatically escaped
    insert([]any{i, "John's Pizza", "[email protected]"})

    // Also works with typed slices:
    // insert([]string{"value1", "value2", "value3"})
    // insert([]int{1, 2, 3})
}
Manual Mode (Legacy - UNSAFE)

Pass values as a pre-formatted string (you must escape values yourself):

insert, flush := hbsql.BatchInserter(db, "users", "id, name, email", 1000)
defer flush()

for i := 0; i < 10000; i++ {
    // UNSAFE: You must escape values yourself!
    values := fmt.Sprintf("%d, '%s', '%s'", i, escapedName, escapedEmail)
    insert(values)
}
EscapeValue Function

For manual escaping of individual values:

import hbsql "github.com/parf/homebase-go-lib/sql"

// Escape a single value for SQL
escaped := hbsql.EscapeValue("John's Pizza")  // Returns: 'John''s Pizza'
escaped := hbsql.EscapeValue(42)              // Returns: 42
escaped := hbsql.EscapeValue(nil)             // Returns: NULL

Also available: BatchDBInserter - Opens database connection for you.

SqlIterator - Query Iteration with Statistics

Iterate over SQL query results with automatic progress tracking.

import hbsql "github.com/parf/homebase-go-lib/sql"

hbsql.SqlIterator("user:pass@tcp(host:3306)/db", "SELECT id, name FROM users", func(row *sql.Rows) {
    var id int
    var name string
    row.Scan(&id, &name)
    fmt.Printf("User: %d - %s\n", id, name)
})
SqlExtra - Dynamic Query Results

Execute SQL SELECT statements and get results as maps.

Types
type SqlRow  map[string]any        // Single row as map[column]value
type SqlRows []SqlRow               // Multiple rows
Functions
WildSqlQuery
func WildSqlQuery(db *sql.DB, query string) (SqlRows, error)

Executes a SQL query and returns results as a slice of maps. Each row is represented as a map with column names as keys and string values.

Note: All values are returned as strings. NULL values are returned as nil.

Usage Example

package main

import (
    "database/sql"
    "fmt"
    "log"

    hbsql "github.com/parf/homebase-go-lib/sql"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    db, err := sql.Open("mysql", "user:pass@tcp(localhost:3306)/mydb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    // Execute query and get results as maps
    rows, err := hbsql.WildSqlQuery(db, "SELECT id, name, email FROM users LIMIT 10")
    if err != nil {
        log.Fatal(err)
    }

    // Process results
    for _, row := range rows {
        fmt.Printf("ID: %s, Name: %s, Email: %s\n",
            row["id"], row["name"], row["email"])
    }

    // Access specific row
    if len(rows) > 0 {
        firstRow := rows[0]
        fmt.Printf("First user ID: %s\n", firstRow["id"])
    }
}

Benefits

  • Dynamic queries: Works with any SELECT query without knowing the schema in advance
  • Simple interface: Results as maps are easy to work with
  • Type flexibility: All values returned as strings, easily convertible
  • NULL handling: NULL values are properly handled

Limitations

  • All non-NULL values are converted to strings
  • For type-specific handling, use standard database/sql with explicit type scanning
  • Not optimized for very large result sets (loads all rows into memory)

Use Cases

  • Dynamic query results where schema is not known at compile time
  • Quick prototyping and debugging
  • Administration tools
  • Configuration queries
  • Metadata queries

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func BatchDBInserter

func BatchDBInserter(db, table, fields string, bufferSize int) (insert func(any), flushClose func())

BatchDBInserter creates a batch inserter with a new database connection.

Usage with auto-escaping (recommended):

connect_string := "parf:passwd(rxdb:3306)/visits_log"
insert, flush := sql.BatchDBInserter(connect_string, "tableName", "field1, field2, ...", 10000)
defer flush()

for .... {
	insert([]any{val1, val2, val3, val4, val5})  // Auto-escaped
}

Usage with manual string (legacy):

for .... {
	values := fmt.Sprintf("%d, %d, %d, %d, %d", ...)  // You must escape
	insert(values)
}

func BatchInserter

func BatchInserter(db *sql.DB, table string, fields string, bufferSize int) (insert func(any), flush func())

BatchInserter creates a batch inserter for an existing database connection. It accumulates insert values and flushes them in batches when bufferSize is reached.

The insert function accepts either:

  • string: values as SQL string (UNSAFE - you must escape yourself)
  • slice/array: values as slice (SAFE - automatically escaped)

Example with auto-escaping:

insert([]any{1, "John's Pizza", 99.95})
insert([]string{"value1", "value2", "value3"})
insert([]int{1, 2, 3})

Example with manual escaping (backward compatible):

insert("1, 'John''s Pizza', 99.95")
Example (AutoEscape)

Example showing expected usage with auto-escaping (new style - recommended)

package main

import ()

func main() {
	// This would require a real database connection
	// db, _ := sql.Open("mysql", "user:pass@tcp(host:3306)/dbname")
	// defer db.Close()
	//
	// insert, flush := hbsql.BatchInserter(db, "users", "id, name, email", 1000)
	// defer flush()
	//
	// for i := 0; i < 10000; i++ {
	//     // Auto-escaping - SAFE, handles quotes and special characters
	//     insert([]any{i, fmt.Sprintf("user%d", i), fmt.Sprintf("user%[email protected]", i)})
	// }
	//
	// // Also works with typed slices:
	// insert([]string{"value1", "value2", "value3"})
	// insert([]int{1, 2, 3})
	// insert([]any{1, "John's Pizza", 99.95, true, nil})
}
Example (Manual)

Example showing expected usage with manual escaping (old style)

package main

import ()

func main() {
	// This would require a real database connection
	// db, _ := sql.Open("mysql", "user:pass@tcp(host:3306)/dbname")
	// defer db.Close()
	//
	// insert, flush := hbsql.BatchInserter(db, "users", "id, name, email", 1000)
	// defer flush()
	//
	// for i := 0; i < 10000; i++ {
	//     // Manual escaping - UNSAFE if data comes from user input
	//     values := fmt.Sprintf("%d, \"user%d\", \"user%[email protected]\"", i, i, i)
	//     insert(values)
	// }
}

func EscapeValue

func EscapeValue(val any) string

EscapeValue converts a value to a SQL-safe string representation. Handles NULL, strings (with escaping), numbers, booleans, and other types. This function is exported so users can use it for manual escaping if needed.

func PostgreBatchDBInserter

func PostgreBatchDBInserter(dsn, table, fields string, bufferSize int) (insert func(any), flushClose func())

PostgreBatchDBInserter creates a batch inserter with a new PostgreSQL connection.

Usage:

connect_string := "host=localhost port=5432 user=myuser password=mypass dbname=mydb sslmode=disable"
insert, flush := sql.PostgreBatchDBInserter(connect_string, "schema.table", "col1, col2, col3", 1000)
defer flush()

for ... {
	insert([]any{val1, val2, val3})
}

func PostgreBatchInserter

func PostgreBatchInserter(db *sql.DB, table string, fields string, bufferSize int) (insert func(any), flush func())

PostgreBatchInserter creates a batch inserter optimized for PostgreSQL. It's functionally identical to BatchInserter but makes the intent clear and can be extended with PostgreSQL-specific optimizations in the future.

Usage:

insert, flush := sql.PostgreBatchInserter(db, "schema.table", "col1, col2, col3", 1000)
defer flush()

for ... {
	insert([]any{val1, val2, val3})  // Auto-escaped
}

func SqlIterator

func SqlIterator(connection string, sql_ string, processor SqlRowProcessor)

SqlIterator iterates over SQL query and shows statistics

sample connection: "parf:mv700@tcp(hdb2:3306)/visits_log" sample sql: "SELECT FL, T, C, B, G, V, Blocked, L FROM flTCBGVL limit 10"

Example

Example showing expected usage

package main

import ()

func main() {
	// This would require a real database connection
	// hbsql.SqlIterator("user:pass@tcp(host:3306)/db", "SELECT * FROM users LIMIT 10", func(row *sql.Rows) {
	//     var id int
	//     var name string
	//     row.Scan(&id, &name)
	//     fmt.Printf("User: %d - %s\n", id, name)
	// })
}

Types

type SqlRow

type SqlRow map[string]any

type SqlRowProcessor

type SqlRowProcessor func(row *sql.Rows)

SqlRowProcessor is a function type for processing SQL rows

type SqlRows

type SqlRows []SqlRow

func WildSqlQuery

func WildSqlQuery(db *sql.DB, query string) (rz SqlRows, err error)

WildSqlQuery executes a SQL query and returns results as a slice of maps. Each row is represented as a map with column names as keys and string values.

Example

Example test showing the expected structure

package main

import (
	_ "github.com/go-sql-driver/mysql"
)

func main() {
	// This would require a real database connection
	// db, _ := sql.Open("mysql", "user:pass@tcp(host:3306)/dbname")
	// defer db.Close()
	//
	// rows, err := hbsql.WildSqlQuery(db, "SELECT id, name FROM users LIMIT 10")
	// if err != nil {
	//     log.Fatal(err)
	// }
	//
	// for _, row := range rows {
	//     fmt.Printf("ID: %s, Name: %s\n", row["id"], row["name"])
	// }
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL