Erste Version Platzhalter EAV #86

Merged
Lars merged 21 commits from develop into main 2026-04-17 21:52:14 +02:00
2 changed files with 56 additions and 9 deletions
Showing only changes of commit c9d71c0179 - Show all commits

View File

@ -260,15 +260,18 @@ def upsert_session_metrics_from_csv_mapped(
nur in ``activity_log``-Kernfeldern). nur in ``activity_log``-Kernfeldern).
Kernfelder schreibt der Executor nach ``activity_log``; hier keine EAV-Zeilen für Registry-Keys. Kernfelder schreibt der Executor nach ``activity_log``; hier keine EAV-Zeilen für Registry-Keys.
Bei gesetztem ``training_parameters.source_field`` ist die Spalte kanonisch kein EAV-Schreiben.
Hat ein Parameter ``source_field`` (Semantik aus ``activity_log``), wird EAV nur dann **nicht**
geschrieben, wenn diese Spalte nach dem Import bereits befüllt ist sonst gäbe es doppelte
Speicherung und der Merge würde ohnehin die Spalte bevorzugen. Ist die Spalte leer (z. B. Feld
nur noch über EAV / Custom-Mapping, ohne Registry-Patch), schreibt der Import den Wert aus
``mapped`` nach EAV analog zum Lesepfad (Spalte zuerst, sonst EAV).
""" """
cur.execute( cur.execute("SELECT * FROM activity_log WHERE id = %s", (activity_log_id,))
"SELECT profile_id FROM activity_log WHERE id = %s",
(activity_log_id,),
)
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
header = dict(row)
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"]
@ -281,6 +284,8 @@ def upsert_session_metrics_from_csv_mapped(
continue continue
sf_raw = spec.get("source_field") sf_raw = spec.get("source_field")
if sf_raw is not None and str(sf_raw).strip(): if sf_raw is not None and str(sf_raw).strip():
col = str(sf_raw).strip()
if col in header and header[col] is not None:
continue continue
tid = spec["training_parameter_id"] tid = spec["training_parameter_id"]
dt = spec["data_type"] dt = spec["data_type"]

View File

@ -329,7 +329,10 @@ def test_upsert_csv_skips_eav_when_source_field_maps_activity_log(mock_schema):
self.asm_inserts += 1 self.asm_inserts += 1
def fetchone(self): def fetchone(self):
return {"profile_id": "00000000-0000-0000-0000-000000000001"} return {
"profile_id": "00000000-0000-0000-0000-000000000001",
"hr_avg": 130,
}
cur = Cur() cur = Cur()
upsert_session_metrics_from_csv_mapped( upsert_session_metrics_from_csv_mapped(
@ -343,6 +346,45 @@ def test_upsert_csv_skips_eav_when_source_field_maps_activity_log(mock_schema):
assert cur.asm_inserts == 0 assert cur.asm_inserts == 0
@patch("data_layer.activity_session_metrics.resolve_activity_attribute_schema")
def test_upsert_csv_writes_eav_when_source_field_but_column_empty(mock_schema):
"""source_field gesetzt, activity_log-Spalte leer — Wert aus mapped nur in EAV (kein Registry-Patch)."""
mock_schema.return_value = [
{
"key": "avg_hr",
"training_parameter_id": 42,
"data_type": "integer",
"validation_rules": {"min": 30, "max": 220},
"source_field": "hr_avg",
}
]
class Cur:
def __init__(self):
self.asm_inserts = 0
def execute(self, sql, params=None):
if "INSERT INTO activity_session_metrics" in sql:
self.asm_inserts += 1
def fetchone(self):
return {
"profile_id": "00000000-0000-0000-0000-000000000001",
"hr_avg": None,
}
cur = Cur()
upsert_session_metrics_from_csv_mapped(
cur,
"00000000-0000-0000-0000-000000000001",
"00000000-0000-0000-0000-000000000002",
{"avg_hr": 130},
"cardio",
1,
)
assert cur.asm_inserts == 1
@patch("data_layer.activity_session_metrics.resolve_activity_attribute_schema") @patch("data_layer.activity_session_metrics.resolve_activity_attribute_schema")
def test_upsert_csv_writes_eav_when_no_source_field(mock_schema): def test_upsert_csv_writes_eav_when_no_source_field(mock_schema):
mock_schema.return_value = [ mock_schema.return_value = [
@ -364,7 +406,7 @@ def test_upsert_csv_writes_eav_when_no_source_field(mock_schema):
self.asm_inserts += 1 self.asm_inserts += 1
def fetchone(self): def fetchone(self):
return {"profile_id": "00000000-0000-0000-0000-000000000001"} return {"profile_id": "00000000-0000-0000-0000-000000000001", "hr_avg": None}
cur = Cur() cur = Cur()
upsert_session_metrics_from_csv_mapped( upsert_session_metrics_from_csv_mapped(
@ -390,7 +432,7 @@ def test_upsert_csv_skips_eav_when_mapped_key_not_in_profile_schema(mock_resolve
self.asm_inserts += 1 self.asm_inserts += 1
def fetchone(self): def fetchone(self):
return {"profile_id": "00000000-0000-0000-0000-000000000001"} return {"profile_id": "00000000-0000-0000-0000-000000000001", "hr_avg": None}
cur = Cur() cur = Cur()
upsert_session_metrics_from_csv_mapped( upsert_session_metrics_from_csv_mapped(