Initial commit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
200
backend/internal/store/set_store.go
Executable file
200
backend/internal/store/set_store.go
Executable file
@@ -0,0 +1,200 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"krafttrainer/internal/model"
|
||||
)
|
||||
|
||||
// ListSets gibt alle nicht-gelöschten Sets mit ihren Übungen zurück.
|
||||
func (s *Store) ListSets() ([]model.TrainingSet, error) {
|
||||
rows, err := s.db.Query(`
|
||||
SELECT id, name, created_at FROM training_sets
|
||||
WHERE deleted_at IS NULL ORDER BY name`)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Sets abfragen: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var sets []model.TrainingSet
|
||||
for rows.Next() {
|
||||
var ts model.TrainingSet
|
||||
if err := rows.Scan(&ts.ID, &ts.Name, &ts.CreatedAt); err != nil {
|
||||
return nil, fmt.Errorf("Set scannen: %w", err)
|
||||
}
|
||||
sets = append(sets, ts)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if sets == nil {
|
||||
sets = []model.TrainingSet{}
|
||||
}
|
||||
|
||||
for i := range sets {
|
||||
exercises, err := s.getSetExercises(sets[i].ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sets[i].Exercises = exercises
|
||||
}
|
||||
return sets, nil
|
||||
}
|
||||
|
||||
// GetSet gibt ein einzelnes Set mit Übungen zurück.
|
||||
func (s *Store) GetSet(id int64) (*model.TrainingSet, error) {
|
||||
var ts model.TrainingSet
|
||||
err := s.db.QueryRow(`
|
||||
SELECT id, name, created_at, deleted_at FROM training_sets WHERE id = ?`, id,
|
||||
).Scan(&ts.ID, &ts.Name, &ts.CreatedAt, &ts.DeletedAt)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Set abfragen: %w", err)
|
||||
}
|
||||
|
||||
exercises, err := s.getSetExercises(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ts.Exercises = exercises
|
||||
return &ts, nil
|
||||
}
|
||||
|
||||
// CreateSet legt ein neues Set an (in einer Transaktion).
|
||||
func (s *Store) CreateSet(req *model.CreateSetRequest) (*model.TrainingSet, error) {
|
||||
tx, err := s.db.Begin()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Transaktion starten: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
// Prüfen ob alle Übungen existieren
|
||||
for _, eid := range req.ExerciseIDs {
|
||||
var exists bool
|
||||
err := tx.QueryRow(`SELECT EXISTS(SELECT 1 FROM exercises WHERE id = ? AND deleted_at IS NULL)`, eid).Scan(&exists)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Übung prüfen: %w", err)
|
||||
}
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("Übung %d existiert nicht", eid)
|
||||
}
|
||||
}
|
||||
|
||||
result, err := tx.Exec(`INSERT INTO training_sets (name) VALUES (?)`, req.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Set erstellen: %w", err)
|
||||
}
|
||||
|
||||
id, _ := result.LastInsertId()
|
||||
|
||||
for pos, eid := range req.ExerciseIDs {
|
||||
_, err := tx.Exec(`INSERT INTO set_exercises (set_id, exercise_id, position) VALUES (?, ?, ?)`, id, eid, pos)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Set-Übung zuordnen: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, fmt.Errorf("Transaktion committen: %w", err)
|
||||
}
|
||||
return s.GetSet(id)
|
||||
}
|
||||
|
||||
// UpdateSet aktualisiert ein Set (Name + Übungszuordnungen).
|
||||
func (s *Store) UpdateSet(id int64, req *model.UpdateSetRequest) (*model.TrainingSet, error) {
|
||||
tx, err := s.db.Begin()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Transaktion starten: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
// Prüfen ob Set existiert
|
||||
var exists bool
|
||||
err = tx.QueryRow(`SELECT EXISTS(SELECT 1 FROM training_sets WHERE id = ? AND deleted_at IS NULL)`, id).Scan(&exists)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Set prüfen: %w", err)
|
||||
}
|
||||
if !exists {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Prüfen ob alle Übungen existieren
|
||||
for _, eid := range req.ExerciseIDs {
|
||||
var eExists bool
|
||||
err := tx.QueryRow(`SELECT EXISTS(SELECT 1 FROM exercises WHERE id = ? AND deleted_at IS NULL)`, eid).Scan(&eExists)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Übung prüfen: %w", err)
|
||||
}
|
||||
if !eExists {
|
||||
return nil, fmt.Errorf("Übung %d existiert nicht", eid)
|
||||
}
|
||||
}
|
||||
|
||||
_, err = tx.Exec(`UPDATE training_sets SET name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?`, req.Name, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Set aktualisieren: %w", err)
|
||||
}
|
||||
|
||||
_, err = tx.Exec(`DELETE FROM set_exercises WHERE set_id = ?`, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Set-Übungen löschen: %w", err)
|
||||
}
|
||||
|
||||
for pos, eid := range req.ExerciseIDs {
|
||||
_, err := tx.Exec(`INSERT INTO set_exercises (set_id, exercise_id, position) VALUES (?, ?, ?)`, id, eid, pos)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Set-Übung zuordnen: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, fmt.Errorf("Transaktion committen: %w", err)
|
||||
}
|
||||
return s.GetSet(id)
|
||||
}
|
||||
|
||||
// SoftDeleteSet markiert ein Set als gelöscht.
|
||||
func (s *Store) SoftDeleteSet(id int64) error {
|
||||
result, err := s.db.Exec(`
|
||||
UPDATE training_sets SET deleted_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ? AND deleted_at IS NULL`, id,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Set löschen: %w", err)
|
||||
}
|
||||
rows, _ := result.RowsAffected()
|
||||
if rows == 0 {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getSetExercises lädt die Übungen eines Sets sortiert nach Position.
|
||||
func (s *Store) getSetExercises(setID int64) ([]model.Exercise, error) {
|
||||
rows, err := s.db.Query(`
|
||||
SELECT e.id, e.name, e.description, e.muscle_group, e.weight_step_kg, e.created_at, e.updated_at
|
||||
FROM exercises e
|
||||
JOIN set_exercises se ON se.exercise_id = e.id
|
||||
WHERE se.set_id = ?
|
||||
ORDER BY se.position`, setID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Set-Übungen abfragen: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var exercises []model.Exercise
|
||||
for rows.Next() {
|
||||
var e model.Exercise
|
||||
if err := rows.Scan(&e.ID, &e.Name, &e.Description, &e.MuscleGroup, &e.WeightStepKg, &e.CreatedAt, &e.UpdatedAt); err != nil {
|
||||
return nil, fmt.Errorf("Übung scannen: %w", err)
|
||||
}
|
||||
exercises = append(exercises, e)
|
||||
}
|
||||
if exercises == nil {
|
||||
exercises = []model.Exercise{}
|
||||
}
|
||||
return exercises, rows.Err()
|
||||
}
|
||||
Reference in New Issue
Block a user