feat: Refactor activity data handling to use dynamic registry fields
- Replaced hardcoded keys in `activity_data_canon.py` with a dynamic retrieval method from the module registry, ensuring that `ACTIVITY_MODULE_REGISTRY_FIELD_KEYS` reflects the current configuration. - Updated `activity_persistence_orchestrator.py` to utilize the new dynamic field retrieval function, enhancing consistency across the data layer. - Modified `activity_session_metrics.py` to reference the dynamic field keys, improving maintainability and reducing redundancy in the codebase.
This commit is contained in:
parent
06f83e2ffc
commit
8d0a6dd487
|
|
@ -1,8 +1,10 @@
|
||||||
"""
|
"""
|
||||||
Kanonische Aufteilung activity_log vs. EAV für Aktivitätssessions.
|
Kanonische Aufteilung activity_log vs. EAV für Aktivitätssessions.
|
||||||
|
|
||||||
Single Source für: welche Felder das CSV-/Registry-Modul „activity“ direkt in activity_log schreibt,
|
- **Kern / Mapping-Ziele für activity_log:** ausschließlich die Keys aus
|
||||||
und welche training_parameters primär über EAV laufen (mit optionalem Lesefallback auf Legacy-Spalten).
|
``csv_parser.module_registry.MODULE_DEFINITIONS["activity"].fields`` (keine zweite hartcodierte Liste).
|
||||||
|
- **Alle anderen Attribute:** ``training_parameters`` + Attributprofil (Kategorie/Typ) → EAV;
|
||||||
|
Lesefallback für bekannte Legacy-Spalten siehe unten.
|
||||||
|
|
||||||
Normative Doku: .claude/docs/technical/ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md
|
Normative Doku: .claude/docs/technical/ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md
|
||||||
"""
|
"""
|
||||||
|
|
@ -10,25 +12,22 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import Dict, Final
|
from typing import Dict, Final
|
||||||
|
|
||||||
# ── activity_log: Modul „activity“ (Universal-CSV-Kern) ───────────────────────
|
from csv_parser.module_registry import get_module_definition
|
||||||
# Nur diese Keys erscheinen in csv_parser.module_registry MODULE_DEFINITIONS["activity"].fields.
|
|
||||||
# Alles Weitere: training_parameters + EAV (Import über upsert_session_metrics_from_csv_mapped).
|
|
||||||
ACTIVITY_MODULE_REGISTRY_FIELD_KEYS: Final[frozenset[str]] = frozenset(
|
def get_activity_module_registry_field_keys() -> frozenset[str]:
|
||||||
{
|
"""Keys des Universal-CSV-Moduls ``activity`` (= feste activity_log-Kernfelder / Mapping-Ziele)."""
|
||||||
"date",
|
mod = get_module_definition("activity")
|
||||||
"start_time",
|
if not mod:
|
||||||
"end_time",
|
return frozenset()
|
||||||
"activity_type",
|
return frozenset((mod.get("fields") or {}).keys())
|
||||||
"duration_min",
|
|
||||||
"kcal_active",
|
|
||||||
"kcal_resting",
|
# Gleiche Menge wie ``MODULE_DEFINITIONS["activity"].fields`` — zur Laufzeit aus der Registry abgeleitet.
|
||||||
"distance_km",
|
ACTIVITY_MODULE_REGISTRY_FIELD_KEYS: Final[frozenset[str]] = get_activity_module_registry_field_keys()
|
||||||
"hr_avg",
|
|
||||||
"hr_max",
|
# Teil-UPDATEs (Import): alle Kernfelder außer ``date`` (Identität / Duplikat-Key).
|
||||||
"rpe",
|
ACTIVITY_LOG_PATCHABLE_COLUMNS: Final[frozenset[str]] = ACTIVITY_MODULE_REGISTRY_FIELD_KEYS - {"date"}
|
||||||
"notes",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Parameter-Keys (training_parameters.key), die primär in EAV geführt werden; source_field nach Migration 057 NULL.
|
# Parameter-Keys (training_parameters.key), die primär in EAV geführt werden; source_field nach Migration 057 NULL.
|
||||||
# Lesefallback: activity_log-Spalte unter ACTIVITY_LOG_LEGACY_COLUMN_FOR_EAV_PRIMARY_PARAM, falls EAV leer.
|
# Lesefallback: activity_log-Spalte unter ACTIVITY_LOG_LEGACY_COLUMN_FOR_EAV_PRIMARY_PARAM, falls EAV leer.
|
||||||
|
|
@ -59,20 +58,3 @@ ACTIVITY_LOG_LEGACY_COLUMN_FOR_EAV_PRIMARY_PARAM: Final[Dict[str, str]] = {
|
||||||
"kcal_per_km": "kcal_per_km",
|
"kcal_per_km": "kcal_per_km",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Spalten, die mit training_parameters.source_field (nach Migration 057) noch activity_log abbilden.
|
|
||||||
# Erweiterte Metriken sind EAV-primär — nicht hier auflisten.
|
|
||||||
ACTIVITY_LOG_PATCHABLE_COLUMNS: Final[frozenset[str]] = frozenset(
|
|
||||||
{
|
|
||||||
"start_time",
|
|
||||||
"end_time",
|
|
||||||
"activity_type",
|
|
||||||
"duration_min",
|
|
||||||
"kcal_active",
|
|
||||||
"kcal_resting",
|
|
||||||
"hr_avg",
|
|
||||||
"hr_max",
|
|
||||||
"distance_km",
|
|
||||||
"rpe",
|
|
||||||
"notes",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ from typing import Any, Dict, List, Mapping, Optional
|
||||||
from models import ActivityEntry
|
from models import ActivityEntry
|
||||||
|
|
||||||
from csv_parser.module_registry import get_module_definition
|
from csv_parser.module_registry import get_module_definition
|
||||||
|
from data_layer.activity_data_canon import get_activity_module_registry_field_keys
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -50,10 +51,8 @@ _ACTIVITY_CSV_REGISTRY_EXCLUDE = frozenset({"date", "start_time", "end_time", "a
|
||||||
|
|
||||||
|
|
||||||
def activity_registry_field_keys() -> frozenset[str]:
|
def activity_registry_field_keys() -> frozenset[str]:
|
||||||
mod = get_module_definition("activity")
|
"""Gleiche Menge wie ``ACTIVITY_MODULE_REGISTRY_FIELD_KEYS`` (Registry als Single Source)."""
|
||||||
if not mod:
|
return get_activity_module_registry_field_keys()
|
||||||
return frozenset()
|
|
||||||
return frozenset((mod.get("fields") or {}).keys())
|
|
||||||
|
|
||||||
|
|
||||||
def activity_csv_registry_updates_from_mapped(mapped: Mapping[str, Any]) -> Dict[str, Any]:
|
def activity_csv_registry_updates_from_mapped(mapped: Mapping[str, Any]) -> Dict[str, Any]:
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,10 @@ import logging
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Any, Dict, List, Mapping, Optional, Sequence
|
from typing import Any, Dict, List, Mapping, Optional, Sequence
|
||||||
|
|
||||||
from csv_parser.module_registry import get_module_definition
|
from data_layer.activity_data_canon import (
|
||||||
from data_layer.activity_data_canon import ACTIVITY_LOG_LEGACY_COLUMN_FOR_EAV_PRIMARY_PARAM
|
ACTIVITY_LOG_LEGACY_COLUMN_FOR_EAV_PRIMARY_PARAM,
|
||||||
|
ACTIVITY_MODULE_REGISTRY_FIELD_KEYS,
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -262,8 +264,6 @@ def upsert_session_metrics_from_csv_mapped(
|
||||||
row = cur.fetchone()
|
row = cur.fetchone()
|
||||||
if not row or str(row["profile_id"]) != str(profile_id):
|
if not row or str(row["profile_id"]) != str(profile_id):
|
||||||
return
|
return
|
||||||
mod = get_module_definition("activity") or {}
|
|
||||||
activity_registry_keys = frozenset((mod.get("fields") or {}).keys())
|
|
||||||
schema = resolve_activity_attribute_schema(cur, training_category, training_type_id)
|
schema = resolve_activity_attribute_schema(cur, training_category, training_type_id)
|
||||||
for spec in schema:
|
for spec in schema:
|
||||||
pkey = spec["key"]
|
pkey = spec["key"]
|
||||||
|
|
@ -272,7 +272,7 @@ def upsert_session_metrics_from_csv_mapped(
|
||||||
raw = mapped[pkey]
|
raw = mapped[pkey]
|
||||||
if raw is None or raw == "":
|
if raw is None or raw == "":
|
||||||
continue
|
continue
|
||||||
if pkey in activity_registry_keys:
|
if pkey in ACTIVITY_MODULE_REGISTRY_FIELD_KEYS:
|
||||||
continue
|
continue
|
||||||
tid = spec["training_parameter_id"]
|
tid = spec["training_parameter_id"]
|
||||||
dt = spec["data_type"]
|
dt = spec["data_type"]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user