231 lines
6.3 KiB
Go

package models
import (
"context"
"errors"
"fmt"
"github.com/oklog/ulid/v2"
"gorm.io/gorm"
)
// Project repräsentiert ein Projekt im System
type Project struct {
EntityBase
Name string `gorm:"column:name;not null"`
CustomerID ulid.ULID `gorm:"column:customer_id;type:uuid;not null"`
// Beziehungen (für Eager Loading)
Customer *Customer `gorm:"foreignKey:CustomerID"`
}
// TableName gibt den Tabellennamen für GORM an
func (Project) TableName() string {
return "projects"
}
// ProjectCreate enthält die Felder zum Erstellen eines neuen Projekts
type ProjectCreate struct {
Name string
CustomerID ulid.ULID
}
// ProjectUpdate enthält die aktualisierbaren Felder eines Projekts
type ProjectUpdate struct {
ID ulid.ULID `gorm:"-"` // Ausschließen von Updates
Name *string `gorm:"column:name"`
CustomerID *ulid.ULID `gorm:"column:customer_id"`
}
// Validate prüft, ob die Create-Struktur gültige Daten enthält
func (pc *ProjectCreate) Validate() error {
if pc.Name == "" {
return errors.New("project name darf nicht leer sein")
}
// Prüfung auf gültige CustomerID
if pc.CustomerID.Compare(ulid.ULID{}) == 0 {
return errors.New("customerID darf nicht leer sein")
}
return nil
}
// Validate prüft, ob die Update-Struktur gültige Daten enthält
func (pu *ProjectUpdate) Validate() error {
if pu.Name != nil && *pu.Name == "" {
return errors.New("project name darf nicht leer sein")
}
return nil
}
// GetProjectByID sucht ein Projekt anhand seiner ID
func GetProjectByID(ctx context.Context, id ulid.ULID) (*Project, error) {
var project Project
result := GetEngine(ctx).Where("id = ?", id).First(&project)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, result.Error
}
return &project, nil
}
// GetProjectWithCustomer lädt ein Projekt mit den zugehörigen Kundeninformationen
func GetProjectWithCustomer(ctx context.Context, id ulid.ULID) (*Project, error) {
var project Project
result := GetEngine(ctx).Preload("Customer").Where("id = ?", id).First(&project)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, result.Error
}
return &project, nil
}
// GetAllProjects gibt alle Projekte zurück
func GetAllProjects(ctx context.Context) ([]Project, error) {
var projects []Project
result := GetEngine(ctx).Find(&projects)
if result.Error != nil {
return nil, result.Error
}
return projects, nil
}
// GetAllProjectsWithCustomers gibt alle Projekte mit Kundeninformationen zurück
func GetAllProjectsWithCustomers(ctx context.Context) ([]Project, error) {
var projects []Project
result := GetEngine(ctx).Preload("Customer").Find(&projects)
if result.Error != nil {
return nil, result.Error
}
return projects, nil
}
// GetProjectsByCustomerID gibt alle Projekte eines bestimmten Kunden zurück
func GetProjectsByCustomerID(ctx context.Context, customerID ulid.ULID) ([]Project, error) {
var projects []Project
result := GetEngine(ctx).Where("customer_id = ?", customerID).Find(&projects)
if result.Error != nil {
return nil, result.Error
}
return projects, nil
}
// CreateProject erstellt ein neues Projekt mit Validierung
func CreateProject(ctx context.Context, create ProjectCreate) (*Project, error) {
// Validierung
if err := create.Validate(); err != nil {
return nil, fmt.Errorf("validierungsfehler: %w", err)
}
// Prüfen, ob der Kunde existiert
customer, err := GetCustomerByID(ctx, create.CustomerID)
if err != nil {
return nil, fmt.Errorf("fehler beim Prüfen des Kunden: %w", err)
}
if customer == nil {
return nil, errors.New("der angegebene Kunde existiert nicht")
}
project := Project{
Name: create.Name,
CustomerID: create.CustomerID,
}
result := GetEngine(ctx).Create(&project)
if result.Error != nil {
return nil, fmt.Errorf("fehler beim Erstellen des Projekts: %w", result.Error)
}
return &project, nil
}
// UpdateProject aktualisiert ein bestehendes Projekt mit Validierung
func UpdateProject(ctx context.Context, update ProjectUpdate) (*Project, error) {
// Validierung
if err := update.Validate(); err != nil {
return nil, fmt.Errorf("validierungsfehler: %w", err)
}
project, err := GetProjectByID(ctx, update.ID)
if err != nil {
return nil, err
}
if project == nil {
return nil, errors.New("project nicht gefunden")
}
// Wenn CustomerID aktualisiert wird, prüfen ob der Kunde existiert
if update.CustomerID != nil {
customer, err := GetCustomerByID(ctx, *update.CustomerID)
if err != nil {
return nil, fmt.Errorf("fehler beim Prüfen des Kunden: %w", err)
}
if customer == nil {
return nil, errors.New("der angegebene Kunde existiert nicht")
}
}
// Generische Update-Funktion verwenden
if err := UpdateModel(ctx, project, update); err != nil {
return nil, fmt.Errorf("fehler beim Aktualisieren des Projekts: %w", err)
}
// Aktualisierte Daten aus der Datenbank laden
return GetProjectByID(ctx, update.ID)
}
// DeleteProject löscht ein Projekt anhand seiner ID
func DeleteProject(ctx context.Context, id ulid.ULID) error {
// Hier könnte man prüfen, ob abhängige Entitäten existieren
result := GetEngine(ctx).Delete(&Project{}, id)
if result.Error != nil {
return fmt.Errorf("fehler beim Löschen des Projekts: %w", result.Error)
}
return nil
}
// CreateProjectWithTransaction erstellt ein Projekt innerhalb einer Transaktion
func CreateProjectWithTransaction(ctx context.Context, create ProjectCreate) (*Project, error) {
// Validierung
if err := create.Validate(); err != nil {
return nil, fmt.Errorf("validierungsfehler: %w", err)
}
var project *Project
// Transaktion starten
err := GetEngine(ctx).Transaction(func(tx *gorm.DB) error {
// Kundenprüfung innerhalb der Transaktion
var customer Customer
if err := tx.Where("id = ?", create.CustomerID).First(&customer).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("der angegebene Kunde existiert nicht")
}
return err
}
// Projekt erstellen
newProject := Project{
Name: create.Name,
CustomerID: create.CustomerID,
}
if err := tx.Create(&newProject).Error; err != nil {
return err
}
// Projekt für die Rückgabe speichern
project = &newProject
return nil
})
if err != nil {
return nil, fmt.Errorf("transaktionsfehler: %w", err)
}
return project, nil
}