Files
kouiz/internal/store/quiz.go

115 lines
2.7 KiB
Go
Raw Normal View History

2025-06-13 16:55:46 +02:00
package store
import (
"context"
"math/rand/v2"
"time"
"github.com/pkg/errors"
"gorm.io/gorm"
)
func (s *Store) UpsertQuizCategory(ctx context.Context, category *QuizCategory) error {
return errors.WithStack(s.Do(ctx, func(db *gorm.DB) error {
var existing *QuizCategory
err := db.Find(&existing, "name = ? and theme = ?", category.Name, category.Theme).Error
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.WithStack(err)
}
if existing != nil {
category.Model = existing.Model
}
if err := db.Save(category).Error; err != nil {
return errors.WithStack(err)
}
return nil
}))
}
func (s *Store) UpsertQuizEntry(ctx context.Context, entry *QuizEntry) error {
return errors.WithStack(s.Do(ctx, func(db *gorm.DB) error {
var existing *QuizEntry
err := db.Find(&existing, "provider = ? and provider_id = ?", entry.Provider, entry.ProviderID).Error
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.WithStack(err)
}
if existing != nil {
entry.Model = existing.Model
}
if err := db.Save(entry).Error; err != nil {
return errors.WithStack(err)
}
return nil
}))
}
func (s *Store) GetQuizTurn(ctx context.Context, playInterval time.Duration) (*QuizTurn, error) {
var quizTurn *QuizTurn
err := s.Tx(ctx, func(tx *gorm.DB) error {
now := time.Now().UTC()
err := tx.Model(&quizTurn).Preload("Entries").Preload("Entries.Category").Order("ended_at DESC").First(&quizTurn, "ended_at >= ?", now).Error
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.WithStack(err)
}
if quizTurn != nil && quizTurn.ID != 0 {
return nil
}
quizTurn = &QuizTurn{
StartedAt: now.Round(time.Hour),
EndedAt: now.Add(playInterval).Round(time.Hour),
}
alreadyUsed := make([]uint, 0)
err = tx.Table("quiz_turn_entries").Pluck("quiz_entry_id", &alreadyUsed).Error
if err != nil {
return errors.WithStack(err)
}
query := tx.Model(&QuizEntry{})
if len(alreadyUsed) > 0 {
query = query.Where("id NOT IN ?", alreadyUsed)
}
var entryIDs []uint
err = query.Pluck("id", &entryIDs).Error
if err != nil {
return errors.WithStack(err)
}
for range 3 {
index := rand.IntN(len(entryIDs))
quizTurn.Entries = append(quizTurn.Entries, &QuizEntry{
Model: gorm.Model{
ID: entryIDs[index],
},
})
}
if err := tx.Save(quizTurn).Error; err != nil {
return errors.WithStack(err)
}
err = tx.Model(&QuizTurn{}).Preload("Entries").Preload("Entries.Category").First(&quizTurn).Error
if err != nil {
return errors.WithStack(err)
}
return nil
})
if err != nil {
return nil, errors.WithStack(err)
}
return quizTurn, nil
}