92 lines
2.9 KiB
Go
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()
|
|
}
|