fix: Refine EAV writing logic in session metrics upsert function
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Build Test / pytest-backend (push) Successful in 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 16s

- Updated the `upsert_session_metrics_from_csv_mapped` function to ensure EAV writes are only skipped when the `source_field` is populated, preventing duplicate storage.
- Enhanced unit tests to cover scenarios where the `source_field` is set but the corresponding column is empty, ensuring correct EAV behavior.
- Adjusted test cases to reflect changes in the handling of `hr_avg` and other metrics, improving overall test coverage and accuracy.
This commit is contained in:
Lars 2026-04-16 13:01:32 +02:00
parent 9d5e16455c
commit c9d71c0179
2 changed files with 56 additions and 9 deletions

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,6 +284,8 @@ 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():
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"]

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(