Files
clientflow_backend/app/db_helpers.py

42 lines
1.4 KiB
Python

"""Small persistence helpers for safer SQL text usage.
ClientFlow still uses SQLAlchemy ``text()`` for PostgreSQL-specific JSONB and
reconciliation queries. These helpers standardise JSONB patches so new code can
prefer ``metadata = metadata || CAST(:metadata_patch AS jsonb)`` over fragile
``jsonb_build_object('x', :param)`` patterns.
"""
from __future__ import annotations
import json
from datetime import date, datetime, timezone
from decimal import Decimal
from typing import Any, Dict, Mapping, Optional
from uuid import UUID
def json_default(value: Any) -> Any:
if isinstance(value, (datetime, date)):
return value.isoformat()
if isinstance(value, UUID):
return str(value)
if isinstance(value, Decimal):
# Use string to avoid float rounding in money fields.
return str(value)
if isinstance(value, set):
return sorted(str(item) for item in value)
return str(value)
def jsonb_param(value: Any) -> str:
"""Return a JSON string suitable for ``CAST(:param AS jsonb)``."""
return json.dumps(value if value is not None else {}, ensure_ascii=False, default=json_default)
def metadata_patch(**items: Any) -> Dict[str, Any]:
"""Create a small metadata patch with an ISO timestamp when requested."""
return {key: value for key, value in items.items() if value is not None}
def utc_now_text() -> str:
return datetime.now(timezone.utc).isoformat()