feat(tsl-syntax-reference): harden retrieval contracts

Add stable section IDs, structural and routing regressions, quickstart consistency checks, and CI enforcement.

BREAKING CHANGE: replace heading-derived Section IDs with explicit syntax-NN-NNN identifiers.
This commit is contained in:
csh
2026-07-31 10:05:15 +08:00
parent 21e688a436
commit 736d1a8ad7
30 changed files with 1635 additions and 137 deletions
@@ -4,10 +4,14 @@
## 本篇职责
<!-- section-id: syntax-13-001 -->
回答“写 TS-SQL 查询和写回时,怎样从最小 `select ... from ... end` 骨架开始,逐步处理筛选、分组、排序、多表联接(含 LEFT JOIN)、组内子查询、极值引用,以及如何用 `insert`/`update`/`delete` 修改内存数组”。
## 核心规则
<!-- section-id: syntax-13-002 -->
- TS-SQL 是 TSL 自带的类 SQL 查询语法,不是金融业务函数库。
- 基础查询文档骨架是:以 `select` / `sselect` / `vselect` / `mselect` 开始,以 `end` 收尾。
- `from` 后面可以直接跟内存数组结果集。
@@ -29,8 +33,12 @@
## 可直接照写示例
<!-- section-id: syntax-13-003 -->
### 最小查询骨架
<!-- section-id: syntax-13-004 -->
<!-- tags: 怎么写查询, 最简 select, 查数组, 内存表查询 -->
代码块身份:可直接照写示例
@@ -58,6 +66,8 @@ writeLn(length(query_result));
### 字段选择
<!-- section-id: syntax-13-005 -->
<!-- tags: 选哪些列, 只取部分字段, 指定列, 输出字段 -->
代码块身份:可直接照写示例
@@ -80,6 +90,8 @@ writeLn(length(query_result));
### 四个查询入口怎样分工
<!-- section-id: syntax-13-006 -->
<!-- tags: select 和 sselect 区别, vselect, mselect, 返回什么形态, 该用哪个查询 -->
代码块身份:可直接照写示例
@@ -106,6 +118,8 @@ col_index := mcols(matrix_result, 1);
### `where` 和 `order by`
<!-- section-id: syntax-13-007 -->
<!-- tags: 条件筛选, 排序, 按某列排, 倒序, 只要满足条件的行 -->
代码块身份:可直接照写示例
@@ -127,6 +141,8 @@ query_result := select * from source_rows where ["B"] > 1 order by ["B"] end;
### `group by`
<!-- section-id: syntax-13-008 -->
<!-- tags: 分组, 汇总, 聚合统计, 按类别合计 -->
代码块身份:可直接照写示例
@@ -153,6 +169,8 @@ group_result := select ["A"], sumOf(["B"]) as "SumB"
### 一维数组上的 `thisRow` 与 `thisRowIndex`
<!-- section-id: syntax-13-009 -->
<!-- tags: 当前行, 当前行号, 一维数组查询 -->
代码块身份:可直接照写示例
@@ -176,6 +194,8 @@ query_result := select thisRow as "Value", thisRowIndex as "Idx"
### `join`
<!-- section-id: syntax-13-010 -->
<!-- tags: 两表关联, 表连接, 按键匹配, 拼接两张表 -->
代码块身份:可直接照写示例
@@ -215,6 +235,8 @@ writeLn(join_result[0]["V2"]);
### `thisGroup`
<!-- section-id: syntax-13-011 -->
<!-- tags: 组内数据, 分组明细, 取当前组 -->
代码块身份:可直接照写示例
@@ -242,6 +264,8 @@ group_result := select ["A"], max_b := maxOf(["B"]) as "MaxB",
### `thisRowIndex` 在排序后仍指向原始位置
<!-- section-id: syntax-13-012 -->
<!-- tags: 排序后原始行号, 原位置, 排序不改下标 -->
代码块身份:可直接照写示例
@@ -265,6 +289,8 @@ query_result := select thisRowIndex as "Idx", ["B"]
### `refMaxOf` 与 `refMinOf`
<!-- section-id: syntax-13-013 -->
<!-- tags: 取最大值那行, 取最小值对应字段, 谁最大, 极值行 -->
代码块身份:可直接照写示例
@@ -283,6 +309,8 @@ min_ref_result := select minOf([0]) as "MinA", refMinOf([1]) as "RefB" from sour
### `LEFT JOIN` 多表联接
<!-- section-id: syntax-13-014 -->
<!-- tags: 左连接, 左联接, 保留左表, 右边没有就空 -->
`left join` 保留左表所有行,右表不匹配时用 `nil` 填充:
@@ -322,6 +350,8 @@ writeLn("(1,1):", result[1]["vb"]);
### `right join` / `full join` / `cross join` 与逗号联接
<!-- section-id: syntax-13-015 -->
<!-- tags: 右连接, 全连接, 笛卡尔积, 交叉联接 -->
`right join` / `full join` 的不匹配行同样用 `nil` 填充:
@@ -423,6 +453,8 @@ writeLn("(0,0):", result[0]["id"]);
### `INSERT` 写回
<!-- section-id: syntax-13-016 -->
<!-- tags: 插入行, 新增记录, 往数组加数据 -->
`insert into` 向内存数组插入新行:
@@ -480,6 +512,8 @@ writeLn(a[2]["id"], a[2]["cls"]);
### `UPDATE` 写回
<!-- section-id: syntax-13-017 -->
<!-- tags: 更新行, 改字段值, 批量修改 -->
`update` 修改符合条件的行:
@@ -533,6 +567,8 @@ writeLn(r[0], r[1], r[2]);
### `DELETE` 写回
<!-- section-id: syntax-13-018 -->
<!-- tags: 删除行, 删掉记录, 按条件删 -->
`delete` 删除符合条件的行:
@@ -582,6 +618,8 @@ writeLn(mrows(a));
### `distinct` 结果集去重
<!-- section-id: syntax-13-019 -->
<!-- tags: 去重, 不要重复行, 唯一值 -->
`select distinct` 对结果集去重;聚集函数内也可用 `distinct` 前缀:
@@ -613,6 +651,8 @@ writeLn(plain_sum);
### `as` 别名、`as nil` 与字段区间
<!-- section-id: syntax-13-020 -->
<!-- tags: 改列名, 起别名, 丢弃字段, 字段区间 -->
代码块身份:可直接照写示例
@@ -643,6 +683,8 @@ writeLn(mcols(range_rows));
### `drange` 取行区间
<!-- section-id: syntax-13-021 -->
<!-- tags: 取前几行, 分页, 行区间, 只要一段 -->
代码块身份:可直接照写示例
@@ -672,6 +714,8 @@ writeLn(mrows(part_rows));
### `selectopt` 位选项
<!-- section-id: syntax-13-022 -->
<!-- tags: 查询选项, 返回形态控制, 位标志 -->
代码块身份:可直接照写示例
@@ -697,6 +741,8 @@ writeLn(opt_rows[0]);
### 条件聚集、移动聚集与 `refof`
<!-- section-id: syntax-13-023 -->
<!-- tags: 条件求和, 滑动窗口, 移动平均, 带条件的聚合 -->
聚集函数统一支持 `(Expr, BoolConditionExp, N, MovingFirst, CacheId)` 形态:
@@ -729,6 +775,8 @@ writeLn(ref_prev[1]["Expr1"]);
### `group by ... having`
<!-- section-id: syntax-13-024 -->
<!-- tags: 分组后筛选, 聚合条件, 组级过滤 -->
`having` 用聚集条件筛选分组(`where` 不能用聚集):
@@ -764,6 +812,8 @@ having_rows := select ["cls"] from a group by ["cls"] having countof(*) > 1 end;
### `thisOrder` 与多列 `order by`
<!-- section-id: syntax-13-025 -->
<!-- tags: 多列排序, 排名, 序号, 先按 A 再按 B -->
代码块身份:可直接照写示例
@@ -791,6 +841,8 @@ writeLn(desc_rows[0]["id"]);
### `refsof` 引用上级结果集
<!-- section-id: syntax-13-026 -->
<!-- tags: 子查询取外层, 嵌套查询, 引用上一层 -->
在嵌套子查询里,`refsof(Exp, UpLevel)` 用上 N 级结果集计算 `Exp`
@@ -818,6 +870,8 @@ writeLn(r[1]["id"], ",", r[1]["up"]);
### `[@Field]` 取字段类型
<!-- section-id: syntax-13-027 -->
<!-- tags: 字段类型, 列的数据类型 -->
代码块身份:可直接照写示例
@@ -840,6 +894,8 @@ integer
### `aggof` 自定义聚集扩展
<!-- section-id: syntax-13-028 -->
<!-- tags: 自定义聚合, 自己写聚集函数 -->
`aggof('名称', 表达式)` 调用一个自定义回调函数做聚集。本地 `TSL.exe` 会报 `AggOf Init Error`;下例在服务端(pyTSL)验证通过:
@@ -877,6 +933,8 @@ end;
## 本页不生成的范围
<!-- section-id: syntax-13-029 -->
- `TSQLInsert` / `TSQLSetValue` / `TSQLBatchInsert` / `TSQLEdit` / `TSQLPost` / `TSQLFinal` 对象被 TS-SQL 查询的回调机制
- 面向 SQL 表、业务表或时间序列的数据查询与写回(`marketTable` / `infoTable` / `tradeTable` / `sqlTable` / `hugeSqlTable` 等数据源)
@@ -884,6 +942,8 @@ end;
## 默认生成模板
<!-- section-id: syntax-13-030 -->
TS-SQL 的最短默认骨架如下:
代码块身份:可直接照写示例
@@ -895,6 +955,8 @@ query_result := select * from source_rows end;
## 禁止项
<!-- section-id: syntax-13-031 -->
- 不要把数据库 SQL 方言直接迁移成 TS-SQL 代码。
- 不要把 `select` 当成普通函数调用,忘了以 `end` 收尾。
- 在二维结果集里直接写 `A` 而不是 `["A"]`