From c5b737287e69f6b0395b441373dd0ce60127031b Mon Sep 17 00:00:00 2001 From: 5803024006 Date: Wed, 1 Oct 2025 06:42:15 -0400 Subject: [PATCH] Upload files to "/" --- database.sql | 26 +++++++++++++++++ enrollment.go | 33 ++++++++++++++++++++++ go.mod | 5 ++++ go.sum | 2 ++ pool_manager.go | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 141 insertions(+) create mode 100644 database.sql create mode 100644 enrollment.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 pool_manager.go diff --git a/database.sql b/database.sql new file mode 100644 index 0000000..ea2d5f4 --- /dev/null +++ b/database.sql @@ -0,0 +1,26 @@ +-- -------------------------------------------------------- +-- Host: 202.46.28.160 +-- Server version: PostgreSQL 17.5 (Debian 17.5-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit +-- Server OS: +-- HeidiSQL Version: 12.10.0.7000 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- Data exporting was unselected. + +-- Data exporting was unselected. + +-- Data exporting was unselected. + +/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */; +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */; diff --git a/enrollment.go b/enrollment.go new file mode 100644 index 0000000..b8bfbfa --- /dev/null +++ b/enrollment.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + "sync" + "time" +) + +var ( + IdempotencyStore = make(map[string]string) + mu sync.Mutex +) + +func EnrollCourseIdempotent(key string) string { + mu.Lock() + if val, ok := IdempotencyStore[key]; ok { + mu.Unlock() + return fmt.Sprintf("Hasil cache: %s", val) + } + mu.Unlock() + + // proses baru + fmt.Println("Memproses enrollment baru...") + time.Sleep(1500 * time.Millisecond) + + result := "Enrollment berhasil untuk " + key + + mu.Lock() + IdempotencyStore[key] = result + mu.Unlock() + + return result +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..832e4fb --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module 07-06-Melvin-Goroutine + +go 1.25.1 + +require github.com/lib/pq v1.10.9 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..aeddeae --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= diff --git a/pool_manager.go b/pool_manager.go new file mode 100644 index 0000000..68eae89 --- /dev/null +++ b/pool_manager.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "database/sql" + "fmt" + "time" + + _ "github.com/lib/pq" +) + +var DB *sql.DB + +func InitDB() { + dbURL := "postgres://5803024006:5803024006@202.46.28.160:45432/tgs03_5803024006?sslmode=disable" + + var err error + DB, err = sql.Open("postgres", dbURL) + if err != nil { + panic(err) + } + + // setting pool + DB.SetMaxOpenConns(10) + DB.SetMaxIdleConns(5) + DB.SetConnMaxLifetime(time.Minute * 5) + + // test koneksi + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + if err = DB.PingContext(ctx); err != nil { + panic(fmt.Sprintf("gagal koneksi database: %v", err)) + } + + fmt.Println("✅ Database connected!") +} + +// ===== CRUD Contoh ===== + +func CreateUser(name, email string) (int, error) { + var id int + err := DB.QueryRow(`INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id`, name, email).Scan(&id) + return id, err +} + +func CreateCourse(title, desc string) (int, error) { + var id int + err := DB.QueryRow(`INSERT INTO courses (title, description) VALUES ($1, $2) RETURNING id`, title, desc).Scan(&id) + return id, err +} + +func EnrollUser(userID, courseID int) error { + _, err := DB.Exec(`INSERT INTO enrollments (user_id, course_id) VALUES ($1, $2) ON CONFLICT (user_id, course_id) DO NOTHING`, userID, courseID) + return err +} + +func ListEnrollments() error { + rows, err := DB.Query(`SELECT u.name, c.title, e.created_at + FROM enrollments e + JOIN users u ON e.user_id = u.id + JOIN courses c ON e.course_id = c.id`) + if err != nil { + return err + } + defer rows.Close() + + fmt.Println("=== Enrollments ===") + for rows.Next() { + var name, title string + var created time.Time + _ = rows.Scan(&name, &title, &created) + fmt.Printf("%s enrolled in %s at %v\n", name, title, created) + } + return nil +}