from __future__ import annotations import json import re def safe_table_id(value: str, *, max_length: int = 900) -> str: """Return a stable BigQuery table id for source names that may contain mixed case or symbols.""" text = re.sub(r"[^A-Za-z0-9_]", "_", value).strip("_").lower() text = re.sub(r"_+", "_", text) if not text: text = "table" if text[0].isdigit(): text = f"t_{text}" return text[:max_length] def run_id_token(run_id: str) -> str: return safe_table_id(run_id, max_length=120) def bq_path(project: str, dataset: str, table: str) -> str: return f"`{project}.{dataset}.{table}`" def quote_name(name: str) -> str: return f"`{name.replace('`', '``')}`" def sql_string(value: str) -> str: return json.dumps(value) def table_prefix(source_name: str, table_name: str) -> str: return safe_table_id(f"{source_name}_{table_name}")