// Package db gère la connexion à PostgreSQL et l'application des migrations. package db import ( "context" "database/sql" "fmt" "time" "github.com/jackc/pgx/v5/pgxpool" _ "github.com/jackc/pgx/v5/stdlib" // enregistre le driver database/sql "pgx" "github.com/pressly/goose/v3" "pdfeditor/migrations" ) // Connect ouvre un pool de connexions pgx vers la base, en réessayant // quelques fois pour laisser le temps au service Postgres de démarrer. func Connect(ctx context.Context, databaseURL string) (*pgxpool.Pool, error) { cfg, err := pgxpool.ParseConfig(databaseURL) if err != nil { return nil, fmt.Errorf("DATABASE_URL invalide : %w", err) } var pool *pgxpool.Pool // On tente plusieurs fois car la base peut ne pas être encore prête au boot. for attempt := 1; attempt <= 10; attempt++ { pool, err = pgxpool.NewWithConfig(ctx, cfg) if err == nil { if pingErr := pool.Ping(ctx); pingErr == nil { return pool, nil } else { err = pingErr pool.Close() } } time.Sleep(2 * time.Second) } return nil, fmt.Errorf("connexion à la base impossible après plusieurs tentatives : %w", err) } // Migrate applique toutes les migrations embarquées via goose. // goose s'appuie sur database/sql ; on ouvre une connexion *sql.DB // à partir de la même configuration pgx le temps de la migration. func Migrate(databaseURL string) error { sqlDB, err := openStdlib(databaseURL) if err != nil { return fmt.Errorf("ouverture connexion migration : %w", err) } defer sqlDB.Close() goose.SetBaseFS(migrations.FS) if err := goose.SetDialect("postgres"); err != nil { return fmt.Errorf("dialecte goose : %w", err) } if err := goose.Up(sqlDB, "."); err != nil { return fmt.Errorf("application des migrations : %w", err) } return nil } // openStdlib ouvre une connexion database/sql basée sur le driver pgx stdlib. func openStdlib(databaseURL string) (*sql.DB, error) { return sql.Open("pgx", databaseURL) }