fix(company-profile): deserialize JSONB columns in row_to_response
CI / detect-changes (push) Successful in 9s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / build-sha-integrity (push) Failing after 3s
CI / validate-canonical-controls (push) Successful in 13s
CI / loc-budget (push) Failing after 15s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Has been skipped
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-backend (push) Successful in 30s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped

Raw text() queries return JSONB columns as JSON-encoded Python strings,
not as Python list/dict objects. The existing isinstance check then fails
and silently falls back to defaults — so list-valued fields like
target_markets, offerings, processing_systems, ai_systems were always
returned as their defaults regardless of stored content.

Add a JSON-decode pass over _JSONB_FIELDS before the type check.

Verified: PATCH of target_markets=["DE","EU"] now round-trips through
GET correctly. Previously the DB had the right data but GET returned
["DE"] (the default).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-07 08:26:14 +02:00
parent 5958b575b1
commit 4cad0a29ad
@@ -109,7 +109,12 @@ def _where_clause() -> str:
def row_to_response(row: Any) -> CompanyProfileResponse:
"""Convert a DB row to response model using zip-based column mapping."""
"""Convert a DB row to response model using zip-based column mapping.
JSONB columns may arrive as JSON strings from raw text() queries — we
json.loads them first so the isinstance check below succeeds against the
expected Python type.
"""
raw = dict(zip(_BASE_COLUMNS_LIST, row))
coerced: dict[str, Any] = {}
@@ -117,6 +122,13 @@ def row_to_response(row: Any) -> CompanyProfileResponse:
default, expected_type = _FIELD_DEFAULTS[col]
value = raw[col]
# JSONB columns can come back as JSON-encoded strings from raw queries
if col in _JSONB_FIELDS and isinstance(value, str):
try:
value = json.loads(value)
except (json.JSONDecodeError, TypeError):
pass # fall through to default below
if expected_type == "STR":
coerced[col] = str(value)
elif expected_type == "STR_OR_NONE":