Files
common/database/pgdb/CLAUDE.md
Ask Bjørn Hansen 45308cd4bf feat(database): add PostgreSQL support with native pgx pool
Add PostgreSQL support to database package alongside existing MySQL support.
Both databases share common infrastructure (pool management, metrics,
transactions) while using database-specific connectors.

database/ changes:
- Add PostgresConfig struct and PostgreSQL connector using pgx/stdlib
- Change MySQL config from DBConfig to *MySQLConfig (pointer)
- Add Config.Validate() to prevent multiple database configs
- Add PostgreSQL connector with secure config building (no password in DSN)
- Add field validation and secure defaults (SSLMode="prefer")
- Support legacy flat PostgreSQL config format for backward compatibility
- Add tests for PostgreSQL configs and validation

New database/pgdb/ package:
- Native pgx connection pool support (*pgxpool.Pool)
- OpenPool() and OpenPoolWithConfigFile() APIs
- CreatePoolConfig() for secure config conversion
- PoolOptions for fine-grained pool control
- Full test coverage and documentation

Security:
- Passwords never exposed in DSN strings
- Set passwords separately in pgx config objects
- Validate all configuration before connection

Architecture:
- Shared code in database/ for both MySQL and PostgreSQL (sql.DB)
- database/pgdb/ for PostgreSQL-specific native pool support
2025-09-27 16:55:54 -07:00

2.8 KiB

pgdb - Native PostgreSQL Connection Pool

Primary package for PostgreSQL connections using native pgx pool (*pgxpool.Pool). Provides better performance and PostgreSQL-specific features compared to database/sql.

Usage

Basic Example

import (
    "context"
    "go.ntppool.org/common/database/pgdb"
)

func main() {
    ctx := context.Background()

    // Open pool with default options
    pool, err := pgdb.OpenPool(ctx, pgdb.DefaultPoolOptions())
    if err != nil {
        log.Fatal(err)
    }
    defer pool.Close()

    // Use the pool for queries
    row := pool.QueryRow(ctx, "SELECT version()")
    var version string
    row.Scan(&version)
}

With Custom Config File

pool, err := pgdb.OpenPoolWithConfigFile(ctx, "/path/to/database.yaml")

With Custom Pool Settings

opts := pgdb.DefaultPoolOptions()
opts.MaxConns = 50
opts.MinConns = 5
opts.MaxConnLifetime = 2 * time.Hour

pool, err := pgdb.OpenPool(ctx, opts)

Configuration Format

postgres:
  host: localhost
  port: 5432
  user: myuser
  pass: mypassword
  name: mydb
  sslmode: prefer

Legacy: Flat Format (backward compatible)

host: localhost
port: 5432
user: myuser
pass: mypassword
name: mydb
sslmode: prefer

Configuration Options

PoolOptions

  • ConfigFiles - List of config file paths to search (default: database.yaml, /vault/secrets/database.yaml)
  • MinConns - Minimum connections (default: 0)
  • MaxConns - Maximum connections (default: 25)
  • MaxConnLifetime - Connection lifetime (default: 1 hour)
  • MaxConnIdleTime - Idle timeout (default: 30 minutes)
  • HealthCheckPeriod - Health check interval (default: 1 minute)

PostgreSQL Config Fields

  • host - Database host (required)
  • user - Database user (required)
  • pass - Database password
  • name - Database name (required)
  • port - Port number (default: 5432)
  • sslmode - SSL mode: disable, allow, prefer, require, verify-ca, verify-full (default: prefer)

Environment Variables

  • DATABASE_CONFIG_FILE - Override config file location

When to Use

Use pgdb.OpenPool() (this package) when:

  • You need native PostgreSQL features (LISTEN/NOTIFY, COPY, etc.)
  • You want better performance
  • You're writing new PostgreSQL code

Use database.OpenDB() (sql.DB) when:

  • You need database-agnostic code
  • You're using SQLC or other tools that expect database/sql
  • You need to support both MySQL and PostgreSQL

Security

This package avoids password exposure by:

  1. Never constructing DSN strings with passwords
  2. Setting passwords separately in pgx config objects
  3. Validating all configuration before connection

See Also