""" 数据版本上下文:通过 ContextVar 传递"当前查询使用哪个版本的数据"。 - 读路径:store 层的 list/search/count/get_by_id 从 ACTIVE_VERSION 读当前版本,加到 WHERE - 写路径:insert 时使用业务显式传入的 version(不从 contextvar 推断),避免误写入 - knowledge 表默认带 'v0'(共享基层),其他表不带 典型调用链: FastAPI middleware 从请求头 X-KnowHub-Version 或 ?version=xxx 读取 → set_version('dev_dedup') → store.list_all() 内部自动过滤 WHERE version = 'dev_dedup' """ from contextvars import ContextVar from typing import Tuple, List DEFAULT_VERSION = 'tao_dev' KNOWLEDGE_BASE_VERSION = 'v0' # knowledge 共享基层,永远包含 ACTIVE_VERSION: ContextVar[str] = ContextVar('knowhub_active_version', default=DEFAULT_VERSION) def get_version() -> str: return ACTIVE_VERSION.get() def set_version(v: str) -> None: ACTIVE_VERSION.set(v) def requirement_version() -> str: """ reqs 的映射规则(非对称): - active='tao_dev' → 'tao_dev'(tao_dev 有自己的 req 行,带 __td 后缀) - active='dev_abstract' / 'dev_dedup' → 'v0'(这两版共享 v0 reqs,从未复制) - 其它 → 'v0' """ v = ACTIVE_VERSION.get() return v if v == 'tao_dev' else 'v0' def req_version_where(alias: str = '') -> Tuple[str, List[str]]: col = f'{alias}.version' if alias else 'version' return f'{col} = %s', [requirement_version()] def version_where(alias: str = '', include_v0: bool = False) -> Tuple[str, List[str]]: """ 构造 WHERE 版本过滤片段。 Args: alias: 表别名(如 'k' / 'strategy'),空则不加前缀 include_v0: 是否把 'v0' 也纳入(knowledge 用) Returns: (sql_fragment, params) — sql_fragment 用 %s 占位,params 给 cursor.execute """ v = get_version() col = f'{alias}.version' if alias else 'version' if include_v0 and v != KNOWLEDGE_BASE_VERSION: return f'{col} = ANY(%s)', [[v, KNOWLEDGE_BASE_VERSION]] return f'{col} = %s', [v]