@@ -56,34 +56,82 @@ DELETE FROM sessions WHERE expires_at <= ?;
5656-- =============================================================================
5757
5858-- name: ListExercises :many
59- -- Global order. Used by progression code where order does not matter.
60- SELECT id, slug, name, kind, default_sets, default_reps, default_weight_kg, sort_order
61- FROM exercises ORDER BY sort_order;
59+ -- Used by progression code. Scoped to one user: includes seeded exercises
60+ -- (created_by_user_id IS NULL) and that user's own customs, excluding
61+ -- soft-deleted rows.
62+ SELECT id, slug, name, kind, default_sets, default_reps, default_weight_kg, sort_order,
63+ created_by_user_id, auto_progress, deleted_at
64+ FROM exercises
65+ WHERE deleted_at IS NULL
66+ AND (created_by_user_id IS NULL OR created_by_user_id = CAST(sqlc .arg (user_id) AS INTEGER ))
67+ ORDER BY sort_order;
6268
6369-- name: ListExercisesForUser :many
6470-- Per-user order: rows in user_exercise_sort_order override exercises.sort_order.
65- -- Exercises without a per-user row fall back to the seeded default.
66- SELECT e .id , e .slug , e .name , e .kind , e .default_sets , e .default_reps , e .default_weight_kg , e .sort_order
71+ -- Exercises without a per-user row fall back to the seeded default. Filters
72+ -- out other users' customs and soft-deleted rows.
73+ SELECT e .id , e .slug , e .name , e .kind , e .default_sets , e .default_reps , e .default_weight_kg , e .sort_order ,
74+ e .created_by_user_id , e .auto_progress , e .deleted_at
6775FROM exercises e
6876LEFT JOIN user_exercise_sort_order uso
69- ON uso .exercise_id = e .id AND uso .user_id = ?
77+ ON uso .exercise_id = e .id AND uso .user_id = sqlc .arg (user_id)
78+ WHERE e .deleted_at IS NULL
79+ AND (e .created_by_user_id IS NULL OR e .created_by_user_id = sqlc .arg (user_id))
7080ORDER BY COALESCE(uso .sort_order , e .sort_order ), e .id ;
7181
7282-- name: GetExerciseByID :one
73- SELECT id, slug, name, kind, default_sets, default_reps, default_weight_kg, sort_order
83+ -- No visibility filter at the SQL layer; handlers enforce ownership before
84+ -- mutation (custom rename/delete) and seeded vs custom is determined by the
85+ -- created_by_user_id column on the returned row.
86+ SELECT id, slug, name, kind, default_sets, default_reps, default_weight_kg, sort_order,
87+ created_by_user_id, auto_progress, deleted_at
7488FROM exercises WHERE id = ?;
7589
7690-- name: UpsertExercise :exec
77- -- sort_order is intentionally only set on initial INSERT so that user
78- -- reordering on the settings page is not clobbered by the seed on restart.
79- INSERT INTO exercises (slug, name, kind, default_sets, default_reps, default_weight_kg, sort_order)
80- VALUES (?, ?, ?, ?, ?, ?, ?)
91+ -- Used only by SeedExercises for the global seeded list. sort_order and
92+ -- auto_progress are intentionally NOT updated on conflict so that user
93+ -- reordering / a future schema-bump for auto_progress aren't clobbered by
94+ -- the seed on restart. created_by_user_id is implicitly NULL for seeded rows.
95+ INSERT INTO exercises (slug, name, kind, default_sets, default_reps, default_weight_kg, sort_order, auto_progress)
96+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
8197ON CONFLICT(slug) DO UPDATE SET
8298 name = excluded .name ,
8399 kind = excluded .kind ,
84100 default_sets = excluded .default_sets ,
85101 default_reps = excluded .default_reps ;
86102
103+ -- name: SetSeededAutoProgress :exec
104+ -- One-shot used by SeedExercises to align the auto_progress flag on the
105+ -- two seeded exercises that are deliberately manual (walking, dumbbell_curls).
106+ -- Only touches seeded rows (created_by_user_id IS NULL).
107+ UPDATE exercises SET auto_progress = ?
108+ WHERE slug = ? AND created_by_user_id IS NULL ;
109+
110+ -- name: CreateCustomExercise :execlastid
111+ -- Inserts a user-created custom exercise. sort_order is computed by the
112+ -- caller (typically MAX(sort_order)+1 so the new exercise appears last in
113+ -- the global order; per-user reordering still applies on top).
114+ INSERT INTO exercises (slug, name, kind, default_sets, default_reps, default_weight_kg, sort_order,
115+ created_by_user_id, auto_progress)
116+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);
117+
118+ -- name: MaxExerciseSortOrder :one
119+ SELECT CAST(COALESCE(MAX (sort_order), 0 ) AS INTEGER ) AS max_sort_order FROM exercises;
120+
121+ -- name: RenameCustomExercise :exec
122+ -- Defence in depth: only the creator can rename their custom exercise.
123+ -- Seeded rows (created_by_user_id IS NULL) are never affected because the
124+ -- WHERE clause requires a matching user id.
125+ UPDATE exercises SET name = ?
126+ WHERE id = ? AND created_by_user_id = ?;
127+
128+ -- name: SoftDeleteCustomExercise :exec
129+ -- Soft-delete: the row stays for historical sets to reference but is hidden
130+ -- from new workouts and from the per-user exercise list. Only the creator
131+ -- can soft-delete their own custom.
132+ UPDATE exercises SET deleted_at = ?
133+ WHERE id = ? AND created_by_user_id = ?;
134+
87135-- name: ClearUserExerciseSortOrder :exec
88136DELETE FROM user_exercise_sort_order WHERE user_id = ?;
89137
0 commit comments