返回正文目录

第十四章实操:在一个 QM 中关联两个 TM

2026-10-21,更正上一轮主题理解。当前第十四章讲 QM 内 model + joins 及聚合 relation,查询端只调用一个 QM 的普通 queryModel DSL。本轮未调用 Compose。

环境与模型

沿用 http://127.0.0.1:18067,Namespace chinook,命名 SQLite 数据源 chinook-sqlite。实际 Launcher 0.1.30 / CLI 0.1.25,API foggy-runtime-api/v1、schema 2026-06-06,本地 none-dev-test-only 匿名查询,无真实身份凭据。教学服务未重启,未升级发行包。

两个 TM 均复用:ChinookInvoiceModel、ChinookInvoiceLineModel。仅新增两个正式 QM:

原八个建模文件和数据库 SHA256 未变,当前主模型目录共十个文件校验、加载通过。上一轮新增客户目录仍保留为既有素材,本章不依赖客户 QM,不重复创建 TM。明细和账单的日期、金额定义沿用前章。

操作与公开入口

  1. 核对能力、数据源绑定、原账单与明细元数据。
  2. 编写两个 QM,models validate --models-dir lab/models 后 models refresh。
  3. 对两个 QM 分别 models describe,包括 format=markdown;自动生成说明的样本已保存,执行时仍实时获取。
  4. 每个普通 JSON payload 先 query validate <QM>,再 query explain <QM> 与 query execute <QM>。explain 是重新编译的解释证据,不冒充历史执行 trace;实际 execute 响应另外保留。
  5. 读取只读 SQLite 原行,用 Decimal 逐张账单、逐明细、逐客户独立核对。未复用引擎生成 SQL 当作预期。
  6. 两个临时测试 QM 用于空匹配 LEFT 与普通 INNER,完成后移除测试 Bundle 并刷新;原三类查询回归。

验证结果

用例 实际与独立基线
01 直接 JOIN 明细记录 447 行;按账单和明细 ID 排序逐行一致
02 直接 JOIN 后汇总 账单金额累计 4256.25,明细金额 477.53;count(invoiceId)=447,count_distinct=83,故意演示错误粒度的后果
03 聚合 JOIN 后逐账单 83 行,逐张账单金额与明细合计一致,数量与条数分别核对
04 聚合 JOIN 后总汇总 两侧各 477.53、83 张账单、447 条明细、数量 447
05 按客户再次汇总 47 位客户,两侧金额逐客户一致
06 无记录期间 1990 年范围返回空列表
07/08 首次页和第二页 每页 5 张账单,total=83,与完整结果对应位置一致
09 错误字段 FIELD_NOT_FOUND,phase=query.validate,提示 detailCount;未执行
10 右侧聚合无匹配 测试 QM 在聚合前 filterEq(trackId,-1),返回 83 张左侧账单,右侧字段被序列化省略,没有按零处理
11 普通 INNER JOIN 样例关联完整,返回相同的 447 条明细
聚合 relation 改 INNER 在 models.validate 明确拒绝:aggregate relation 首版仅支持 LEFT JOIN;未登记、未刷新、未查询该无效模型

10 项查询用例完成独立核对(含错误粒度演示),另有 1 项错误字段拒绝和 1 项不支持的模型组合拒绝。账单固定均额、明细总额/数量、十二个月汇总三项旧查询回归通过。浮点结果对 Decimal 基线容差小于 1e-9,正文展示两位小数。

所有查询都指定一个 QM。普通 groupBy 作用于对外 QM 的查询结果;relation 中的 groupBy 是预先写入 QM 的聚合规则,不能把两者混作同一步。

复跑与证据

已创建的模型保留在主目录;完整自动复跑包括校验刷新、普通查询、临时模型测试、清理与回归:

python -u .\lab\checks\run-chapter-14-qm-join.py

只核对保存的响应与独立原行:

python .\lab\checks\verify-chapter-14-qm-join.py

完整复跑不是正文第一步的“先不查询”。本次当前 Codex 会话确实执行了 CLI,未另开干净 Codex 会话仅用短提示词复现。未做 Text-to-SQL 重复生成对比。

查询与模型映射、验收摘要、直接关联实时 Markdown、聚合关联实时 Markdown。各请求按编号保存 validate、explain、execute,拒绝请求没有 execute。

与此前 Compose 记录的关系

上一轮错误地把本章写成多个 QM 动态组合,其执行证据真实,但不属于本章。已移入高级篇 Compose 素材;旧实操记录、旧查询、日志、模型和证据目录保持。#150/#151 分别是 Compose 校验和输入 limit 问题,不等同于当前 QM 建模 JOIN 的缺陷;本轮未关闭或修改其 GitHub 内容。

本轮只验证同源 SQLite、普通 LEFT/INNER 和聚合 LEFT;未覆盖任意多事实、其他数据库、复杂权限组合或完整关系 DSL。当前对外字段与权限由这个 QM 自身定义,不能把其他 QM 的策略视作自动继承。