store: scope workout kinds and their pace/HR ranges to a user_id
workout_kinds gains a real user_id column (Task 1); workout_type_paces has none of its own and is scoped via a join to workout_kinds instead, since it's always accessed through a specific kind. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,40 +40,42 @@ func (db *DB) CreateWorkoutKind(ctx context.Context, userID int64, k WorkoutKind
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
// UpdateWorkoutKind updates an existing workout kind's editable fields.
|
||||
func (db *DB) UpdateWorkoutKind(ctx context.Context, k WorkoutKind) error {
|
||||
// UpdateWorkoutKind updates an existing workout kind's editable fields,
|
||||
// scoped so it can only ever affect a row owned by userID.
|
||||
func (db *DB) UpdateWorkoutKind(ctx context.Context, userID int64, k WorkoutKind) error {
|
||||
_, err := db.ExecContext(ctx, `
|
||||
UPDATE workout_kinds SET name=?, description=?, color=?, rule_json=?, priority=?, is_active=?, updated_at=datetime('now')
|
||||
WHERE id=?`,
|
||||
k.Name, k.Description, k.Color, k.RuleJSON, k.Priority, k.IsActive, k.ID)
|
||||
WHERE id=? AND user_id=?`,
|
||||
k.Name, k.Description, k.Color, k.RuleJSON, k.Priority, k.IsActive, k.ID, userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("update workout kind %d: %w", k.ID, err)
|
||||
return fmt.Errorf("update workout kind %d for user %d: %w", k.ID, userID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetWorkoutKind fetches one workout kind by id.
|
||||
func (db *DB) GetWorkoutKind(ctx context.Context, id int64) (WorkoutKind, bool, error) {
|
||||
row := db.QueryRowContext(ctx, `SELECT `+workoutKindColumns+` FROM workout_kinds WHERE id = ?`, id)
|
||||
// GetWorkoutKind fetches one workout kind by id, scoped to userID.
|
||||
func (db *DB) GetWorkoutKind(ctx context.Context, userID, id int64) (WorkoutKind, bool, error) {
|
||||
row := db.QueryRowContext(ctx, `SELECT `+workoutKindColumns+` FROM workout_kinds WHERE id = ? AND user_id = ?`, id, userID)
|
||||
k, err := scanWorkoutKind(row)
|
||||
if err == sql.ErrNoRows {
|
||||
return WorkoutKind{}, false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return WorkoutKind{}, false, fmt.Errorf("get workout kind %d: %w", id, err)
|
||||
return WorkoutKind{}, false, fmt.Errorf("get workout kind %d for user %d: %w", id, userID, err)
|
||||
}
|
||||
return k, true, nil
|
||||
}
|
||||
|
||||
// GetWorkoutKindByName fetches one workout kind by its unique name.
|
||||
func (db *DB) GetWorkoutKindByName(ctx context.Context, name string) (WorkoutKind, bool, error) {
|
||||
row := db.QueryRowContext(ctx, `SELECT `+workoutKindColumns+` FROM workout_kinds WHERE name = ?`, name)
|
||||
// GetWorkoutKindByName fetches one workout kind by name, scoped to userID
|
||||
// (the same name can exist for different users -- see UNIQUE(user_id, name)).
|
||||
func (db *DB) GetWorkoutKindByName(ctx context.Context, userID int64, name string) (WorkoutKind, bool, error) {
|
||||
row := db.QueryRowContext(ctx, `SELECT `+workoutKindColumns+` FROM workout_kinds WHERE name = ? AND user_id = ?`, name, userID)
|
||||
k, err := scanWorkoutKind(row)
|
||||
if err == sql.ErrNoRows {
|
||||
return WorkoutKind{}, false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return WorkoutKind{}, false, fmt.Errorf("get workout kind %q: %w", name, err)
|
||||
return WorkoutKind{}, false, fmt.Errorf("get workout kind %q for user %d: %w", name, userID, err)
|
||||
}
|
||||
return k, true, nil
|
||||
}
|
||||
@@ -105,11 +107,11 @@ func (db *DB) ListWorkoutKinds(ctx context.Context, userID int64, activeOnly boo
|
||||
}
|
||||
|
||||
// SoftDeleteWorkoutKind sets is_active=0, keeping history (kind_assignments
|
||||
// referencing it) intact.
|
||||
func (db *DB) SoftDeleteWorkoutKind(ctx context.Context, id int64) error {
|
||||
_, err := db.ExecContext(ctx, `UPDATE workout_kinds SET is_active=0, updated_at=datetime('now') WHERE id=?`, id)
|
||||
// referencing it) intact. Scoped to userID.
|
||||
func (db *DB) SoftDeleteWorkoutKind(ctx context.Context, userID, id int64) error {
|
||||
_, err := db.ExecContext(ctx, `UPDATE workout_kinds SET is_active=0, updated_at=datetime('now') WHERE id=? AND user_id=?`, id, userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("soft delete workout kind %d: %w", id, err)
|
||||
return fmt.Errorf("soft delete workout kind %d for user %d: %w", id, userID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user