Revert "Revert "feat: surface permit metadata in v2 results""

This reverts commit 33bbbb7d8c.
This commit is contained in:
Codex Agent 2025-10-24 09:05:21 +08:00
parent 33bbbb7d8c
commit 628a4f1435
1 changed files with 82 additions and 9 deletions

View File

@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
import os import os
from typing import Dict, List from typing import Dict, List, Optional, Set
import pg8000.dbapi as pg import pg8000.dbapi as pg
@ -104,6 +104,13 @@ def _load_permit_scopes_for_region(
return scope_map return scope_map
def _clean_text(value: Optional[str]) -> Optional[str]:
if value is None:
return None
txt = str(value).strip()
return txt or None
def load_permits_and_risks(region_id: str, theme_id: str) -> List[Dict[str, object]]: def load_permits_and_risks(region_id: str, theme_id: str) -> List[Dict[str, object]]:
"""Return permits with attached risk entries for a region-theme pair.""" """Return permits with attached risk entries for a region-theme pair."""
sql = """ sql = """
@ -114,9 +121,21 @@ def load_permits_and_risks(region_id: str, theme_id: str) -> List[Dict[str, obje
rk.risk_content, rk.risk_content,
rk.legal_basis, rk.legal_basis,
rk.document_no, rk.document_no,
rk.summary rk.summary,
rpd.permit_status,
rpd.subitem_summary,
rpd.responsible_contact,
rpd.jurisdiction_scope,
psi.description AS subitem_desc
FROM region_theme_permits rtp FROM region_theme_permits rtp
JOIN permits p ON p.id = rtp.permit_id JOIN permits p ON p.id = rtp.permit_id
LEFT JOIN region_permit_details rpd
ON rpd.region_id = rtp.region_id
AND rpd.permit_id = rtp.permit_id
LEFT JOIN region_permit_subitems rpsi
ON rpsi.region_id = rtp.region_id
AND rpsi.permit_id = rtp.permit_id
LEFT JOIN permit_subitems psi ON psi.id = rpsi.subitem_id
LEFT JOIN region_permit_risks rpr LEFT JOIN region_permit_risks rpr
ON rpr.region_id = rtp.region_id ON rpr.region_id = rtp.region_id
AND rpr.permit_id = rtp.permit_id AND rpr.permit_id = rtp.permit_id
@ -129,7 +148,20 @@ def load_permits_and_risks(region_id: str, theme_id: str) -> List[Dict[str, obje
cur = conn.cursor() cur = conn.cursor()
cur.execute(sql, (region_id, theme_id)) cur.execute(sql, (region_id, theme_id))
for row in cur.fetchall(): for row in cur.fetchall():
permit_id, permit_name, risk_id, risk_content, legal_basis, document_no, summary = row (
permit_id,
permit_name,
risk_id,
risk_content,
legal_basis,
document_no,
summary,
permit_status,
subitem_summary,
responsible_contact,
jurisdiction_scope,
subitem_desc,
) = row
pid = str(permit_id) pid = str(permit_id)
entry = permits.setdefault( entry = permits.setdefault(
pid, pid,
@ -138,23 +170,64 @@ def load_permits_and_risks(region_id: str, theme_id: str) -> List[Dict[str, obje
"name": str(permit_name), "name": str(permit_name),
"business_scopes": [], "business_scopes": [],
"risks": [], "risks": [],
"scopes": [],
"risk_count": 0,
"permit_status": None,
"subitem_summary": None,
"subitems": [],
"responsible_contact": None,
"jurisdiction_scope": None,
"_risk_ids": set(),
"_subitems": set(),
}, },
) )
if permit_status is not None:
entry["permit_status"] = _clean_text(permit_status)
if subitem_summary is not None:
entry["subitem_summary"] = _clean_text(subitem_summary)
if responsible_contact is not None:
entry["responsible_contact"] = _clean_text(responsible_contact)
if jurisdiction_scope is not None:
entry["jurisdiction_scope"] = _clean_text(jurisdiction_scope)
if subitem_desc:
cleaned = _clean_text(subitem_desc)
if cleaned:
entry["_subitems"].add(cleaned)
if risk_id is not None: if risk_id is not None:
rid = str(risk_id)
risk_ids: Set[str] = entry["_risk_ids"]
if rid in risk_ids:
continue
risk_ids.add(rid)
entry["risks"].append( entry["risks"].append(
{ {
"id": str(risk_id), "id": rid,
"risk_content": risk_content or "", "risk_content": _clean_text(risk_content) or "",
"legal_basis": legal_basis or "", "legal_basis": _clean_text(legal_basis) or "",
"document_no": document_no or "", "document_no": _clean_text(document_no) or "",
"summary": summary or "", "summary": _clean_text(summary) or "",
} }
) )
permit_ids = list(permits.keys()) permit_ids = list(permits.keys())
scope_map = _load_permit_scopes_for_region(conn, region_id, permit_ids) scope_map = _load_permit_scopes_for_region(conn, region_id, permit_ids)
for pid in permit_ids: for pid in permit_ids:
permits[pid]["business_scopes"] = scope_map.get(pid, []) entry = permits[pid]
entry["business_scopes"] = scope_map.get(pid, [])
entry["scopes"] = [
scope.get("description", "")
for scope in entry["business_scopes"]
if scope.get("description")
]
subitems_set: Set[str] = entry.pop("_subitems", set())
entry["subitems"] = sorted(subitems_set)
risk_ids: Set[str] = entry.pop("_risk_ids", set())
entry["risk_count"] = len(risk_ids)
# Ensure optional text fields default to None if empty strings slipped through
entry["permit_status"] = _clean_text(entry.get("permit_status"))
entry["subitem_summary"] = _clean_text(entry.get("subitem_summary"))
entry["responsible_contact"] = _clean_text(entry.get("responsible_contact"))
entry["jurisdiction_scope"] = _clean_text(entry.get("jurisdiction_scope"))
return list(permits.values()) return list(permits.values())