Files
PinePods-nix/PinePods-0.8.2/gpodder-api/internal/db/postgres.go
2026-03-03 10:57:43 -05:00

92 lines
2.9 KiB
Go

package db
import (
"database/sql"
"fmt"
"net/url"
"os"
"pinepods/gpodder-api/config"
"strings"
_ "github.com/lib/pq"
)
// PostgresDB represents a connection to the PostgreSQL database
type PostgresDB struct {
*sql.DB
}
// NewPostgresDB creates a new PostgreSQL database connection
func NewPostgresDB(cfg config.DatabaseConfig) (*PostgresDB, error) {
// Print connection details for debugging (hide password for security)
fmt.Printf("Connecting to database: host=%s port=%d user=%s dbname=%s sslmode=%s\n",
cfg.Host, cfg.Port, cfg.User, cfg.DBName, cfg.SSLMode)
// Get password directly from environment to handle special characters
password := os.Getenv("DB_PASSWORD")
if password == "" {
// Fall back to config if env var is empty
password = cfg.Password
}
// Escape special characters in password
escapedPassword := url.QueryEscape(password)
// Use a connection string without password for logging
logConnStr := fmt.Sprintf(
"host=%s port=%d user=%s dbname=%s sslmode=%s",
cfg.Host, cfg.Port, cfg.User, cfg.DBName, cfg.SSLMode,
)
fmt.Printf("Connection string (without password): %s\n", logConnStr)
// Build the actual connection string with password
connStr := fmt.Sprintf(
"host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
cfg.Host, cfg.Port, cfg.User, password, cfg.DBName, cfg.SSLMode,
)
// Try alternate connection string format if the first fails
db, err := sql.Open("postgres", connStr)
if err != nil {
// Try URL format connection string
urlConnStr := fmt.Sprintf(
"postgres://%s:%s@%s:%d/%s?sslmode=%s",
cfg.User, escapedPassword, cfg.Host, cfg.Port, cfg.DBName, cfg.SSLMode,
)
fmt.Println("First connection attempt failed, trying URL format...")
db, err = sql.Open("postgres", urlConnStr)
if err != nil {
return nil, fmt.Errorf("failed to open database connection: %w", err)
}
}
// Test the connection
if err := db.Ping(); err != nil {
db.Close()
// Check if error contains password authentication failure
if strings.Contains(err.Error(), "password authentication failed") {
// Print environment variables (hide password)
fmt.Println("Password authentication failed. Environment variables:")
fmt.Printf("DB_HOST=%s\n", os.Getenv("DB_HOST"))
fmt.Printf("DB_PORT=%s\n", os.Getenv("DB_PORT"))
fmt.Printf("DB_USER=%s\n", os.Getenv("DB_USER"))
fmt.Printf("DB_NAME=%s\n", os.Getenv("DB_NAME"))
fmt.Printf("DB_PASSWORD=*** (length: %d)\n", len(os.Getenv("DB_PASSWORD")))
}
return nil, fmt.Errorf("failed to ping database: %w", err)
}
fmt.Println("Successfully connected to the database")
// Migrations are now handled by the Python migration system
// Skip Go migrations to avoid conflicts
fmt.Println("Skipping Go migrations - now handled by Python migration system")
return &PostgresDB{DB: db}, nil
}
// Close closes the database connection
func (db *PostgresDB) Close() error {
return db.DB.Close()
}