// Path: Backend/internal/database/postgres.go package database import ( "context" "database/sql" "time" "github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/stdlib" "github.com/pressly/goose/v3" "moku-backend/db" ) type DB struct { Pool *pgxpool.Pool } func NewPostgres(databaseURL string) (*DB, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() config, err := pgxpool.ParseConfig(databaseURL) if err != nil { return nil, err } config.MaxConns = 25 config.MinConns = 5 config.MaxConnLifetime = time.Hour config.MaxConnIdleTime = 30 * time.Minute pool, err := pgxpool.NewWithConfig(ctx, config) if err != nil { return nil, err } if err := pool.Ping(ctx); err != nil { pool.Close() return nil, err } return &DB{Pool: pool}, nil } func (d *DB) MigrateUp() error { return d.runGoose(goose.Up) } func (d *DB) MigrateDown() error { return d.runGoose(goose.Down) } func (d *DB) MigrateReset() error { return d.runGoose(goose.Reset) } func (d *DB) MigrateStatus() error { return d.runGoose(goose.Status) } func (d *DB) runGoose(command func(*sql.DB, string, ...goose.OptionsFunc) error) error { if d == nil || d.Pool == nil { return nil } sqlDB := stdlib.OpenDBFromPool(d.Pool) defer sqlDB.Close() goose.SetBaseFS(db.Migrations) if err := goose.SetDialect("postgres"); err != nil { return err } return command(sqlDB, "migrations") } func (d *DB) Health(ctx context.Context) error { if d == nil || d.Pool == nil { return nil } return d.Pool.Ping(ctx) } func (d *DB) Close() { if d == nil || d.Pool == nil { return } d.Pool.Close() }