package main import ( "context" "database/sql" "fmt" "net/url" "os" "strings" "github.com/danielgtaylor/huma/v2" "github.com/danielgtaylor/huma/v2/adapters/humaecho" "github.com/golang-migrate/migrate/v4" _ "github.com/golang-migrate/migrate/v4/database/postgres" _ "github.com/golang-migrate/migrate/v4/source/file" "github.com/jackc/pgx/v5/pgxpool" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" _ "github.com/lib/pq" "completed/internal/api" "completed/internal/db" ) func ensureDatabase(dbURL string) error { u, err := url.Parse(dbURL) if err != nil { return err } dbName := strings.TrimPrefix(u.Path, "/") if dbName == "" { return fmt.Errorf("database name is empty in URL: %s", dbURL) } // Connect to 'postgres' database to create the new DB u.Path = "/postgres" db, err := sql.Open("postgres", u.String()) if err != nil { return err } defer db.Close() // Check if DB exists var exists bool err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = $1)", dbName).Scan(&exists) if err != nil { return err } if !exists { fmt.Printf("Database '%s' does not exist. Creating...\n", dbName) _, err = db.Exec(fmt.Sprintf("CREATE DATABASE \"%s\"", dbName)) if err != nil { return err } fmt.Printf("Database '%s' created successfully.\n", dbName) } else { fmt.Printf("Database '%s' already exists.\n", dbName) } return nil } func runMigrations(dbURL string) { m, err := migrate.New( "file:///app/db/migrations", // Path inside Docker container dbURL, ) if err != nil { // Fallback for local development if not in /app if os.Getenv("MIGRATION_PATH") != "" { m, err = migrate.New( "file://"+os.Getenv("MIGRATION_PATH"), dbURL, ) } else { // Try relative path default m, err = migrate.New( "file://db/migrations", dbURL, ) } } if err != nil { fmt.Fprintf(os.Stderr, "Migration initialization failed: %v\n", err) return } if err := m.Up(); err != nil && err != migrate.ErrNoChange { fmt.Fprintf(os.Stderr, "Migration failed: %v\n", err) } else { fmt.Println("Migrations ran successfully") } } func main() { // 1. Database connection dbURL := os.Getenv("DATABASE_URL") if dbURL == "" { dbURL = "postgres://user:password@localhost:5432/dbname?sslmode=disable" } // Ensure Database Exists if err := ensureDatabase(dbURL); err != nil { fmt.Fprintf(os.Stderr, "Failed to ensure database: %v\n", err) } // Run Migrations runMigrations(dbURL) pool, err := pgxpool.New(context.Background(), dbURL) if err != nil { fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err) os.Exit(1) } defer pool.Close() queries := db.New(pool) // 2. Setup Echo e := echo.New() e.Use(middleware.Logger()) e.Use(middleware.Recover()) // 3. Setup Huma humaApi := humaecho.New(e, huma.DefaultConfig("My API", "1.0.0")) // 4. Register Routes api.RegisterRoutes(humaApi, queries) // 5. Start Server port := os.Getenv("PORT") if port == "" { port = "8080" } e.Logger.Fatal(e.Start(":" + port)) }