Download src/t2s/serving/dbs.py from Ashoksainibadu/text2sql-assistant: direct link, hf CLI and curl.
- Browser
- Download file 6.58 kB
-
https://huggingface.co/spaces/Ashoksainibadu/text2sql-assistant/resolve/main/src/t2s/serving/dbs.py
- Command line
-
hf download hf://spaces/Ashoksainibadu/text2sql-assistant/src/t2s/serving/dbs.py
-
curl -L -o dbs.py https://huggingface.co/spaces/Ashoksainibadu/text2sql-assistant/resolve/main/src/t2s/serving/dbs.py
6.58 kB
| """Database registry for demo SQLite databases.""" | |
| import sqlite3 | |
| from pathlib import Path | |
| from typing import Any, Dict, List, Optional | |
| from src.t2s.data.schema import get_sqlite_schema_ddl | |
| class DatabaseRegistry: | |
| def __init__(self, db_base_dir: str = "data/raw/spider/database") -> None: | |
| self.db_base_dir = Path(db_base_dir) | |
| self._upload_dirs: list[Path] = [] # user-uploaded db directories | |
| def register_upload_dir(self, upload_dir: str) -> None: | |
| """Register an additional directory that contains user-uploaded .sqlite files.""" | |
| p = Path(upload_dir) | |
| if p not in self._upload_dirs: | |
| self._upload_dirs.append(p) | |
| def get_db_info_from_path(self, db_path: str, db_id: str) -> dict: | |
| """Return db info dict directly from an absolute path (for uploads).""" | |
| tables: list[str] = [] | |
| try: | |
| conn = sqlite3.connect(db_path) | |
| cursor = conn.cursor() | |
| cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") | |
| tables = [r[0] for r in cursor.fetchall() if not r[0].startswith("sqlite_")] | |
| conn.close() | |
| except Exception: | |
| tables = [] | |
| p = Path(db_path) | |
| size_bytes = p.stat().st_size if p.exists() else 0 | |
| return { | |
| "db_id": db_id, | |
| "table_count": len(tables), | |
| "tables": tables, | |
| "size_bytes": size_bytes, | |
| "source": "uploaded", | |
| } | |
| def list_databases(self) -> List[Dict[str, Any]]: | |
| seen_dbs = set() | |
| dbs = [] | |
| if self.db_base_dir.exists(): | |
| # Check nested subdirectories (e.g. data/raw/spider/database/<db_id>/<db_id>.sqlite) | |
| for p in sorted(self.db_base_dir.glob("*/*.sqlite")): | |
| db_id = p.parent.name | |
| if db_id not in seen_dbs: | |
| info = self.get_db_info(db_id) | |
| if info is not None: | |
| seen_dbs.add(db_id) | |
| dbs.append(info) | |
| # Check flat files (e.g. data/raw/spider/database/<db_id>.sqlite) | |
| for p in sorted(self.db_base_dir.glob("*.sqlite")): | |
| db_id = p.stem | |
| if db_id not in seen_dbs: | |
| info = self.get_db_info(db_id) | |
| if info is not None: | |
| seen_dbs.add(db_id) | |
| dbs.append(info) | |
| # Check user-uploaded databases | |
| for upload_dir in self._upload_dirs: | |
| for p in sorted(upload_dir.glob("*.sqlite")): | |
| db_id = p.stem | |
| if db_id not in seen_dbs: | |
| info = self.get_db_info_from_path(str(p), db_id) | |
| seen_dbs.add(db_id) | |
| dbs.append(info) | |
| # Fallback to committed seed databases in db/seeds/ if not found | |
| seeds_dir = Path("db/seeds") | |
| if seeds_dir.exists(): | |
| for p in sorted(seeds_dir.glob("*.sqlite")): | |
| db_id = p.stem | |
| # Support chinook_1 alias for chinook.sqlite | |
| alias_ids = [db_id] | |
| if db_id == "chinook": | |
| alias_ids.append("chinook_1") | |
| for aid in alias_ids: | |
| if aid not in seen_dbs: | |
| info = self.get_db_info_from_path(str(p), aid) | |
| seen_dbs.add(aid) | |
| dbs.append(info) | |
| return dbs | |
| def get_db_path(self, db_id: str) -> Optional[Path]: | |
| # Path traversal guard | |
| if not db_id or ".." in db_id or "/" in db_id or "\\" in db_id: | |
| return None | |
| import os | |
| if os.getenv("APP_PROFILE", "").lower() == "demo": | |
| allowed_demo_dbs = os.getenv("DEMO_DB_ALLOWLIST", "chinook_1").split(",") | |
| if db_id not in [d.strip() for d in allowed_demo_dbs if d.strip()]: | |
| # Also allow user-uploaded databases in demo mode | |
| for upload_dir in self._upload_dirs: | |
| p = (upload_dir / f"{db_id}.sqlite").resolve() | |
| if p.exists() and upload_dir.resolve() in p.parents: | |
| return p | |
| return None | |
| p = (self.db_base_dir / f"{db_id}.sqlite").resolve() | |
| base_resolved = self.db_base_dir.resolve() | |
| if p.exists() and base_resolved in p.parents: | |
| return p | |
| p_sub = (self.db_base_dir / db_id / f"{db_id}.sqlite").resolve() | |
| if p_sub.exists() and base_resolved in p_sub.parents: | |
| return p_sub | |
| # Check upload dirs | |
| for upload_dir in self._upload_dirs: | |
| pu = (upload_dir / f"{db_id}.sqlite").resolve() | |
| if pu.exists() and upload_dir.resolve() in pu.parents: | |
| return pu | |
| # Fallback to committed seed databases in db/seeds/ | |
| seeds_dir = Path("db/seeds") | |
| if seeds_dir.exists(): | |
| ps = (seeds_dir / f"{db_id}.sqlite").resolve() | |
| if ps.exists() and seeds_dir.resolve() in ps.parents: | |
| return ps | |
| if db_id == "chinook_1": | |
| ps_chinook = (seeds_dir / "chinook.sqlite").resolve() | |
| if ps_chinook.exists() and seeds_dir.resolve() in ps_chinook.parents: | |
| return ps_chinook | |
| return None | |
| def get_db_info(self, db_id: str) -> Optional[Dict[str, Any]]: | |
| db_path = self.get_db_path(db_id) | |
| if not db_path: | |
| return None | |
| tables = [] | |
| try: | |
| conn = sqlite3.connect(db_path) | |
| cursor = conn.cursor() | |
| cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") | |
| tables = [row[0] for row in cursor.fetchall() if not row[0].startswith("sqlite_")] | |
| conn.close() | |
| except Exception: | |
| tables = [] | |
| size_bytes = db_path.stat().st_size if db_path.exists() else 0 | |
| return { | |
| "db_id": db_id, | |
| "table_count": len(tables), | |
| "tables": tables, | |
| "size_bytes": size_bytes, | |
| "source": "builtin", | |
| } | |
| def get_schema_ddl(self, db_id: str, include_sample_rows: bool = False) -> str: | |
| db_path = self.get_db_path(db_id) | |
| if not db_path: | |
| raise FileNotFoundError(f"Database '{db_id}' not found") | |
| return get_sqlite_schema_ddl(str(db_path), include_sample_rows=include_sample_rows) | |