package postgres import ( "context" "fmt" "os" "github.com/jackc/pgx/v5" ) // Config holds the database configuration. type Config struct { ctx context.Context Host string Port string User string Password string DBName string SSLMode string } // ConfigOption is a functional option for Config. type ConfigOption func(*Config) // WithContext sets the context on the config. func WithContext(ctx context.Context) ConfigOption { return func(c *Config) { c.ctx = ctx } } // NewConfig creates a new database configuration from environment variables. // DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_SSL_MODE fall back to sensible // defaults. DB_NAME is required and must be set in the environment. func NewConfig(opts ...ConfigOption) *Config { c := &Config{ Host: getEnvOrDefault("DB_HOST", "localhost"), Port: getEnvOrDefault("DB_PORT", "5432"), User: getEnvOrDefault("DB_USER", "postgres"), Password: getEnvOrDefault("DB_PASSWORD", "postgres"), DBName: os.Getenv("DB_NAME"), SSLMode: getEnvOrDefault("DB_SSL_MODE", "disable"), } for _, opt := range opts { opt(c) } return c } // DSN returns the database connection string in key=value format. func (c *Config) DSN() string { return fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s", c.Host, c.Port, c.User, c.Password, c.DBName, c.SSLMode) } // Connect creates a new single database connection using pgx. func (c *Config) Connect() (*pgx.Conn, error) { conn, err := pgx.Connect(c.Context(), c.DSN()) if err != nil { return nil, fmt.Errorf("failed to connect to database: %w", err) } return conn, nil } // Context returns the context associated with this config, defaulting to // context.Background() if none was set. func (c *Config) Context() context.Context { if c.ctx == nil { c.ctx = context.Background() } return c.ctx } // getEnvOrDefault returns the value of an environment variable or a fallback. func getEnvOrDefault(key, fallback string) string { if value := os.Getenv(key); value != "" { return value } return fallback }