Files
workout/features/stats.py

132 lines
5.3 KiB
Python

from collections import defaultdict
from datetime import date
class Stats:
def __init__(self, db_connection_method):
self.execute = db_connection_method
def get_stats_from_topsets(self, topsets):
if not topsets:
return []
# Extract necessary fields
workout_ids = [t["WorkoutId"] for t in topsets if t["WorkoutId"]]
person_ids = [t["PersonId"] for t in topsets if t["PersonId"]]
start_dates = [t["StartDate"] for t in topsets if t["StartDate"]]
exercise_ids = [t["ExerciseId"] for t in topsets if t["ExerciseId"]]
workout_count = len(set(workout_ids))
people_count = len(set(person_ids))
total_sets = len(topsets)
exercise_count = len(set(exercise_ids))
# Group sets by workout and exercise
sets_per_exercise_per_workout = defaultdict(lambda: defaultdict(int))
for t in topsets:
if t["WorkoutId"] and t["ExerciseId"]:
sets_per_exercise_per_workout[t["WorkoutId"]][t["ExerciseId"]] += 1
# Calculate the average sets per exercise across all workouts
total_sets_per_exercise = []
for workout_exercises in sets_per_exercise_per_workout.values():
total_sets_per_exercise.extend(workout_exercises.values())
average_sets_per_exercise = round(sum(total_sets_per_exercise) / len(total_sets_per_exercise), 1) if total_sets_per_exercise else 0
# Group exercises by workout
exercises_by_workout = defaultdict(set)
for t in topsets:
if t["WorkoutId"] and t["ExerciseId"]:
exercises_by_workout[t["WorkoutId"]].add(t["ExerciseId"])
# Calculate average exercises per workout
average_exercises_per_workout = round(
sum(len(exercises) for exercises in exercises_by_workout.values()) / workout_count, 1
) if workout_count > 0 else 0
# Stats
stats = [
{"Text": "Total Workouts", "Value": workout_count},
{"Text": "Total Sets", "Value": total_sets},
{"Text": "Average Sets Per Exercise", "Value": average_sets_per_exercise}
]
if exercise_count > 1:
stats.append({"Text": "Total Exercises", "Value": exercise_count})
stats.append({"Text": "Average Exercises Per Workout", "Value": average_exercises_per_workout})
if people_count > 1:
stats.append({"Text": "People Tracked", "Value": people_count})
if workout_count > 0:
first_workout_date = min(start_dates)
last_workout_date = max(start_dates)
current_date = date.today()
stats.append({"Text": "Days Since First Workout",
"Value": (current_date - first_workout_date).days})
if workout_count >= 2:
stats.append({"Text": "Days Since Last Workout",
"Value": (current_date - last_workout_date).days})
average_sets_per_workout = round(total_sets / workout_count, 1)
stats.append({"Text": "Average Sets Per Workout",
"Value": average_sets_per_workout})
training_duration = last_workout_date - first_workout_date
if training_duration.days > 0:
average_workouts_per_week = round(
workout_count / (training_duration.days / 7), 1)
stats.append({"Text": "Average Workouts Per Week",
"Value": average_workouts_per_week})
return stats
def fetch_stats(self, selected_people_ids=None, min_date=None, max_date=None, selected_exercise_ids=None):
# Base query
query = """
SELECT
t.workout_id AS "WorkoutId",
w.person_id AS "PersonId",
w.start_date AS "StartDate",
e.exercise_id AS "ExerciseId"
FROM
topset t
JOIN workout w ON t.workout_id = w.workout_id
JOIN person p ON w.person_id = p.person_id
JOIN exercise e ON t.exercise_id = e.exercise_id
"""
# Parameters for the query
params = []
# Add optional filters
conditions = [] # Collect conditions dynamically
if selected_people_ids:
placeholders = ", ".join(["%s"] * len(selected_people_ids))
conditions.append(f"p.person_id IN ({placeholders})")
params.extend(selected_people_ids)
if min_date:
conditions.append("w.start_date >= %s")
params.append(min_date)
if max_date:
conditions.append("w.start_date <= %s")
params.append(max_date)
if selected_exercise_ids:
placeholders = ", ".join(["%s"] * len(selected_exercise_ids))
conditions.append(f"e.exercise_id IN ({placeholders})")
params.extend(selected_exercise_ids)
# Add conditions to the query
if conditions:
query += " WHERE " + " AND ".join(conditions)
# Execute the query
workouts_data = self.execute(query, params)
# Generate stats from the retrieved data
stats = self.get_stats_from_topsets(workouts_data)
return stats