From e170165842ecf0625fe0e7709b7ccf4e3541c14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Markovi=C4=87?= Date: Mon, 1 Jun 2026 00:44:16 +0200 Subject: [PATCH] Dodavanje SQLite konekcije i sistema migracija --- cmd/ntech/main.go | 22 ++++++++- internal/db/sqlite/migracije.go | 88 +++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 internal/db/sqlite/migracije.go diff --git a/cmd/ntech/main.go b/cmd/ntech/main.go index 9ce3b78..1bb8b74 100644 --- a/cmd/ntech/main.go +++ b/cmd/ntech/main.go @@ -7,6 +7,7 @@ import ( "os" "ntech/internal/config" + "ntech/internal/db/sqlite" "github.com/go-chi/chi/v5" "github.com/joho/godotenv" @@ -27,13 +28,32 @@ func main() { port = "8080" } + // putanja do SQLite fajla + putanjaBaze := os.Getenv("NTECH_SQLITE") + if putanjaBaze == "" { + putanjaBaze = "ntech.db" + } + + // otvaramo konekciju ka bazi + db, err := sqlite.OtvoriDB(putanjaBaze) + if err != nil { + log.Fatalf("Greška pri otvaranju baze: %v", err) + } + defer db.Close() + + // pokrećemo migracije + if err := sqlite.PokreniMigracije(db, "migrations"); err != nil { + log.Fatalf("Greška pri migracijama: %v", err) + } + log.Println("Migracije uspešno izvršene") + r := chi.NewRouter() r.Get("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Zdravo iz NTech-a") }) log.Printf("NTech pokrenut na portu %s", port) - err := http.ListenAndServe(":"+port, r) + err = http.ListenAndServe(":"+port, r) if err != nil { log.Fatalf("Greška: port %s je zauzet ili nije dostupan", port) } diff --git a/internal/db/sqlite/migracije.go b/internal/db/sqlite/migracije.go new file mode 100644 index 0000000..69f757e --- /dev/null +++ b/internal/db/sqlite/migracije.go @@ -0,0 +1,88 @@ +package sqlite + +import ( + "database/sql" + "fmt" + "os" + "path/filepath" + "sort" + + _ "modernc.org/sqlite" +) + +// OtvoriDB otvara konekciju ka SQLite bazi i uključuje strane ključeve +func OtvoriDB(putanja string) (*sql.DB, error) { + db, err := sql.Open("sqlite", putanja) + if err != nil { + return nil, fmt.Errorf("ntech: OtvoriDB: %w", err) + } + + // uključujemo podršku za strane ključeve — SQLite je ne uključuje automatski + if _, err := db.Exec("PRAGMA foreign_keys = ON"); err != nil { + return nil, fmt.Errorf("ntech: OtvoriDB: foreign_keys: %w", err) + } + + return db, nil +} + +// PokreniMigracije izvršava sve SQL fajlove iz foldera koji još nisu izvršeni +func PokreniMigracije(db *sql.DB, folder string) error { + // kreiramo tabelu za praćenje migracija ako ne postoji + _, err := db.Exec(` + CREATE TABLE IF NOT EXISTS migracije ( + naziv TEXT PRIMARY KEY, + datum_izvrsavanja DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP + ) + `) + if err != nil { + return fmt.Errorf("ntech: PokreniMigracije: kreiranje tabele: %w", err) + } + + // čitamo sve .sql fajlove iz foldera + unosi, err := os.ReadDir(folder) + if err != nil { + return fmt.Errorf("ntech: PokreniMigracije: čitanje foldera: %w", err) + } + + // sortiramo po imenu da bi se izvršavali po redu (001, 002, ...) + sort.Slice(unosi, func(i, j int) bool { + return unosi[i].Name() < unosi[j].Name() + }) + + for _, unos := range unosi { + if filepath.Ext(unos.Name()) != ".sql" { + continue + } + + naziv := unos.Name() + + // proveravamo da li je migracija već izvršena + var broj int + err := db.QueryRow("SELECT COUNT(*) FROM migracije WHERE naziv = ?", naziv).Scan(&broj) + if err != nil { + return fmt.Errorf("ntech: PokreniMigracije: provera %s: %w", naziv, err) + } + if broj > 0 { + continue + } + + // čitamo sadržaj SQL fajla + putanja := filepath.Join(folder, naziv) + sadrzaj, err := os.ReadFile(putanja) + if err != nil { + return fmt.Errorf("ntech: PokreniMigracije: čitanje %s: %w", naziv, err) + } + + // izvršavamo SQL + if _, err := db.Exec(string(sadrzaj)); err != nil { + return fmt.Errorf("ntech: PokreniMigracije: izvršavanje %s: %w", naziv, err) + } + + // upisujemo u tabelu migracija da je izvršena + if _, err := db.Exec("INSERT INTO migracije (naziv) VALUES (?)", naziv); err != nil { + return fmt.Errorf("ntech: PokreniMigracije: upis %s: %w", naziv, err) + } + } + + return nil +}