Replace fixed DSL fields with parameterized metric expressions

This commit is contained in:
Peter Stockings
2026-10-04 10:24:12 +11:00
parent 418e03583a
commit d660b86bb0
18 changed files with 402 additions and 137 deletions
+19 -17
View File
@@ -18,41 +18,41 @@ def daily(history, owner_id, zone, start, end, q, catalog):
db.select(DailyHealth).where(DailyHealth.owner_id == owner_id,
DailyHealth.day >= start, DailyHealth.day < end))}
result = []
last_run = last_long = None
last_matching = {}
streak = 0
earlier = [r for r in history if r.day < start]
if earlier:
last_run = max(r.day for r in earlier)
longs = [r.day for r in earlier if r.distance_m >= q["long_run"] * 1000]
last_long = max(longs) if longs else None
day = start - timedelta(days=1)
while by_day[day]:
streak += 1
day -= timedelta(days=1)
from .analysis_engine import matches
since_specs = [s for s in q["derived"] if "since" in s]
for spec in since_specs:
qualifying = [r.day for r in earlier if matches(r, spec["since"])]
last_matching[spec["name"]] = max(qualifying) if qualifying else None
for index in range((end - start).days):
day = start + timedelta(days=index)
rows = by_day[day]
if rows:
last_run = day
streak += 1
else:
streak = 0
if any(r.distance_m >= q["long_run"] * 1000 for r in rows):
last_long = day
values = {key: None for key in catalog}
distance = sum(r.distance_m for r in rows)
duration = sum(r.duration_s for r in rows)
values.update(distance=distance / 1000, duration=duration / 3600,
sessions=len(rows), count=1, run_day_streak=streak,
days_since_run=(day - last_run).days if last_run else None,
days_since_long_run=(day - last_long).days if last_long else None)
for days in (7, 28):
window = [r for d in range(days) for r in by_day[day - timedelta(days=d)]]
values[f"rolling_{days}d_distance"] = sum(r.distance_m for r in window) / 1000
values[f"rolling_{days}d_count"] = len(window)
if days == 7:
total = sum(r.distance_m for r in window)
values["long_run_share"] = max(r.distance_m for r in window) / total * 100 if total else None
sessions=len(rows), count=1, run_day_streak=streak)
window = [r for d in range(7) for r in by_day[day - timedelta(days=d)]]
total = sum(r.distance_m for r in window)
values["long_run_share"] = max(r.distance_m for r in window) / total * 100 if total else None
for spec in since_specs:
name = spec["name"]
if any(matches(r, spec["since"]) for r in rows):
last_matching[name] = day
last = last_matching[name]
values[name] = (day - last).days if last else None
for field in ("perceived_effort", "fatigue"):
known = [r.values[field] for r in rows if valid(r.values.get(field))]
values[field] = sum(known) / len(known) if known else None
@@ -69,6 +69,8 @@ def daily(history, owner_id, zone, start, end, q, catalog):
activity_id=None, activity_ids=[r.id for r in rows])
result.append(row)
for spec in q["derived"]:
if "since" in spec:
continue
if "window" in spec:
config = spec["window"]
from .stats_analysis import statistic