# adapter_python_pg 项目指令 基于 ontology(本体)数据基座的 **Python 中间层适配器**。用 YAML 定义实体、关系、属性、动作、规则,由本适配器驱动 PostgreSQL 完成读写与图查询,对上暴露实体/对象级的语义接口。 **这是一份给 AI 编码工具(Claude Code / Codex / Hermes / OpenCode)的项目约定**,优先级高于 README 的描述性内容;与本文冲突的实现一律视为错误。 --- ## 1. 使用形态(硬规则) | 项 | 约定 | |---|---| | 交付物 | **pip 包**,被已有的 FastAPI 项目 `include_router` 引用 | | 不做的事 | **不提供独立 HTTP 服务**,不带 `uvicorn` 启动入口,不假设自己是独立进程 | | FastAPI 位置 | 只出现在 `adapter_python_pg/api/`,是 **optional extra**;核心包禁止 import fastapi | | 宿主感知边界 | 宿主看不到 SQL / Cypher,只拿到实体对象与语义方法 | | 契约来源 | 本体 YAML 是唯一事实来源;**只加载 YAML 即可工作**,不做代码生成、不要求手写 DDL | 宿主项目的典型用法: ```python from fastapi import FastAPI from adapter_python_pg import Adapter, build_router adapter = Adapter.load("ontology/factory-twin.yaml", dsn=settings.pg_dsn) app = FastAPI() app.include_router(build_router(adapter), prefix="/ontology") ``` ## 2. 技术栈 | 层 | 选型 | 约束 | |---|---|---| | 语言 | Python **3.11+** | 与 `pricing-service`、`data-mould` 对齐 | | 包管理 | **uv**(`uv.lock` 入库) | 不用手工 venv + pip | | 构建 | hatchling | `src/` 布局,带 `py.typed` | | 驱动 | **psycopg 3**(async + `psycopg_pool`) | 不用 asyncpg、不用任何 ORM | | 图 | **自研 agtype 解析**(`graph/agtype.py`),注册 psycopg3 loader | 不用 PyPI 的 `apache-age-python`(0.0.7 依赖 psycopg2+antlr4);AGE master 的 psycopg3 驱动未发布 | | 对象 | **pydantic v2** + `create_model()` | 运行期按本体动态建类 | | 本体校验 | pydantic 模型 + 导出 JSON Schema | 本体先自查,schema 供其他语言消费 | | 表达式 | **SQL 下推** + **CEL**(`cel-python`) | 不自研表达式解析器,不 `eval` | | 批量写 | `COPY` 协议 | 时序吞吐量级差异 | | API | FastAPI `add_api_route()` 动态注册 | 泛化 OpenAPI,不做 codegen | | 测试 | pytest + pytest-asyncio + testcontainers | 集成测试连真库 | | 质量 | ruff(line-length 100, py311)+ mypy | 配置写在 `pyproject.toml` | 依赖分层:`[project.dependencies]` 只放核心(psycopg / age / pydantic / pyyaml / cel-python);fastapi 放 `[project.optional-dependencies].api`。 ## 3. 目录结构 ```text src/adapter_python_pg/ ├── ontology/ YAML 解析与校验(pydantic spec:entities/links/actions/functions/rules/constraints) ├── compiler/ 本体 → 存储映射:幂等 DDL、索引推导、版本记录 ├── storage/ psycopg 连接池、事务边界、动态 SQL 构建(标识符管控) ├── repository/ 实体读写、批量、部分更新、约束校验 ├── graph/ AGE 封装:建图、建边、遍历、路径 —— 转义与白名单集中在这里 ├── timeseries/ hypertable 读写、COPY 批量、聚合查询 ├── expr/ 表达式双轨:SQL 下推编译 + CEL 求值 ├── rules/ 派生链接(传递闭包)、派生属性、计算属性 ├── api/ FastAPI router 工厂(optional) └── errors.py 统一错误模型 ``` ## 4. 架构决策(已拍板,勿反复) 1. **异步优先 + 同步门面**:内部全 async;对同步调用方提供 `SyncAdapter` 薄包装,不复制实现。 2. **多本体并存**:文档落在 `docs.collection = "{ontology}.{entity}"`;每个本体一个 AGE graph;多本体之间不做跨本体 JOIN。 3. **先全 JSONB**:属性一律存 JSONB,`column: true`(属性提升为真实列)在 spec 里**预留字段但不实现**,等性能有真实压力再开。 4. **FastAPI 路由动态生成**:`entity` 作为路径参数,OpenAPI 是泛化 schema;**不做**逐实体 typed routes、不导出 OpenAPI 代码。 5. **发布方式**:先支持 `pip install git+ssh://git@gitlab.cnsjzn.com/donnyzhang/adapter_python_pg.git`;GitLab PyPI registry 后续再接。 6. **agtype 自己解析,不 vendor、不引包**:`graph/agtype.py` 用 `json.raw_decode` + 自定义数组扫描消费 `::vertex` / `::edge` / `::path` 后缀。理由——需要在解析层做自己的类型映射、错误归一与标识符校验,vendor 上游未发布代码等于把维护负担抄一份。测试样本必须是**从真实库抓的原文**。 ## 5. 硬规则(违反即回退) - **核心包禁止 `import fastapi` / `import uvicorn`**。跑 `python -c "import adapter_python_pg"` 不应拉起任何 web 依赖。 - **Cypher 禁止字符串拼接值**。所有进入 `cypher()` 的标识符走白名单、值走转义函数,集中在 `graph/`,并配独立的注入用例矩阵。 - **实体与图必须同事务**。一个实体既有 JSONB 行又有图节点,写入在一个事务内完成;禁止 repository 与 graph 各自 commit 造成半实体。 - **禁止 `eval` / `exec` / `importlib` 执行 YAML 内容**。表达式只允许两条路:编译成 SQL 下推,或交给 CEL 求值。 - **DDL 必须幂等**(`IF NOT EXISTS`);本体演进只做加法,破坏性变更不做自动迁移。 - **默认不建索引**。只有 `index: true` / `unique: true` 才建;GIN 不是默认项。 - **公共接口必须完整类型标注**;动态 pydantic 模型只出现在数据边界,不穿透内部函数签名。 - **不用 `print`**,用标准库 `logging`(库不配置 handler,由宿主决定)。 - **测试不得写真实业务库**;集成测试用 testcontainers 起的临时实例。 ## 6. 常用命令 ```bash uv sync --extra api # 安装(含 FastAPI 可选依赖) uv sync # 只装核心,验证"无 web 依赖"边界 uv run pytest # 全部测试 uv run pytest -m "not integration" # 只跑不连库的单元测试 uv run ruff check . && uv run ruff format --check . uv run mypy src ``` ## 7. 测试约定 | 层 | 做法 | |---|---| | 本体解析 / 编译 | 纯单元测试,断言生成的 SQL 字符串与索引清单 | | 仓储 / 图 / 时序 | 集成测试,testcontainers 起 `pg-multimodel:pg18-age-timescale` | | 注入防护 | 专门的用例矩阵:非法标识符、引号、`$$`、注释符、Unicode 绕过 | | 回归 | 每个 bug 先写失败用例(RED),再修(GREEN) | 集成测试镜像默认复用本机已构建的 `pg-multimodel:pg18-age-timescale`;CI 里改为拉 registry 里的预构建镜像,避免每次重新编译 AGE。 ## 8. 与其他仓库的关系 | 仓库 | 关系 | |---|---| | `E:\code\ueos\devops\devos\server-resources\postgres-multimodel` | 底层多模型 PostgreSQL 的 Dockerfile / compose / 初始化脚本 | | `ueos/backend` 的 `ontology` 模块(Java) | 概念同源(Action / Function / Query / 编排);**不共享代码**,接口语义对齐即可 | ## 9. 当前状态 v0.1 设计阶段:README 与本文已定契约,代码未开始。落地顺序见 README「路线」:本体解析 → 文档读写 → 图 → 时序 → 推理 → FastAPI 路由 → Actions。