86 lines
1.9 KiB
Go
86 lines
1.9 KiB
Go
package db
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"server/internal/config"
|
|
"strings"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
"gorm.io/driver/postgres"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var DB *gorm.DB
|
|
|
|
// GetDB returns the global *gorm.DB instance. It panics if the database is not initialized.
|
|
func GetDB() (*gorm.DB, error) {
|
|
if DB == nil {
|
|
cfg, err := config.GetConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
DB, err = InitDB(cfg.Db)
|
|
if err != nil {
|
|
fmt.Printf("Failed to initialize database: %v\n", err)
|
|
return nil, err
|
|
}
|
|
}
|
|
return DB, nil
|
|
}
|
|
|
|
// Init opens the configured database connection and runs schema migrations.
|
|
func InitDB(cfg config.DbConfig) (*gorm.DB, error) {
|
|
switch cfg.Driver {
|
|
case "sqlite":
|
|
if err := ensureSQLiteDir(cfg.DSN); err != nil {
|
|
return nil, fmt.Errorf("prepare sqlite path: %w", err)
|
|
}
|
|
DB, err := gorm.Open(sqlite.Open(cfg.DSN), &gorm.Config{})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open sqlite: %w", err)
|
|
}
|
|
return DB, nil
|
|
case "postgres":
|
|
DB, err := gorm.Open(postgres.Open(cfg.DSN), &gorm.Config{})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open postgres: %w", err)
|
|
}
|
|
return DB, nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported driver %q", cfg.Driver)
|
|
}
|
|
}
|
|
|
|
func ensureSQLiteDir(dsn string) error {
|
|
pathSpec := dsn
|
|
if idx := strings.Index(pathSpec, "?"); idx >= 0 {
|
|
pathSpec = pathSpec[:idx]
|
|
}
|
|
pathSpec = strings.TrimPrefix(pathSpec, "file:")
|
|
if pathSpec == "" || strings.Contains(pathSpec, ":memory:") {
|
|
return nil
|
|
}
|
|
dir := filepath.Dir(pathSpec)
|
|
if dir == "." || dir == "" {
|
|
return nil
|
|
}
|
|
return os.MkdirAll(dir, 0o755)
|
|
}
|
|
|
|
// dbFromCtx extracts *gorm.DB from Fiber context.
|
|
func dbFromCtx(c fiber.Ctx) (*gorm.DB, error) {
|
|
dbVal := c.Locals("db")
|
|
db, ok := dbVal.(*gorm.DB)
|
|
if !ok || db == nil {
|
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "database unavailable")
|
|
}
|
|
return db, nil
|
|
}
|
|
|
|
func DBFromCtx(c fiber.Ctx) (*gorm.DB, error) {
|
|
return dbFromCtx(c)
|
|
}
|