package main import ( "fmt" "io" "net/http" "os" "time" "github.com/jmoiron/sqlx" _ "github.com/mattn/go-sqlite3" ) // This is a function that takes a long time to run // Useful for demonstrating concurrency (goroutines) func delayPrint() { time.Sleep(5 * time.Second) fmt.Printf("delay print\n") } // Reads files from the migrations directory and runs them func runMigrations(db *sqlx.DB) error { // Read the migrations directory files, err := os.ReadDir("migrations") if err != nil { return err } // Run each migration file for _, file := range files { // Skip directories if file.IsDir() { continue } // Read the migration file content, err := os.ReadFile("migrations/" + file.Name()) if err != nil { return err } // Execute the migration SQL _, err = db.Exec(string(content)) if err != nil { fmt.Printf("Error executing migration %s: %s\n", file.Name(), err) return err } fmt.Printf("Migration %s executed\n", file.Name()) } fmt.Println("Migrations complete") return nil } // This is what a handler looks like func handler(w http.ResponseWriter, r *http.Request) { fmt.Println("Request received") go delayPrint() // This will run in the background io.WriteString(w, "This is my website!\n") } func dbConnect() *sqlx.DB { // Check for the environment variable dbpath := os.Getenv("SQLITE_DB_PATH") // Default to something reasonable if dbpath == "" { dbpath = "./db.sqlite3" } // Open the database // db, err := sqlx.Connect("sqlite3", ":memory:") db, err := sqlx.Connect("sqlite3", dbpath) if err != nil { panic(err) } err = db.Ping() if err != nil { panic(err) } // Run the migrations err = runMigrations(db) if err != nil { panic(err) } return db } func main() { println("Starting server...") // Connect to the database db := dbConnect() defer db.Close() // Tx is a transaction tx := db.MustBegin() tx.MustExec("INSERT INTO users (username, password) VALUES (?, ?)", "John Doe", "a") err := tx.Commit() if err != nil { panic(err) } // This is how you query the database rows, err := db.Queryx("SELECT * FROM users") if err != nil { panic(err) } for rows.Next() { var user struct { ID int Username string Password string } err = rows.StructScan(&user) if err != nil { panic(err) } fmt.Printf("User: %d %s %s\n", user.ID, user.Username, user.Password) } // Mounting the handler fs := http.FileServer(http.Dir("static")) http.Handle("/", fs) http.HandleFunc("/hello", handler) // Start the server on port 8080 err = http.ListenAndServe(":8080", nil) if err != nil { panic(err) } }