postgres

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2025 License: MIT Imports: 16 Imported by: 0

README

Go PostgreSQL Library

A PostgreSQL library built on top of sqlx with focus on performance, security, and ease of use.

✨ Features

  • Connection Pooling: Optimal connection pool configuration
  • Transaction Support: Pipeline transactions with automatic rollback
  • Memory Safe: Prepared statements automatically closed to prevent memory leaks
  • Type Safety: Custom types for PostgreSQL arrays
  • Parameter Binding: Named parameters to prevent SQL injection

🚀 Quick Start

package main

import (
    "context"
    "log"
    "time"
    
    "github.com/andryhardiyanto/go-postgres"
)

func main() {
    // Initialize database
    db, err := postgres.New(
        postgres.WithHost("localhost"),
        postgres.WithPort(5432),
        postgres.WithUser("username"),
        postgres.WithPassword("password"),
        postgres.WithDBName("mydb"),
        postgres.WithSSLMode("disable"),
        postgres.WithDriverName("postgres"),
        postgres.WithMaxOpenConns(25),
        postgres.WithMaxIdleConns(5),
        postgres.WithConnMaxLifetime(5*time.Minute),
        postgres.WithConnMaxIdleTime(1*time.Minute),
    )
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()

    // Select single record
    var user User
    found, err := db.Select("SELECT * FROM users WHERE id = :id", &user, "id", 1).One(ctx)
    if err != nil {
        log.Fatal(err)
    }
    if found {
        log.Printf("User: %+v", user)
    }

    // Select multiple records with debug
    var users []User
    found, err = db.Select("SELECT * FROM users WHERE active = :active", &users, "active", true).Debug().Many(ctx)
    if err != nil {
        log.Fatal(err)
    }

    // Insert with returning ID
    id, err := db.Insert("INSERT INTO users (name, email) VALUES (:name, :email) RETURNING id", 
        "name", "John Doe", 
        "email", "john@example.com").Exec(ctx)
    if err != nil {
        log.Fatal(err)
    }

    // Transaction
    result, err := db.Insert("INSERT INTO users (name) VALUES (:name) RETURNING id", "name", "User1").
        Insert("INSERT INTO profiles (user_id, bio) VALUES (:user_id, :bio)", 
            "user_id", db.FromResult("INSERT INTO users (name) VALUES (:name) RETURNING id"), 
            "bio", "User bio").
        ExecInTx(ctx)
    if err != nil {
        log.Fatal(err)
    }
}

📊 Performance Optimizations

1. Connection Pool Configuration
db, err := postgres.New(
    // Optimal for web applications with moderate traffic
    postgres.WithMaxOpenConns(25),        // Max connections
    postgres.WithMaxIdleConns(5),         // Idle connections
    postgres.WithConnMaxLifetime(5*time.Minute),  // Connection lifetime
    postgres.WithConnMaxIdleTime(1*time.Minute),  // Idle timeout
)
2. Context with Timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

found, err := db.Select("SELECT * FROM users WHERE id = :id", &user, "id", 1).One(ctx)
3. Prepared Statements

The library automatically uses prepared statements and closes them to prevent memory leaks.

4. Debug Mode

Enable debug mode for individual queries to see SQL execution:

// Debug a specific select query
found, err := db.Select("SELECT * FROM users WHERE id = :id", &user, "id", 1).Debug().One(ctx)

// Debug an insert query
id, err := db.Insert("INSERT INTO users (name) VALUES (:name) RETURNING id", "name", "John").Debug().Exec(ctx)

🔒 Security Best Practices

1. Parameter Binding

Always use named parameters to prevent SQL injection:

// ✅ CORRECT
db.Select("SELECT * FROM users WHERE email = :email", &user, "email", userEmail)

// ❌ WRONG - vulnerable to SQL injection
db.Select(fmt.Sprintf("SELECT * FROM users WHERE email = '%s'", userEmail), &user)
2. Connection Security
postgres.New(
    postgres.WithSSLMode("require"),  // Use SSL in production
    postgres.WithHost("localhost"),   // Don't expose to public
)

🔧 Error Handling

_, err := db.Insert("INSERT INTO users (email) VALUES (:email)", "email", "duplicate@example.com").Exec(ctx)
if err != nil {
    // Handle database errors
    log.Printf("Database error: %v", err)
    return err
}

🤝 Contributing

We welcome contributions! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

🌟 Support

If you encounter any issues or have questions, please open an issue on GitHub.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Filter

func Filter(sl []string, m map[string]string) (result []string)

Filter filters the slice of strings based on the map.

func NewPipeline

func NewPipeline() *pipeline

NewPipeline creates a new pipeline

func Pairs

func Pairs(kv []any) (map[string]any, error)

Pairs converts a slice of key-value pairs to a map.

func PairsHook

func PairsHook(kv []any, ids map[string]any, hook string) (map[string]any, error)

PairsHook converts a slice of key-value pairs to a map. If the value is a string and starts with the hook, it will be replaced with the value from the ids map.

Types

type Exec

type Exec interface {
	Debug() Exec
	Exec(ctx context.Context) (any, error)
	ExecInTx(ctx context.Context) (res *ExecResult, err error)
	Insert(query string, kv ...any) Exec
	Update(query string, kv ...any) Exec
	Delete(query string, kv ...any) Exec
	Wrap(exec Exec) Exec
	FromResult(from string) string
}

type ExecResult

type ExecResult struct {
	// contains filtered or unexported fields
}

ExecResult is the result of an exec query.

func (*ExecResult) TxResult

func (e *ExecResult) TxResult(query string) any

type Option

type Option func(*config)

Option is a function that configures the postgres database.

func WithConnMax

func WithConnMax(maxOpenConns int) Option

WithConnMax sets the max conn. maxOpenConns is the maximum number of open connections to the database.

func WithConnMaxIdleTime

func WithConnMaxIdleTime(maxConnIdleTime time.Duration) Option

WithConnMaxIdleTime sets the max conn idle time. maxConnIdleTime is the maximum amount of time a connection may be idle.

func WithConnMaxLifetime

func WithConnMaxLifetime(maxConnLifetime time.Duration) Option

WithConnMaxLifetime sets the max conn lifetime. maxConnLifetime is the maximum amount of time a connection may be reused.

func WithDBName

func WithDBName(dbName string) Option

WithDBName sets the db name. dbName is the name of the database to connect to.

func WithDriverName

func WithDriverName(driverName string) Option

WithDriverName sets the driver name.

func WithDsn

func WithDsn(dsn string) Option

WithDsn sets the dsn. dsn is the data source name.

func WithHost

func WithHost(host string) Option

WithHost sets the host.

func WithMaxIdleConns

func WithMaxIdleConns(maxIdleConns int) Option

func WithMaxOpenConns

func WithMaxOpenConns(maxOpenConns int) Option

WithMaxOpenConns sets the max open conns. maxOpenConns is the maximum number of open connections to the database.

func WithPassword

func WithPassword(password string) Option

WithPassword sets the password. password is the password to connect with.

func WithPort

func WithPort(port int) Option

WithPort sets the port. port is the port number to connect to.

func WithSSLMode

func WithSSLMode(sslMode string) Option

WithSSLMode sets the ssl mode. sslMode is the SSL mode to use.

func WithUser

func WithUser(user string) Option

WithUser sets the user. user is the username to connect as.

type Postgres

type Postgres interface {
	Select(query string, dest any, kv ...any) Select
	Insert(query string, kv ...any) Exec
	Update(query string, kv ...any) Exec
	Delete(query string, kv ...any) Exec
	FromResult(from string) string
}

Postgres is the interface for the postgres database client.

func New

func New(opts ...Option) (Postgres, error)

New creates a new postgres client

type Select

type Select interface {
	Debug() Select
	One(ctx context.Context) (found bool, err error)
	Many(ctx context.Context) (found bool, err error)
}

Select is an interface for selecting data from the database.

type StringSlice

type StringSlice []string

func (*StringSlice) Scan

func (s *StringSlice) Scan(src any) error

func (StringSlice) Value

func (s StringSlice) Value() (driver.Value, error)

Jump to

Keyboard shortcuts

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