Fix tags, may have increased load on database while only using one query to fetch workout, topsets, and all tags

This commit is contained in:
Peter Stockings
2024-11-04 22:33:08 +11:00
parent 10326ccd7a
commit b5493e627c
6 changed files with 48 additions and 33 deletions

4
app.py
View File

@@ -376,8 +376,8 @@ def get_workout_note(person_id, workout_id):
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/tag/add", methods=['POST']) @ app.route("/person/<int:person_id>/workout/<int:workout_id>/tag/add", methods=['POST'])
def add_tag_to_workout(person_id, workout_id): def add_tag_to_workout(person_id, workout_id):
tags_id = [int(i) for i in request.form.getlist('tag_id')] tags_id = [int(i) for i in request.form.getlist('tag_id')]
workout_tags = db.add_tag_for_workout(workout_id, tags_id) tags = db.add_tag_for_workout(workout_id, tags_id)
return render_template('partials/workout_tags_list.html', workout_tags=workout_tags) return render_template('partials/workout_tags_list.html', tags=tags)
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/tag/new", methods=['POST']) @ app.route("/person/<int:person_id>/workout/<int:workout_id>/tag/new", methods=['POST'])

29
db.py
View File

@@ -342,14 +342,24 @@ class DataBase():
note, person_id, workout_id], commit=True) note, person_id, workout_id], commit=True)
def add_tag_for_workout(self, workout_id, tags_id): def add_tag_for_workout(self, workout_id, tags_id):
# First, delete tags that are not in the new selection # If tags_id is not empty, delete tags that are not in the new selection
self.execute( if tags_id:
""" self.execute(
DELETE FROM workout_tag """
WHERE workout_id = %s AND tag_id NOT IN %s DELETE FROM workout_tag
""", WHERE workout_id = %s AND tag_id NOT IN %s
[workout_id, tuple(tags_id)], commit=True """,
) [workout_id, tuple(tags_id)], commit=True
)
else:
# If tags_id is empty, delete all tags for this workout
self.execute(
"""
DELETE FROM workout_tag
WHERE workout_id = %s
""",
[workout_id], commit=True
)
# Then, attempt to insert the new tags # Then, attempt to insert the new tags
for tag_id in tags_id: for tag_id in tags_id:
@@ -368,7 +378,8 @@ class DataBase():
T.tag_id AS "tag_id", T.tag_id AS "tag_id",
T.person_id AS "person_id", T.person_id AS "person_id",
T.name AS "tag_name", T.name AS "tag_name",
T.filter AS "tag_filter" T.filter AS "tag_filter",
TRUE AS "is_selected"
FROM Workout_Tag WT FROM Workout_Tag WT
LEFT JOIN Tag T ON WT.tag_id=T.tag_id LEFT JOIN Tag T ON WT.tag_id=T.tag_id
WHERE WT.workout_id=%s""", [workout_id]) WHERE WT.workout_id=%s""", [workout_id])

View File

@@ -18,17 +18,19 @@ class Workout:
t.repetitions, t.repetitions,
t.weight, t.weight,
tag.tag_id, tag.tag_id,
tag.name AS tag_name tag.name AS tag_name,
tag.filter as tag_filter,
CASE WHEN wt.workout_id IS NOT NULL THEN TRUE ELSE FALSE END AS is_selected
FROM FROM
workout w workout w
JOIN LEFT JOIN
topset t ON w.workout_id = t.workout_id topset t ON w.workout_id = t.workout_id
JOIN LEFT JOIN
exercise e ON t.exercise_id = e.exercise_id exercise e ON t.exercise_id = e.exercise_id
LEFT JOIN LEFT JOIN
workout_tag wt ON w.workout_id = wt.workout_id workout_tag wt ON w.workout_id = wt.workout_id
LEFT JOIN LEFT JOIN
tag ON wt.tag_id = tag.tag_id tag ON TRUE -- Join to get all tags
WHERE WHERE
w.person_id = %s w.person_id = %s
AND w.workout_id = %s; AND w.workout_id = %s;
@@ -38,8 +40,6 @@ class Workout:
if not data: if not data:
return {"error": "Workout not found"}, 404 return {"error": "Workout not found"}, 404
exercises = self.execute("SELECT exercise_id, name FROM exercise;")
# Initialize workout dictionary # Initialize workout dictionary
workout_data = { workout_data = {
"workout_id": data[0]["workout_id"], "workout_id": data[0]["workout_id"],
@@ -48,7 +48,6 @@ class Workout:
"note": data[0]["note"], "note": data[0]["note"],
"tags": [], "tags": [],
"top_sets": [], "top_sets": [],
"exercises": exercises
} }
# Initialize helpers for tracking unique tags and topsets # Initialize helpers for tracking unique tags and topsets
@@ -57,15 +56,21 @@ class Workout:
# Process each row and add tags and topsets to workout_data # Process each row and add tags and topsets to workout_data
for row in data: for row in data:
# Add unique tags # Add all unique tags with is_selected property
tag_id = row["tag_id"] tag_id = row["tag_id"]
if tag_id and tag_id not in tag_set: if tag_id and tag_id not in tag_set:
workout_data["tags"].append({"tag_id": tag_id, "tag_name": row["tag_name"]}) workout_data["tags"].append({
"tag_id": tag_id,
"tag_name": row["tag_name"],
"tag_filter": row["tag_filter"],
"person_id": person_id,
"is_selected": row["is_selected"]
})
tag_set.add(tag_id) tag_set.add(tag_id)
# Add unique topsets based on topset_id # Add unique topsets based on topset_id
topset_id = row["topset_id"] topset_id = row["topset_id"]
if topset_id not in topsets_seen: if topset_id and topset_id not in topsets_seen:
workout_data["top_sets"].append({ workout_data["top_sets"].append({
"topset_id": topset_id, "topset_id": topset_id,
"exercise_id": row["exercise_id"], "exercise_id": row["exercise_id"],

View File

@@ -1,7 +1,6 @@
<div class="flex"> <div class="flex">
<div id="tag-wrapper-w-{{ workout_id }}"> <div id="tag-wrapper-w-{{ workout_id }}">
{{ render_partial('partials/workout_tags_list.html', workout_tags=workout_tags) {{ render_partial('partials/workout_tags_list.html', tags=tags)}}
}}
</div> </div>
<span id="tag-form-show-w-{{ workout_id }}" class="cursor-pointer" _="on click <span id="tag-form-show-w-{{ workout_id }}" class="cursor-pointer" _="on click
remove .hidden from #tag-form-w-{{ workout_id }} remove .hidden from #tag-form-w-{{ workout_id }}
@@ -23,7 +22,7 @@
</span> </span>
</div> </div>
<div id="tag-form-w-{{ workout_id }}" class="hidden pt-2 pb-3 animate-fadeIn"> <div id="tag-form-w-{{ workout_id }}" class="hidden pt-2 pb-3">
<span class="text-base font-normal text-gray-500">Add tag to workout</span> <span class="text-base font-normal text-gray-500">Add tag to workout</span>
@@ -46,10 +45,10 @@
placeholder: 'Select tags', placeholder: 'Select tags',
}) })
end"> end">
{% for p in person_tags %} {% for tag in tags %}
<option value="{{ p.tag_id }}" {% if p.tag_id in selected_workout_tag_ids %}selected{% endif %}> <option value="{{ tag.tag_id }}" {% if tag.is_selected %}selected{% endif %}>
{{ {{
p.tag_name tag.tag_name
}}</option> }}</option>
{% endfor %} {% endfor %}
</select> </select>

View File

@@ -1,8 +1,10 @@
{% for tag in workout_tags %} {% for tag in tags %}
{% if tag.is_selected %}
<span <span
class="text-xs font-semibold inline-block py-1 px-2 uppercase rounded text-pink-600 bg-pink-200 uppercase last:mr-0 mr-1 max-h-fit cursor-pointer" class="text-xs font-semibold inline-block py-1 px-2 uppercase rounded text-pink-600 bg-pink-200 uppercase last:mr-0 mr-1 max-h-fit cursor-pointer"
hx-get="{{ url_for('goto_tag') }}" hx-vals='{"filter": "{{ tag.tag_filter }}", "person_id": "{{ tag.person_id }}"}' hx-get="{{ url_for('goto_tag') }}" hx-vals='{"filter": "{{ tag.tag_filter }}", "person_id": "{{ tag.person_id }}"}'
hx-target="#container" hx-push-url="true" _='on click trigger closeModalWithoutRefresh'>{{ hx-target="#container" hx-push-url="true">{{
tag.tag_name }} tag.tag_name }}
</span> </span>
{% endif %}
{% endfor%} {% endfor%}

View File

@@ -13,10 +13,8 @@
<div class="w-full"> <div class="w-full">
<h3 class="text-xl font-bold text-gray-900">{{ person_name }}</h3> <h3 class="text-xl font-bold text-gray-900">{{ person_name }}</h3>
{{ render_partial('partials/workout_tags.html', person_id=person_id, {{ render_partial('partials/workout_tags.html', person_id=person_id, workout_id=workout_id,
workout_id=workout_id, tags=tags) }}
person_tags=person_tags, workout_tags=workout_tags,
selected_workout_tag_ids=selected_workout_tag_ids) }}
</div> </div>