Skip to content

Latest commit

 

History

History
133 lines (104 loc) · 3.66 KB

File metadata and controls

133 lines (104 loc) · 3.66 KB

database

A thin wrapper around GORM and the PostgreSQL driver that handles connection setup, pool configuration, health checks, and operates with configurable query logging.

Quick start

cfg := database.Config{
    Host:     "localhost",
    Port:     5432,
    Username: "myuser",
    Password: "mypassword",
    Name:     "mydb",
    SSLMode:  "disable",
}

db, err := database.New(cfg)
if err != nil {
    log.Fatal(err)
}
defer database.Close(db)

db is a *gorm.DB ready to use for all GORM operations.

Configuration

Field Type Required Description
Host string Database host
Port int Port number. Omit to use the driver default
Username string Database user
Password string Database password. Special characters are URL-encoded automatically
Name string Database name
SSLMode string PostgreSQL SSL mode (disable, require, verify-full, …)
MaxIdleConns int Maximum idle connections in the pool
MaxOpenConns int Maximum open connections in the pool
MaxConnLifetimeSeconds int Maximum connection lifetime in seconds
LogLevel LogLevel Query log verbosity (see below). Defaults to LogError

Log levels

Control how much GORM logs about the queries it runs.

Constant Behaviour
database.LogSilent No output at all
database.LogError Errors only (default)
database.LogWarn Errors + slow queries
database.LogInfo Every SQL statement — useful in development
// Development: log every query
cfg := database.Config{
    // ...
    LogLevel: database.LogInfo,
}

// Production: log errors only (or nothing)
cfg := database.Config{
    // ...
    LogLevel: database.LogError, // same as omitting the field
}

API

New(cfg Config) (*gorm.DB, error)

Validates the config, opens a connection, configures the pool, and pings the server. Returns an error if any step fails. On success it logs a single INFO line through log/slog.

Close(db *gorm.DB) error

Closes the underlying sql.DB. Safe to call with a nil argument (no-op). Typically deferred in main:

db, err := database.New(cfg)
// ...
defer func() {
    if err := database.Close(db); err != nil {
        log.Printf("closing database: %v", err)
    }
}()

HealthCheck(db *gorm.DB) error

Pings the database and returns a non-nil error if the connection is unhealthy. Intended for use in a /healthz or /readyz HTTP handler:

func readyzHandler(db *gorm.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if err := database.HealthCheck(db); err != nil {
            http.Error(w, "database unavailable", http.StatusServiceUnavailable)
            return
        }
        w.WriteHeader(http.StatusOK)
    }
}

Connection pool tuning

cfg := database.Config{
    // ...
    MaxIdleConns:           5,
    MaxOpenConns:           25,
    MaxConnLifetimeSeconds: 300, // 5 minutes
}

Any pool field left at 0 is skipped so the driver's own default applies.

Testing

Unit tests cover Config.Validate, Config.DSN, gormLogLevel mapping, and the lifecycle functions (New, Close, HealthCheck) without requiring a running database. Run them with:

go test ./database/...

Integration tests that need a real PostgreSQL instance can be gated with a build tag or by checking an environment variable:

func TestIntegration(t *testing.T) {
    dsn := os.Getenv("TEST_DATABASE_URL")
    if dsn == "" {
        t.Skip("TEST_DATABASE_URL not set")
    }
    // ...
}