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).
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(
"SELECT profile_id FROM activity_log WHERE id = %s",
(activity_log_id,),
)
cur.execute("SELECT * FROM activity_log WHERE id = %s", (activity_log_id,))
row = cur.fetchone()
if not row or str(row["profile_id"]) != str(profile_id):
return
header = dict(row)
schema = resolve_activity_attribute_schema(cur, training_category, training_type_id)
for spec in schema:
pkey = spec["key"]
@ -281,7 +284,9 @@ def upsert_session_metrics_from_csv_mapped(
continue
sf_raw = spec.get("source_field")
if sf_raw is not None and str(sf_raw).strip():
continue
col = str(sf_raw).strip()
if col in header and header[col] is not None:
continue
tid = spec["training_parameter_id"]
dt = spec["data_type"]
rules = _validation_rules_dict(spec["validation_rules"])

View File

@ -329,7 +329,10 @@ def test_upsert_csv_skips_eav_when_source_field_maps_activity_log(mock_schema):
self.asm_inserts += 1
def fetchone(self):
return {"profile_id": "00000000-0000-0000-0000-000000000001"}
return {
"profile_id": "00000000-0000-0000-0000-000000000001",
"hr_avg": 130,
}
cur = Cur()
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
@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")
def test_upsert_csv_writes_eav_when_no_source_field(mock_schema):
mock_schema.return_value = [
@ -364,7 +406,7 @@ def test_upsert_csv_writes_eav_when_no_source_field(mock_schema):
self.asm_inserts += 1
def fetchone(self):
return {"profile_id": "00000000-0000-0000-0000-000000000001"}
return {"profile_id": "00000000-0000-0000-0000-000000000001", "hr_avg": None}
cur = Cur()
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
def fetchone(self):
return {"profile_id": "00000000-0000-0000-0000-000000000001"}
return {"profile_id": "00000000-0000-0000-0000-000000000001", "hr_avg": None}
cur = Cur()
upsert_session_metrics_from_csv_mapped(