Files
training-tracker/backend/internal/storage/exercises.go
2026-01-19 19:49:59 +01:00

122 lines
3.5 KiB
Go

package storage
import (
"context"
"database/sql"
"fmt"
"training-tracker/internal/models"
)
type ExerciseRepository struct {
db *DB
}
func NewExerciseRepository(db *DB) *ExerciseRepository {
return &ExerciseRepository{db: db}
}
func (r *ExerciseRepository) List(ctx context.Context) ([]models.Exercise, error) {
query := `SELECT id, name, type, muscle_group, description, created_at
FROM exercises ORDER BY name`
rows, err := r.db.QueryContext(ctx, query)
if err != nil {
return nil, fmt.Errorf("failed to query exercises: %w", err)
}
defer rows.Close()
var exercises []models.Exercise
for rows.Next() {
var e models.Exercise
var muscleGroup, description sql.NullString
if err := rows.Scan(&e.ID, &e.Name, &e.Type, &muscleGroup, &description, &e.CreatedAt); err != nil {
return nil, fmt.Errorf("failed to scan exercise: %w", err)
}
e.MuscleGroup = muscleGroup.String
e.Description = description.String
exercises = append(exercises, e)
}
return exercises, nil
}
func (r *ExerciseRepository) GetByID(ctx context.Context, id int64) (*models.Exercise, error) {
query := `SELECT id, name, type, muscle_group, description, created_at
FROM exercises WHERE id = $1`
var e models.Exercise
var muscleGroup, description sql.NullString
err := r.db.QueryRowContext(ctx, query, id).Scan(&e.ID, &e.Name, &e.Type, &muscleGroup, &description, &e.CreatedAt)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("failed to get exercise: %w", err)
}
e.MuscleGroup = muscleGroup.String
e.Description = description.String
return &e, nil
}
func (r *ExerciseRepository) Create(ctx context.Context, req *models.CreateExerciseRequest) (*models.Exercise, error) {
query := `INSERT INTO exercises (name, type, muscle_group, description)
VALUES ($1, $2, $3, $4)
RETURNING id, name, type, muscle_group, description, created_at`
var e models.Exercise
var muscleGroup, description sql.NullString
err := r.db.QueryRowContext(ctx, query, req.Name, req.Type, nullString(req.MuscleGroup), nullString(req.Description)).
Scan(&e.ID, &e.Name, &e.Type, &muscleGroup, &description, &e.CreatedAt)
if err != nil {
return nil, fmt.Errorf("failed to create exercise: %w", err)
}
e.MuscleGroup = muscleGroup.String
e.Description = description.String
return &e, nil
}
func (r *ExerciseRepository) Update(ctx context.Context, id int64, req *models.CreateExerciseRequest) (*models.Exercise, error) {
query := `UPDATE exercises
SET name = $1, type = $2, muscle_group = $3, description = $4
WHERE id = $5
RETURNING id, name, type, muscle_group, description, created_at`
var e models.Exercise
var muscleGroup, description sql.NullString
err := r.db.QueryRowContext(ctx, query, req.Name, req.Type, nullString(req.MuscleGroup), nullString(req.Description), id).
Scan(&e.ID, &e.Name, &e.Type, &muscleGroup, &description, &e.CreatedAt)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("failed to update exercise: %w", err)
}
e.MuscleGroup = muscleGroup.String
e.Description = description.String
return &e, nil
}
func (r *ExerciseRepository) Delete(ctx context.Context, id int64) error {
query := `DELETE FROM exercises WHERE id = $1`
result, err := r.db.ExecContext(ctx, query, id)
if err != nil {
return fmt.Errorf("failed to delete exercise: %w", err)
}
rows, _ := result.RowsAffected()
if rows == 0 {
return sql.ErrNoRows
}
return nil
}
func nullString(s string) sql.NullString {
if s == "" {
return sql.NullString{}
}
return sql.NullString{String: s, Valid: true}
}