"""Market overview snapshot persistence.""" import json from datetime import datetime from app.db.schema import get_conn SNAPSHOT_TYPE = "crypto_market" def _now(): return datetime.now().isoformat(timespec="seconds") def save_market_snapshot(data, *, status="success", error_message=""): payload = data if isinstance(data, dict) else {} snapshot_time = str(payload.get("updated_at") or _now()) source = str(payload.get("source") or "binance_spot_usdt_market") conn = get_conn() try: row = conn.execute( """ INSERT INTO market_snapshots ( snapshot_type, source, snapshot_time, data_json, status, error_message, created_at ) VALUES (%s, %s, %s, %s, %s, %s, %s) RETURNING id """, ( SNAPSHOT_TYPE, source, snapshot_time, json.dumps(payload, ensure_ascii=False, default=str), status, str(error_message or "")[:1000], _now(), ), ).fetchone() conn.commit() return int(row["id"] if row else 0) except Exception: conn.rollback() raise finally: conn.close() def get_latest_market_snapshot(max_age_seconds=None): conn = get_conn() try: row = conn.execute( """ SELECT * FROM market_snapshots WHERE snapshot_type=%s AND status='success' ORDER BY snapshot_time DESC, id DESC LIMIT 1 """, (SNAPSHOT_TYPE,), ).fetchone() finally: conn.close() if not row: return None item = dict(row) try: data = json.loads(item.get("data_json") or "{}") except Exception: data = {} if not isinstance(data, dict): data = {} data.setdefault("updated_at", item.get("snapshot_time") or "") data.setdefault("source", item.get("source") or "binance_spot_usdt_market") if max_age_seconds: try: ts = datetime.fromisoformat(str(item.get("snapshot_time") or data.get("updated_at"))) data["snapshot_age_seconds"] = max(0, round((datetime.now() - ts).total_seconds())) data["snapshot_stale"] = data["snapshot_age_seconds"] > int(max_age_seconds) except Exception: data["snapshot_age_seconds"] = None data["snapshot_stale"] = True return data def save_market_error(error_message, data=None): payload = data if isinstance(data, dict) else {"updated_at": _now(), "source": "binance_spot_usdt_market"} return save_market_snapshot(payload, status="error", error_message=error_message)