fix: Phase 0b - correct all SQL column names in calculation engine
Schema corrections applied: - weight_log: weight_kg → weight - nutrition_log: calories → kcal - activity_log: duration → duration_min, avg_heart_rate → hr_avg, max_heart_rate → hr_max - rest_days: rest_type → type (aliased for backward compat) - vitals_baseline: resting_heart_rate → resting_hr - sleep_log: total_sleep_min → duration_minutes, deep_min → deep_minutes, rem_min → rem_minutes, waketime → wake_time - focus_area_definitions: fa.focus_area_id → fa.key (proper join column) Affected files: - body_metrics.py: weight column (all queries) - nutrition_metrics.py: kcal column + weight - activity_metrics.py: duration_min, hr_avg, hr_max, quality via RPE mapping - recovery_metrics.py: sleep + vitals columns - correlation_metrics.py: kcal, weight - scores.py: focus_area key selection All 100+ Phase 0b placeholders should now calculate correctly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
53969f8768
commit
4817fd2b29
|
|
@ -29,7 +29,7 @@ def calculate_training_minutes_week(profile_id: str) -> Optional[int]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT SUM(duration) as total_minutes
|
SELECT SUM(duration_min) as total_minutes
|
||||||
FROM activity_log
|
FROM activity_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
||||||
|
|
@ -87,7 +87,7 @@ def calculate_intensity_proxy_distribution(profile_id: str) -> Optional[Dict]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT duration, avg_heart_rate, max_heart_rate
|
SELECT duration_min, hr_avg, hr_max
|
||||||
FROM activity_log
|
FROM activity_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '28 days'
|
AND date >= CURRENT_DATE - INTERVAL '28 days'
|
||||||
|
|
@ -103,9 +103,9 @@ def calculate_intensity_proxy_distribution(profile_id: str) -> Optional[Dict]:
|
||||||
high_min = 0
|
high_min = 0
|
||||||
|
|
||||||
for activity in activities:
|
for activity in activities:
|
||||||
duration = activity['duration']
|
duration = activity['duration_min']
|
||||||
avg_hr = activity['avg_heart_rate']
|
avg_hr = activity['hr_avg']
|
||||||
max_hr = activity['max_heart_rate']
|
max_hr = activity['hr_max']
|
||||||
|
|
||||||
# Simple proxy classification
|
# Simple proxy classification
|
||||||
if avg_hr:
|
if avg_hr:
|
||||||
|
|
@ -139,7 +139,7 @@ def calculate_ability_balance(profile_id: str) -> Optional[Dict]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT a.duration, tt.abilities
|
SELECT a.duration_min, tt.abilities
|
||||||
FROM activity_log a
|
FROM activity_log a
|
||||||
JOIN training_types tt ON a.training_category = tt.category
|
JOIN training_types tt ON a.training_category = tt.category
|
||||||
WHERE a.profile_id = %s
|
WHERE a.profile_id = %s
|
||||||
|
|
@ -162,7 +162,7 @@ def calculate_ability_balance(profile_id: str) -> Optional[Dict]:
|
||||||
}
|
}
|
||||||
|
|
||||||
for activity in activities:
|
for activity in activities:
|
||||||
duration = activity['duration']
|
duration = activity['duration_min']
|
||||||
abilities = activity['abilities'] # JSONB
|
abilities = activity['abilities'] # JSONB
|
||||||
|
|
||||||
if not abilities:
|
if not abilities:
|
||||||
|
|
@ -237,7 +237,7 @@ def calculate_proxy_internal_load_7d(profile_id: str) -> Optional[int]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT duration, avg_heart_rate, quality_label
|
SELECT duration_min, hr_avg, rpe
|
||||||
FROM activity_log
|
FROM activity_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
||||||
|
|
@ -251,9 +251,18 @@ def calculate_proxy_internal_load_7d(profile_id: str) -> Optional[int]:
|
||||||
total_load = 0
|
total_load = 0
|
||||||
|
|
||||||
for activity in activities:
|
for activity in activities:
|
||||||
duration = activity['duration']
|
duration = activity['duration_min']
|
||||||
avg_hr = activity['avg_heart_rate']
|
avg_hr = activity['hr_avg']
|
||||||
quality = activity['quality_label'] or 'good'
|
# Map RPE to quality (rpe 8-10 = excellent, 6-7 = good, 4-5 = moderate, <4 = poor)
|
||||||
|
rpe = activity.get('rpe')
|
||||||
|
if rpe and rpe >= 8:
|
||||||
|
quality = 'excellent'
|
||||||
|
elif rpe and rpe >= 6:
|
||||||
|
quality = 'good'
|
||||||
|
elif rpe and rpe >= 4:
|
||||||
|
quality = 'moderate'
|
||||||
|
else:
|
||||||
|
quality = 'good' # default
|
||||||
|
|
||||||
# Determine intensity
|
# Determine intensity
|
||||||
if avg_hr:
|
if avg_hr:
|
||||||
|
|
@ -281,7 +290,7 @@ def calculate_monotony_score(profile_id: str) -> Optional[float]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT date, SUM(duration) as daily_duration
|
SELECT date, SUM(duration_min) as daily_duration
|
||||||
FROM activity_log
|
FROM activity_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
||||||
|
|
@ -432,7 +441,7 @@ def _score_cardio_presence(profile_id: str) -> Optional[int]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT COUNT(DISTINCT date) as cardio_days, SUM(duration) as cardio_minutes
|
SELECT COUNT(DISTINCT date) as cardio_days, SUM(duration_min) as cardio_minutes
|
||||||
FROM activity_log
|
FROM activity_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
||||||
|
|
@ -486,7 +495,7 @@ def calculate_rest_day_compliance(profile_id: str) -> Optional[int]:
|
||||||
|
|
||||||
# Get planned rest days
|
# Get planned rest days
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT date, rest_type
|
SELECT date, type as rest_type
|
||||||
FROM rest_days
|
FROM rest_days
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '28 days'
|
AND date >= CURRENT_DATE - INTERVAL '28 days'
|
||||||
|
|
|
||||||
|
|
@ -26,14 +26,14 @@ def calculate_weight_7d_median(profile_id: str) -> Optional[float]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT weight_kg
|
SELECT weight
|
||||||
FROM weight_log
|
FROM weight_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
||||||
ORDER BY date DESC
|
ORDER BY date DESC
|
||||||
""", (profile_id,))
|
""", (profile_id,))
|
||||||
|
|
||||||
weights = [row['weight_kg'] for row in cur.fetchall()]
|
weights = [row['weight'] for row in cur.fetchall()]
|
||||||
|
|
||||||
if len(weights) < 4: # Need at least 4 measurements
|
if len(weights) < 4: # Need at least 4 measurements
|
||||||
return None
|
return None
|
||||||
|
|
@ -59,14 +59,14 @@ def _calculate_weight_slope(profile_id: str, days: int) -> Optional[float]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT date, weight_kg
|
SELECT date, weight
|
||||||
FROM weight_log
|
FROM weight_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '%s days'
|
AND date >= CURRENT_DATE - INTERVAL '%s days'
|
||||||
ORDER BY date
|
ORDER BY date
|
||||||
""", (profile_id, days))
|
""", (profile_id, days))
|
||||||
|
|
||||||
data = [(row['date'], row['weight_kg']) for row in cur.fetchall()]
|
data = [(row['date'], row['weight']) for row in cur.fetchall()]
|
||||||
|
|
||||||
# Need minimum data points based on period
|
# Need minimum data points based on period
|
||||||
min_points = max(18, int(days * 0.6)) # 60% coverage
|
min_points = max(18, int(days * 0.6)) # 60% coverage
|
||||||
|
|
@ -158,7 +158,7 @@ def _calculate_body_composition_change(profile_id: str, metric: str, days: int)
|
||||||
|
|
||||||
# Get weight and caliper measurements
|
# Get weight and caliper measurements
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT w.date, w.weight_kg, c.body_fat_pct
|
SELECT w.date, w.weight, c.body_fat_pct
|
||||||
FROM weight_log w
|
FROM weight_log w
|
||||||
LEFT JOIN caliper_log c ON w.profile_id = c.profile_id
|
LEFT JOIN caliper_log c ON w.profile_id = c.profile_id
|
||||||
AND w.date = c.date
|
AND w.date = c.date
|
||||||
|
|
@ -170,7 +170,7 @@ def _calculate_body_composition_change(profile_id: str, metric: str, days: int)
|
||||||
data = [
|
data = [
|
||||||
{
|
{
|
||||||
'date': row['date'],
|
'date': row['date'],
|
||||||
'weight': row['weight_kg'],
|
'weight': row['weight'],
|
||||||
'bf_pct': row['body_fat_pct']
|
'bf_pct': row['body_fat_pct']
|
||||||
}
|
}
|
||||||
for row in cur.fetchall()
|
for row in cur.fetchall()
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ def _correlate_energy_weight(profile_id: str, max_lag: int) -> Optional[Dict]:
|
||||||
|
|
||||||
# Get energy balance data (daily calories - estimated TDEE)
|
# Get energy balance data (daily calories - estimated TDEE)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT n.date, n.calories, w.weight_kg
|
SELECT n.date, n.kcal, w.weight
|
||||||
FROM nutrition_log n
|
FROM nutrition_log n
|
||||||
LEFT JOIN weight_log w ON w.profile_id = n.profile_id
|
LEFT JOIN weight_log w ON w.profile_id = n.profile_id
|
||||||
AND w.date = n.date
|
AND w.date = n.date
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,14 @@ def calculate_energy_balance_7d(profile_id: str) -> Optional[float]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT calories
|
SELECT kcal
|
||||||
FROM nutrition_log
|
FROM nutrition_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
||||||
ORDER BY date DESC
|
ORDER BY date DESC
|
||||||
""", (profile_id,))
|
""", (profile_id,))
|
||||||
|
|
||||||
calories = [row['calories'] for row in cur.fetchall()]
|
calories = [row['kcal'] for row in cur.fetchall()]
|
||||||
|
|
||||||
if len(calories) < 4: # Need at least 4 days
|
if len(calories) < 4: # Need at least 4 days
|
||||||
return None
|
return None
|
||||||
|
|
@ -46,7 +46,7 @@ def calculate_energy_balance_7d(profile_id: str) -> Optional[float]:
|
||||||
# Get estimated TDEE (simplified - could use Harris-Benedict)
|
# Get estimated TDEE (simplified - could use Harris-Benedict)
|
||||||
# For now, use weight-based estimate
|
# For now, use weight-based estimate
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT weight_kg
|
SELECT weight
|
||||||
FROM weight_log
|
FROM weight_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
ORDER BY date DESC
|
ORDER BY date DESC
|
||||||
|
|
@ -59,7 +59,7 @@ def calculate_energy_balance_7d(profile_id: str) -> Optional[float]:
|
||||||
|
|
||||||
# Simple TDEE estimate: bodyweight (kg) × 30-35
|
# Simple TDEE estimate: bodyweight (kg) × 30-35
|
||||||
# TODO: Improve with activity level, age, gender
|
# TODO: Improve with activity level, age, gender
|
||||||
estimated_tdee = weight_row['weight_kg'] * 32.5
|
estimated_tdee = weight_row['weight'] * 32.5
|
||||||
|
|
||||||
balance = avg_intake - estimated_tdee
|
balance = avg_intake - estimated_tdee
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ def calculate_protein_g_per_kg(profile_id: str) -> Optional[float]:
|
||||||
|
|
||||||
# Get recent weight
|
# Get recent weight
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT weight_kg
|
SELECT weight
|
||||||
FROM weight_log
|
FROM weight_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
ORDER BY date DESC
|
ORDER BY date DESC
|
||||||
|
|
@ -106,7 +106,7 @@ def calculate_protein_g_per_kg(profile_id: str) -> Optional[float]:
|
||||||
if not weight_row:
|
if not weight_row:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
weight_kg = weight_row['weight_kg']
|
weight = weight_row['weight']
|
||||||
|
|
||||||
# Get protein intake
|
# Get protein intake
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
|
|
@ -124,7 +124,7 @@ def calculate_protein_g_per_kg(profile_id: str) -> Optional[float]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
avg_protein = sum(protein_values) / len(protein_values)
|
avg_protein = sum(protein_values) / len(protein_values)
|
||||||
protein_per_kg = avg_protein / weight_kg
|
protein_per_kg = avg_protein / weight
|
||||||
|
|
||||||
return round(protein_per_kg, 2)
|
return round(protein_per_kg, 2)
|
||||||
|
|
||||||
|
|
@ -139,7 +139,7 @@ def calculate_protein_days_in_target(profile_id: str, target_low: float = 1.6, t
|
||||||
|
|
||||||
# Get recent weight
|
# Get recent weight
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT weight_kg
|
SELECT weight
|
||||||
FROM weight_log
|
FROM weight_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
ORDER BY date DESC
|
ORDER BY date DESC
|
||||||
|
|
@ -150,7 +150,7 @@ def calculate_protein_days_in_target(profile_id: str, target_low: float = 1.6, t
|
||||||
if not weight_row:
|
if not weight_row:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
weight_kg = weight_row['weight_kg']
|
weight = weight_row['weight']
|
||||||
|
|
||||||
# Get protein intake last 7 days
|
# Get protein intake last 7 days
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
|
|
@ -172,7 +172,7 @@ def calculate_protein_days_in_target(profile_id: str, target_low: float = 1.6, t
|
||||||
total_days = len(protein_data)
|
total_days = len(protein_data)
|
||||||
|
|
||||||
for row in protein_data:
|
for row in protein_data:
|
||||||
protein_per_kg = row['protein_g'] / weight_kg
|
protein_per_kg = row['protein_g'] / weight
|
||||||
if target_low <= protein_per_kg <= target_high:
|
if target_low <= protein_per_kg <= target_high:
|
||||||
days_in_target += 1
|
days_in_target += 1
|
||||||
|
|
||||||
|
|
@ -189,7 +189,7 @@ def calculate_protein_adequacy_28d(profile_id: str) -> Optional[int]:
|
||||||
|
|
||||||
# Get average weight (28d)
|
# Get average weight (28d)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT AVG(weight_kg) as avg_weight
|
SELECT AVG(weight) as avg_weight
|
||||||
FROM weight_log
|
FROM weight_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '28 days'
|
AND date >= CURRENT_DATE - INTERVAL '28 days'
|
||||||
|
|
@ -199,7 +199,7 @@ def calculate_protein_adequacy_28d(profile_id: str) -> Optional[int]:
|
||||||
if not weight_row or not weight_row['avg_weight']:
|
if not weight_row or not weight_row['avg_weight']:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
weight_kg = weight_row['avg_weight']
|
weight = weight_row['avg_weight']
|
||||||
|
|
||||||
# Get protein intake (28d)
|
# Get protein intake (28d)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
|
|
@ -216,7 +216,7 @@ def calculate_protein_adequacy_28d(profile_id: str) -> Optional[int]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Calculate metrics
|
# Calculate metrics
|
||||||
protein_per_kg_values = [p / weight_kg for p in protein_values]
|
protein_per_kg_values = [p / weight for p in protein_values]
|
||||||
avg_protein_per_kg = sum(protein_per_kg_values) / len(protein_per_kg_values)
|
avg_protein_per_kg = sum(protein_per_kg_values) / len(protein_per_kg_values)
|
||||||
|
|
||||||
# Target range: 1.6-2.2 g/kg for active individuals
|
# Target range: 1.6-2.2 g/kg for active individuals
|
||||||
|
|
@ -258,11 +258,11 @@ def calculate_macro_consistency_score(profile_id: str) -> Optional[int]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT calories, protein_g, fat_g, carbs_g
|
SELECT kcal, protein_g, fat_g, carbs_g
|
||||||
FROM nutrition_log
|
FROM nutrition_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '28 days'
|
AND date >= CURRENT_DATE - INTERVAL '28 days'
|
||||||
AND calories IS NOT NULL
|
AND kcal IS NOT NULL
|
||||||
ORDER BY date DESC
|
ORDER BY date DESC
|
||||||
""", (profile_id,))
|
""", (profile_id,))
|
||||||
|
|
||||||
|
|
@ -282,7 +282,7 @@ def calculate_macro_consistency_score(profile_id: str) -> Optional[int]:
|
||||||
std_dev = statistics.stdev(values)
|
std_dev = statistics.stdev(values)
|
||||||
return std_dev / mean
|
return std_dev / mean
|
||||||
|
|
||||||
calories_cv = cv([d['calories'] for d in data])
|
calories_cv = cv([d['kcal'] for d in data])
|
||||||
protein_cv = cv([d['protein_g'] for d in data if d['protein_g']])
|
protein_cv = cv([d['protein_g'] for d in data if d['protein_g']])
|
||||||
fat_cv = cv([d['fat_g'] for d in data if d['fat_g']])
|
fat_cv = cv([d['fat_g'] for d in data if d['fat_g']])
|
||||||
carbs_cv = cv([d['carbs_g'] for d in data if d['carbs_g']])
|
carbs_cv = cv([d['carbs_g'] for d in data if d['carbs_g']])
|
||||||
|
|
@ -427,7 +427,7 @@ def _score_macro_balance(profile_id: str) -> Optional[int]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT protein_g, fat_g, carbs_g, calories
|
SELECT protein_g, fat_g, carbs_g, kcal
|
||||||
FROM nutrition_log
|
FROM nutrition_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '28 days'
|
AND date >= CURRENT_DATE - INTERVAL '28 days'
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ def _score_rhr_vs_baseline(profile_id: str) -> Optional[int]:
|
||||||
|
|
||||||
# Get recent RHR (last 3 days average)
|
# Get recent RHR (last 3 days average)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT AVG(resting_heart_rate) as recent_rhr
|
SELECT AVG(resting_hr) as recent_rhr
|
||||||
FROM vitals_baseline
|
FROM vitals_baseline
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND resting_heart_rate IS NOT NULL
|
AND resting_heart_rate IS NOT NULL
|
||||||
|
|
@ -336,7 +336,7 @@ def calculate_rhr_vs_baseline_pct(profile_id: str) -> Optional[float]:
|
||||||
|
|
||||||
# Recent RHR (3d avg)
|
# Recent RHR (3d avg)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT AVG(resting_heart_rate) as recent_rhr
|
SELECT AVG(resting_hr) as recent_rhr
|
||||||
FROM vitals_baseline
|
FROM vitals_baseline
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND resting_heart_rate IS NOT NULL
|
AND resting_heart_rate IS NOT NULL
|
||||||
|
|
@ -374,7 +374,7 @@ def calculate_sleep_avg_duration_7d(profile_id: str) -> Optional[float]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT AVG(total_sleep_min) as avg_sleep_min
|
SELECT AVG(duration_minutes) as avg_sleep_min
|
||||||
FROM sleep_log
|
FROM sleep_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
||||||
|
|
@ -399,7 +399,7 @@ def calculate_sleep_debt_hours(profile_id: str) -> Optional[float]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT total_sleep_min
|
SELECT duration_minutes
|
||||||
FROM sleep_log
|
FROM sleep_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '14 days'
|
AND date >= CURRENT_DATE - INTERVAL '14 days'
|
||||||
|
|
@ -427,12 +427,12 @@ def calculate_sleep_regularity_proxy(profile_id: str) -> Optional[float]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT bedtime, waketime, date
|
SELECT bedtime, wake_time, date
|
||||||
FROM sleep_log
|
FROM sleep_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '14 days'
|
AND date >= CURRENT_DATE - INTERVAL '14 days'
|
||||||
AND bedtime IS NOT NULL
|
AND bedtime IS NOT NULL
|
||||||
AND waketime IS NOT NULL
|
AND wake_time IS NOT NULL
|
||||||
ORDER BY date
|
ORDER BY date
|
||||||
""", (profile_id,))
|
""", (profile_id,))
|
||||||
|
|
||||||
|
|
@ -495,7 +495,7 @@ def calculate_sleep_quality_7d(profile_id: str) -> Optional[int]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT total_sleep_min, deep_min, rem_min
|
SELECT duration_minutes, deep_minutes, rem_minutes
|
||||||
FROM sleep_log
|
FROM sleep_log
|
||||||
WHERE profile_id = %s
|
WHERE profile_id = %s
|
||||||
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
AND date >= CURRENT_DATE - INTERVAL '7 days'
|
||||||
|
|
@ -509,8 +509,8 @@ def calculate_sleep_quality_7d(profile_id: str) -> Optional[int]:
|
||||||
|
|
||||||
quality_scores = []
|
quality_scores = []
|
||||||
for s in sleep_data:
|
for s in sleep_data:
|
||||||
if s['deep_min'] and s['rem_min']:
|
if s['deep_minutes'] and s['rem_minutes']:
|
||||||
quality_pct = ((s['deep_min'] + s['rem_min']) / s['total_sleep_min']) * 100
|
quality_pct = ((s['deep_minutes'] + s['rem_minutes']) / s['duration_minutes']) * 100
|
||||||
# 40-60% deep+REM is good
|
# 40-60% deep+REM is good
|
||||||
if quality_pct >= 45:
|
if quality_pct >= 45:
|
||||||
quality_scores.append(100)
|
quality_scores.append(100)
|
||||||
|
|
|
||||||
|
|
@ -26,15 +26,15 @@ def get_user_focus_weights(profile_id: str) -> Dict[str, float]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT fa.focus_area_id, ufw.weight_pct
|
SELECT ufw.focus_area_id, ufw.weight as weight_pct, fa.key
|
||||||
FROM user_focus_area_weights ufw
|
FROM user_focus_area_weights ufw
|
||||||
JOIN focus_area_definitions fa ON ufw.focus_area_id = fa.id
|
JOIN focus_area_definitions fa ON ufw.focus_area_id = fa.id
|
||||||
WHERE ufw.profile_id = %s
|
WHERE ufw.profile_id = %s
|
||||||
AND ufw.weight_pct > 0
|
AND ufw.weight > 0
|
||||||
""", (profile_id,))
|
""", (profile_id,))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
row['focus_area_id']: float(row['weight_pct'])
|
row['key']: float(row['weight_pct'])
|
||||||
for row in cur.fetchall()
|
for row in cur.fetchall()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,13 +410,13 @@ def get_top_priority_goal(profile_id: str) -> Optional[Dict]:
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT fa.focus_area_id
|
SELECT fa.key as focus_area_key
|
||||||
FROM goal_focus_contributions gfc
|
FROM goal_focus_contributions gfc
|
||||||
JOIN focus_area_definitions fa ON gfc.focus_area_id = fa.id
|
JOIN focus_area_definitions fa ON gfc.focus_area_id = fa.id
|
||||||
WHERE gfc.goal_id = %s
|
WHERE gfc.goal_id = %s
|
||||||
""", (goal['id'],))
|
""", (goal['id'],))
|
||||||
|
|
||||||
goal_focus_areas = [row['focus_area_id'] for row in cur.fetchall()]
|
goal_focus_areas = [row['focus_area_key'] for row in cur.fetchall()]
|
||||||
|
|
||||||
# Sum focus weights
|
# Sum focus weights
|
||||||
goal['total_focus_weight'] = sum(
|
goal['total_focus_weight'] = sum(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user