Files
pipely/internal/database/database.go
T
siujamo e070a3fb5f feat: initial open-source release of Pipely
OTA update server designed for high-concurrency, low-bandwidth deployments.
GORM-backed PostgreSQL, JWT auth, device management, artefact versioning,
deployment rollout with gated rate-limited downloads, and a React admin panel.
2026-07-07 10:29:28 +08:00

84 lines
2.1 KiB
Go

package database
import (
"fmt"
"log"
"net/url"
"strings"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"onixbyte.com/message-converter-manifest/internal/model"
)
// Connect opens a PostgreSQL connection via GORM. If the target database does
// not exist it is created automatically. Tables are then migrated.
func Connect(databaseURL string) (*gorm.DB, error) {
dbName, err := ensureDatabase(databaseURL)
if err != nil {
return nil, err
}
db, err := gorm.Open(postgres.Open(databaseURL), &gorm.Config{
Logger: logger.Default.LogMode(logger.Warn),
})
if err != nil {
return nil, fmt.Errorf("failed to open database: %w", err)
}
sqlDB, err := db.DB()
if err != nil {
return nil, fmt.Errorf("failed to get underlying sql.DB: %w", err)
}
sqlDB.SetMaxOpenConns(50)
sqlDB.SetMaxIdleConns(10)
log.Printf("[database] Connected to PostgreSQL database: %s", dbName)
return db, nil
}
// AutoMigrate creates or updates tables to match the model definitions.
func AutoMigrate(db *gorm.DB) error {
return db.AutoMigrate(
&model.AdminUser{},
&model.Device{},
&model.Artefact{},
&model.Deployment{},
&model.DeploymentDevice{},
)
}
// ensureDatabase creates the target database if it does not exist.
func ensureDatabase(databaseURL string) (string, error) {
u, err := url.Parse(databaseURL)
if err != nil {
return "", fmt.Errorf("invalid database URL: %w", err)
}
dbName := strings.TrimPrefix(u.Path, "/")
adminURL := *u
adminURL.Path = "/postgres"
db, err := gorm.Open(postgres.Open(adminURL.String()), &gorm.Config{})
if err != nil {
return "", fmt.Errorf("failed to connect to admin database: %w", err)
}
var exists bool
db.Raw("SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = ?)", dbName).Scan(&exists)
if !exists {
if err := db.Exec(fmt.Sprintf(`CREATE DATABASE "%s"`, dbName)).Error; err != nil {
return "", fmt.Errorf("failed to create database %s: %w", dbName, err)
}
log.Printf("[database] Created database: %s", dbName)
}
sqlDB, _ := db.DB()
if sqlDB != nil {
sqlDB.Close()
}
return dbName, nil
}