go-quasar-partial-ssr/backend/internal/db/db.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)
}