109 lines
2.8 KiB
Go

package models
import (
"context"
"errors"
"fmt"
"reflect"
"strings"
"gorm.io/driver/postgres" // Für PostgreSQL
"gorm.io/gorm"
)
// Globale Variable für die DB-Verbindung
var defaultDB *gorm.DB
// DatabaseConfig enthält die Konfigurationsdaten für die Datenbankverbindung
type DatabaseConfig struct {
Host string
Port int
User string
Password string
DBName string
SSLMode string
}
// InitDB initialisiert die Datenbankverbindung (einmalig beim Start)
// mit der übergebenen Konfiguration
func InitDB(config DatabaseConfig) error {
// DSN (Data Source Name) erstellen
dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
config.Host, config.Port, config.User, config.Password, config.DBName, config.SSLMode)
// Datenbankverbindung herstellen
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
return fmt.Errorf("fehler beim Verbinden zur Datenbank: %w", err)
}
defaultDB = db
return nil
}
// GetEngine gibt die DB-Instanz zurück, ggf. mit context
func GetEngine(ctx context.Context) *gorm.DB {
// Falls in ctx eine spezielle Transaktion steckt, könnte man das hier prüfen
return defaultDB.WithContext(ctx)
}
// UpdateModel aktualisiert ein Modell anhand der gesetzten Pointer-Felder
func UpdateModel(ctx context.Context, model any, updates any) error {
updateValue := reflect.ValueOf(updates)
// Wenn updates ein Pointer ist, den Wert dahinter verwenden
if updateValue.Kind() == reflect.Ptr {
updateValue = updateValue.Elem()
}
// Stelle sicher, dass updates eine Struktur ist
if updateValue.Kind() != reflect.Struct {
return errors.New("updates muss eine Struktur sein")
}
updateType := updateValue.Type()
updateMap := make(map[string]any)
// Durch alle Felder iterieren
for i := 0; i < updateValue.NumField(); i++ {
field := updateValue.Field(i)
fieldType := updateType.Field(i)
// Überspringen von unexportierten Feldern
if !fieldType.IsExported() {
continue
}
// Spezialfall: ID-Feld überspringen (nur für Updates verwenden)
if fieldType.Name == "ID" {
continue
}
// Für Pointer-Typen prüfen, ob sie nicht nil sind
if field.Kind() == reflect.Ptr && !field.IsNil() {
// Feldname aus GORM-Tag extrahieren oder Standard-Feldnamen verwenden
fieldName := fieldType.Name
if tag, ok := fieldType.Tag.Lookup("gorm"); ok {
// Tag-Optionen trennen
options := strings.Split(tag, ";")
for _, option := range options {
if strings.HasPrefix(option, "column:") {
fieldName = strings.TrimPrefix(option, "column:")
break
}
}
}
// Den Wert hinter dem Pointer verwenden
updateMap[fieldName] = field.Elem().Interface()
}
}
if len(updateMap) == 0 {
return nil // Nichts zu aktualisieren
}
return GetEngine(ctx).Model(model).Updates(updateMap).Error
}