fix: robust error handling in goal value fetcher
Prevents crashes when: - Goal types have NULL source_table/column (lean_mass, inactive placeholders) - Old goals reference inactive goal types - SQL queries fail for any reason Changes: - Guard clause checks table/column before SQL - try-catch wraps all aggregation queries - Returns None gracefully instead of crashing endpoint - Logs warnings for debugging Fixes: Goals page not loading due to /api/goals/list crash
This commit is contained in:
parent
1e758696fd
commit
1f4ee5021e
|
|
@ -245,82 +245,92 @@ def _fetch_by_aggregation_method(
|
|||
- min_30d: Minimum value in last 30 days
|
||||
- max_30d: Maximum value in last 30 days
|
||||
"""
|
||||
# Guard: source_table/column required for simple aggregation
|
||||
if not table or not column:
|
||||
print(f"[WARNING] Missing source_table or source_column for aggregation")
|
||||
return None
|
||||
|
||||
cur = get_cursor(conn)
|
||||
|
||||
if method == 'latest':
|
||||
cur.execute(f"""
|
||||
SELECT {column} FROM {table}
|
||||
WHERE profile_id = %s AND {column} IS NOT NULL
|
||||
ORDER BY date DESC LIMIT 1
|
||||
""", (profile_id,))
|
||||
row = cur.fetchone()
|
||||
return float(row[column]) if row else None
|
||||
try:
|
||||
if method == 'latest':
|
||||
cur.execute(f"""
|
||||
SELECT {column} FROM {table}
|
||||
WHERE profile_id = %s AND {column} IS NOT NULL
|
||||
ORDER BY date DESC LIMIT 1
|
||||
""", (profile_id,))
|
||||
row = cur.fetchone()
|
||||
return float(row[column]) if row else None
|
||||
|
||||
elif method == 'avg_7d':
|
||||
days_ago = date.today() - timedelta(days=7)
|
||||
cur.execute(f"""
|
||||
SELECT AVG({column}) as avg_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s AND {column} IS NOT NULL
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['avg_value']) if row and row['avg_value'] is not None else None
|
||||
elif method == 'avg_7d':
|
||||
days_ago = date.today() - timedelta(days=7)
|
||||
cur.execute(f"""
|
||||
SELECT AVG({column}) as avg_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s AND {column} IS NOT NULL
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['avg_value']) if row and row['avg_value'] is not None else None
|
||||
|
||||
elif method == 'avg_30d':
|
||||
days_ago = date.today() - timedelta(days=30)
|
||||
cur.execute(f"""
|
||||
SELECT AVG({column}) as avg_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s AND {column} IS NOT NULL
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['avg_value']) if row and row['avg_value'] is not None else None
|
||||
elif method == 'avg_30d':
|
||||
days_ago = date.today() - timedelta(days=30)
|
||||
cur.execute(f"""
|
||||
SELECT AVG({column}) as avg_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s AND {column} IS NOT NULL
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['avg_value']) if row and row['avg_value'] is not None else None
|
||||
|
||||
elif method == 'sum_30d':
|
||||
days_ago = date.today() - timedelta(days=30)
|
||||
cur.execute(f"""
|
||||
SELECT SUM({column}) as sum_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s AND {column} IS NOT NULL
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['sum_value']) if row and row['sum_value'] is not None else None
|
||||
elif method == 'sum_30d':
|
||||
days_ago = date.today() - timedelta(days=30)
|
||||
cur.execute(f"""
|
||||
SELECT SUM({column}) as sum_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s AND {column} IS NOT NULL
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['sum_value']) if row and row['sum_value'] is not None else None
|
||||
|
||||
elif method == 'count_7d':
|
||||
days_ago = date.today() - timedelta(days=7)
|
||||
cur.execute(f"""
|
||||
SELECT COUNT(*) as count_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['count_value']) if row else 0.0
|
||||
elif method == 'count_7d':
|
||||
days_ago = date.today() - timedelta(days=7)
|
||||
cur.execute(f"""
|
||||
SELECT COUNT(*) as count_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['count_value']) if row else 0.0
|
||||
|
||||
elif method == 'count_30d':
|
||||
days_ago = date.today() - timedelta(days=30)
|
||||
cur.execute(f"""
|
||||
SELECT COUNT(*) as count_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['count_value']) if row else 0.0
|
||||
elif method == 'count_30d':
|
||||
days_ago = date.today() - timedelta(days=30)
|
||||
cur.execute(f"""
|
||||
SELECT COUNT(*) as count_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['count_value']) if row else 0.0
|
||||
|
||||
elif method == 'min_30d':
|
||||
days_ago = date.today() - timedelta(days=30)
|
||||
cur.execute(f"""
|
||||
SELECT MIN({column}) as min_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s AND {column} IS NOT NULL
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['min_value']) if row and row['min_value'] is not None else None
|
||||
elif method == 'min_30d':
|
||||
days_ago = date.today() - timedelta(days=30)
|
||||
cur.execute(f"""
|
||||
SELECT MIN({column}) as min_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s AND {column} IS NOT NULL
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['min_value']) if row and row['min_value'] is not None else None
|
||||
|
||||
elif method == 'max_30d':
|
||||
days_ago = date.today() - timedelta(days=30)
|
||||
cur.execute(f"""
|
||||
SELECT MAX({column}) as max_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s AND {column} IS NOT NULL
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['max_value']) if row and row['max_value'] is not None else None
|
||||
elif method == 'max_30d':
|
||||
days_ago = date.today() - timedelta(days=30)
|
||||
cur.execute(f"""
|
||||
SELECT MAX({column}) as max_value FROM {table}
|
||||
WHERE profile_id = %s AND date >= %s AND {column} IS NOT NULL
|
||||
""", (profile_id, days_ago))
|
||||
row = cur.fetchone()
|
||||
return float(row['max_value']) if row and row['max_value'] is not None else None
|
||||
|
||||
else:
|
||||
print(f"[WARNING] Unknown aggregation method: {method}")
|
||||
else:
|
||||
print(f"[WARNING] Unknown aggregation method: {method}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Failed to fetch value from {table}.{column} using {method}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user