145 lines
3.8 KiB
Go
Executable File
145 lines
3.8 KiB
Go
Executable File
package repository
|
|
|
|
import (
|
|
"acc-server-manager/local/model"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type LeaderboardRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewLeaderboardRepository(db *gorm.DB) *LeaderboardRepository {
|
|
return &LeaderboardRepository{db: db}
|
|
}
|
|
|
|
// GetOrCreateByServerID fetches the leaderboard for a server, creating an empty one if it doesn't exist.
|
|
func (r *LeaderboardRepository) GetOrCreateByServerID(ctx context.Context, serverID uuid.UUID) (*model.Leaderboard, error) {
|
|
lb := new(model.Leaderboard)
|
|
err := r.db.WithContext(ctx).
|
|
Preload("Drivers").
|
|
Preload("Races.Results").
|
|
Preload("PointRows").
|
|
Where("server_id = ?", serverID).
|
|
First(lb).Error
|
|
|
|
if err == nil {
|
|
return lb, nil
|
|
}
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, fmt.Errorf("error fetching leaderboard: %w", err)
|
|
}
|
|
|
|
lb = &model.Leaderboard{
|
|
ServerID: serverID,
|
|
FLPoints: 1,
|
|
FLColor: "#8b5cf6",
|
|
FLTextColor: "#000000",
|
|
}
|
|
if err := r.db.WithContext(ctx).Create(lb).Error; err != nil {
|
|
return nil, fmt.Errorf("error creating leaderboard: %w", err)
|
|
}
|
|
return lb, nil
|
|
}
|
|
|
|
// FullReplace replaces all leaderboard data for a server in a single transaction.
|
|
func (r *LeaderboardRepository) FullReplace(ctx context.Context, serverID uuid.UUID, lb *model.Leaderboard) (*model.Leaderboard, error) {
|
|
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
existing := new(model.Leaderboard)
|
|
err := tx.Where("server_id = ?", serverID).First(existing).Error
|
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return fmt.Errorf("error fetching existing leaderboard: %w", err)
|
|
}
|
|
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
lb.ServerID = serverID
|
|
return tx.Create(lb).Error
|
|
}
|
|
|
|
// Delete children
|
|
if err := tx.Where("leaderboard_id = ?", existing.ID).Delete(&model.LeaderboardPointRow{}).Error; err != nil {
|
|
return err
|
|
}
|
|
if err := tx.Where("leaderboard_id = ?", existing.ID).Delete(&model.LeaderboardDriver{}).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get race IDs to delete results
|
|
var raceIDs []uuid.UUID
|
|
tx.Model(&model.LeaderboardRace{}).Where("leaderboard_id = ?", existing.ID).Pluck("id", &raceIDs)
|
|
if len(raceIDs) > 0 {
|
|
if err := tx.Where("race_id IN ?", raceIDs).Delete(&model.LeaderboardResult{}).Error; err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := tx.Where("leaderboard_id = ?", existing.ID).Delete(&model.LeaderboardRace{}).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Update parent fields
|
|
existing.FLPoints = lb.FLPoints
|
|
existing.FLColor = lb.FLColor
|
|
existing.FLTextColor = lb.FLTextColor
|
|
if err := tx.Save(existing).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Re-insert children with correct leaderboard ID
|
|
for i := range lb.Drivers {
|
|
lb.Drivers[i].LeaderboardID = existing.ID
|
|
}
|
|
if len(lb.Drivers) > 0 {
|
|
if err := tx.Create(&lb.Drivers).Error; err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
for i := range lb.PointRows {
|
|
lb.PointRows[i].LeaderboardID = existing.ID
|
|
lb.PointRows[i].ID = uuid.Nil
|
|
}
|
|
if len(lb.PointRows) > 0 {
|
|
if err := tx.Create(&lb.PointRows).Error; err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
for i := range lb.Races {
|
|
lb.Races[i].LeaderboardID = existing.ID
|
|
}
|
|
if len(lb.Races) > 0 {
|
|
// Create races first (without results) to get IDs
|
|
for i := range lb.Races {
|
|
results := lb.Races[i].Results
|
|
lb.Races[i].Results = nil
|
|
if err := tx.Create(&lb.Races[i]).Error; err != nil {
|
|
return err
|
|
}
|
|
// Re-attach results with correct race ID
|
|
for j := range results {
|
|
results[j].RaceID = lb.Races[i].ID
|
|
results[j].ID = uuid.Nil
|
|
}
|
|
if len(results) > 0 {
|
|
if err := tx.Create(&results).Error; err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lb.ID = existing.ID
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return r.GetOrCreateByServerID(ctx, serverID)
|
|
}
|