Spaces:
Runtime error
Runtime error
| # src/db.py — SQLite helpers (HF Spaces-friendly) | |
| from __future__ import annotations | |
| import os, shutil, sqlite3 | |
| from pathlib import Path | |
| # Canonical schema lives in repo | |
| REPO_DIR = Path(__file__).resolve().parents[1] | |
| CANONICAL_SCHEMA = REPO_DIR / "src" / "schema.sql" | |
| # Writable defaults on HF Spaces | |
| DEFAULT_DB = Path("/tmp/pol_indexer.sqlite") | |
| DEFAULT_SCHEMA = Path("/tmp/schema.sql") | |
| def _is_writable(p: Path) -> bool: | |
| try: | |
| p.parent.mkdir(parents=True, exist_ok=True) | |
| test = p.parent / ".write_test" | |
| test.write_text("ok", encoding="utf-8") | |
| test.unlink(missing_ok=True) | |
| return True | |
| except Exception: | |
| return False | |
| # Resolve DB_PATH | |
| _env_db = os.getenv("DB_PATH") | |
| DB_PATH = Path(_env_db).resolve() if _env_db else DEFAULT_DB | |
| if not _is_writable(DB_PATH): | |
| DB_PATH = DEFAULT_DB | |
| # Resolve SCHEMA_PATH | |
| _env_schema = os.getenv("SCHEMA_PATH") | |
| SCHEMA_PATH = Path(_env_schema).resolve() if _env_schema else DEFAULT_SCHEMA | |
| if not _is_writable(SCHEMA_PATH): | |
| SCHEMA_PATH = DEFAULT_SCHEMA | |
| # Ensure runtime schema exists in the chosen writable location | |
| def _ensure_runtime_schema(): | |
| if SCHEMA_PATH.exists(): | |
| return | |
| src = CANONICAL_SCHEMA if CANONICAL_SCHEMA.exists() else (REPO_DIR / "schema.sql") | |
| if not src.exists(): | |
| raise FileNotFoundError(f"Canonical schema not found at {src}") | |
| SCHEMA_PATH.parent.mkdir(parents=True, exist_ok=True) | |
| shutil.copyfile(src, SCHEMA_PATH) | |
| def _log_paths(): | |
| print("[DB paths]") | |
| print(f" REPO_DIR = {REPO_DIR}") | |
| print(f" CANON_SCHEMA = {CANONICAL_SCHEMA} (exists={CANONICAL_SCHEMA.exists()})") | |
| print(f" RUNTIME_SCHEMA= {SCHEMA_PATH} (exists={SCHEMA_PATH.exists()})") | |
| print(f" DB_PATH = {DB_PATH} (exists={DB_PATH.exists()})") | |
| # Call once on import | |
| _ensure_runtime_schema() | |
| _log_paths() | |
| def get_connection() -> sqlite3.Connection: | |
| conn = sqlite3.connect(str(DB_PATH), timeout=30, check_same_thread=False) | |
| conn.row_factory = sqlite3.Row | |
| with conn: | |
| conn.execute("PRAGMA journal_mode=WAL;") | |
| conn.execute("PRAGMA foreign_keys=ON;") | |
| conn.execute("PRAGMA synchronous=NORMAL;") | |
| return conn | |
| def init_db(w3=None, confirmations: int = 12) -> None: | |
| """ | |
| Initialize or verify DB schema. | |
| w3 + confirmations are accepted for compatibility with indexer, | |
| but not used directly here. This way you won’t get argument errors. | |
| """ | |
| sql = SCHEMA_PATH.read_text(encoding="utf-8") | |
| with get_connection() as conn: | |
| conn.executescript(sql) | |
| print(f"[DB] Schema verified. Using DB at {DB_PATH}") | |
| def get_latest_netflow(): | |
| with get_connection() as conn: | |
| cur = conn.cursor() | |
| cur.execute(""" | |
| SELECT created_at, cumulative_value | |
| FROM netflow | |
| ORDER BY created_at DESC | |
| LIMIT 1 | |
| """) | |
| row = cur.fetchone() | |
| if not row: | |
| return None | |
| return {"created_at": row["created_at"], "cumulative_value": str(row["cumulative_value"])} | |
| def table_counts() -> dict: | |
| out = {} | |
| with get_connection() as conn: | |
| c = conn.cursor() | |
| for t in ("transfers", "netflow", "raw_logs", "meta"): | |
| try: | |
| c.execute(f"SELECT COUNT(*) AS n FROM {t}") | |
| out[t] = int(c.fetchone()["n"]) | |
| except Exception: | |
| out[t] = -1 | |
| return out | |
| # do not refer | |
| # import sqlite3 | |
| # from pathlib import Path | |
| # DB_PATH = Path(__file__).resolve().parent.parent / "data" / "netflow.db" | |
| # def get_connection(): | |
| # conn = sqlite3.connect(DB_PATH) | |
| # conn.row_factory = sqlite3.Row # lets us fetch rows like dictionary | |
| # return conn | |
| # def init_db(): | |
| # conn = get_connection() | |
| # cur = conn.cursor() | |
| # # table for raw transactions we care about | |
| # cur.execute(""" | |
| # CREATE TABLE IF NOT EXISTS transactions ( | |
| # tx_hash TEXT PRIMARY KEY, | |
| # block_number INTEGER, | |
| # from_address TEXT, | |
| # to_address TEXT, | |
| # value REAL, | |
| # timestamp INTEGER | |
| # ); | |
| # """) | |
| # # table to track cumulative netflow / running netflow values | |
| # cur.execute(""" | |
| # CREATE TABLE IF NOT EXISTS netflow ( | |
| # id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| # timestamp INTEGER, | |
| # cumulative_value REAL | |
| # ); | |
| # """) | |
| # conn.commit() | |
| # conn.close() | |
| # print(f"Database initialized at {DB_PATH}") | |