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(