"""Collection utilities extracted for SME exporter. Functions: - zip_rows_to_dicts(rows): convert sequences of row-like objects with keys to dicts - dedupe_list_preserve_order(items): remove duplicates keeping first occurrence order """ from __future__ import annotations from typing import Iterable, Any, List, Dict def zip_rows_to_dicts(rows: Iterable[Any]) -> List[Dict[str, Any]]: """Convert row-like objects to dicts by zipping column names to values. Accepts objects that provide `.keys()` and support item access by key, such as DB-API row proxies. Normalizes keys to lowercase for consistency. """ result: List[Dict[str, Any]] = [] for row in rows: keys = list(row.keys()) if hasattr(row, "keys") else [] # Normalize keys to lowercase for consistency with SQLAlchemy 2.x result.append({k.lower(): row[k] for k in keys}) return result def dedupe_list_preserve_order(items: Iterable[Any]) -> List[Any]: """Remove duplicates from iterable while preserving original order.""" seen: set[Any] = set() out: List[Any] = [] for x in items: if x not in seen: seen.add(x) out.append(x) return out