package store import ( "context" "database/sql" "fmt" ) // WorkoutTypePace is a workout kind's user-declared target pace range and // expected HR zone. Informational only -- never read by the classification // rule engine. No history: fields are overwritten in place. type WorkoutTypePace struct { WorkoutKindID int64 PaceMinSecPerKm *float64 PaceMaxSecPerKm *float64 ExpectedHRZone *int } func scanWorkoutTypePace(row interface{ Scan(...any) error }) (WorkoutTypePace, error) { var p WorkoutTypePace err := row.Scan(&p.WorkoutKindID, &p.PaceMinSecPerKm, &p.PaceMaxSecPerKm, &p.ExpectedHRZone) return p, err } const workoutTypePaceColumns = `workout_kind_id, pace_min_sec_per_km, pace_max_sec_per_km, expected_hr_zone` // GetWorkoutTypePace fetches the pace/zone row for one workout kind. func (db *DB) GetWorkoutTypePace(ctx context.Context, workoutKindID int64) (WorkoutTypePace, error) { row := db.QueryRowContext(ctx, `SELECT `+workoutTypePaceColumns+` FROM workout_type_paces WHERE workout_kind_id = ?`, workoutKindID) p, err := scanWorkoutTypePace(row) if err == sql.ErrNoRows { return WorkoutTypePace{WorkoutKindID: workoutKindID}, nil } if err != nil { return WorkoutTypePace{}, fmt.Errorf("get workout type pace for kind %d: %w", workoutKindID, err) } return p, nil } // UpdateWorkoutTypePace overwrites the pace/zone row for one workout kind. func (db *DB) UpdateWorkoutTypePace(ctx context.Context, p WorkoutTypePace) error { _, err := db.ExecContext(ctx, ` UPDATE workout_type_paces SET pace_min_sec_per_km=?, pace_max_sec_per_km=?, expected_hr_zone=? WHERE workout_kind_id=?`, p.PaceMinSecPerKm, p.PaceMaxSecPerKm, p.ExpectedHRZone, p.WorkoutKindID) if err != nil { return fmt.Errorf("update workout type pace for kind %d: %w", p.WorkoutKindID, err) } return nil } // ListWorkoutTypePaces returns every workout kind's pace/zone row. func (db *DB) ListWorkoutTypePaces(ctx context.Context) ([]WorkoutTypePace, error) { rows, err := db.QueryContext(ctx, `SELECT `+workoutTypePaceColumns+` FROM workout_type_paces ORDER BY workout_kind_id`) if err != nil { return nil, fmt.Errorf("list workout type paces: %w", err) } defer rows.Close() paces := []WorkoutTypePace{} for rows.Next() { p, err := scanWorkoutTypePace(rows) if err != nil { return nil, fmt.Errorf("scan workout type pace row: %w", err) } paces = append(paces, p) } return paces, rows.Err() }