fix(driver-turso)!: remote 停止对聚合函数名做大小写归一化,两面只认协议声明的拼写 (#6203) - #6312
Merged
Conversation
…#6203) `TursoDriver` picks its face from `url`: a local/replica URL inherits `SqlDriver`, a remote one delegates to `RemoteTransport`. The two faces normalised the aggregate function name differently — the remote transport lowercased it before its lowering-table lookup, the local driver looked up whatever it was handed — so one driver answered one query two ways, decided by a connection string. Measured on origin/main @ d367f03: COUNT REMOTE -> RESOLVED "SELECT count(\"stage\") AS \"n\" FROM \"deal\"" LOCAL -> THREW INVALID_QUERY / 400 Count REMOTE -> RESOLVED (same) LOCAL -> THREW INVALID_QUERY / 400 Delete the `.toLowerCase()`. `AggregationFunction` is a case-sensitive `z.enum` (`AggregationFunction.parse('COUNT')` throws), so `COUNT` is a spelling the Query Protocol never declared: what the remote transport accepted was a private dialect, and PD#12 rejects widening a consumer to keep one alive. Teaching the local driver the same dialect would have fossilised it into a second de-facto contract instead. No new classification logic was needed. #5907 (PR #6204) already classifies on the CALLER's spelling, so with the lookup no longer normalising, `COUNT` falls straight onto class 1 — INVALID_QUERY / 400, "not a declared aggregate function" — the same envelope, in the same words, that the local driver has been giving it. The default alias is unchanged for every input that still compiles: only a name already in the lowering table reaches that line, and every key there is lowercase. Tests: the `[filed, not fixed]` control #5907 left here recording `COUNT` compiling on this face is flipped into a four-case local/remote parity block asserting code AND status AND first sentence (#6144), plus a control that the declared lowercase spelling still compiles on both faces. The aliasless fixture drops its miscased axis, which stopped being expressible. Reverse verification, direction predicted before running and recorded in the test docblock because the four cases do NOT move together: with the `toLowerCase()` restored, `COUNT`/`Count` go red on "but it compiled" (2/4), while `COUNT_DISTINCT`/`Median` stay green — lowercasing them still misses the lowering table and #5907 already judged them on the caller's spelling. Measured: exactly that, 2 failed / 806 passed. Both are kept: the insensitive pair is the standing guard on #5907's half of the same fork. driver-sql carries a comment-only correction — a docblock there described the remote transport's lowercasing as current fact. Fixes #6203 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WyvqvKMG6asi9aXjKE6xtx
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 12 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
August 7, 2026 13:38
os-zhuang
enabled auto-merge
August 7, 2026 13:38
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6203
缺陷
TursoDriver按连接串url选面:本地/副本继承SqlDriver,远程委派RemoteTransport。两面对聚合函数名的归一化不一致 —— remote 先.toLowerCase()再查自己的编译表,local 拿到什么查什么。于是同一个驱动、同一条查询,答案取决于连接串。在
origin/main@d367f03d6(已含 #6204 的信封与 #6210 的签名)实测:即 issue 的前提在最新
main上依然成立,且剩下的分叉正好收敛到「与某个已编译名字只差大小写」这一族。修法(裁决方向 1:收紧 remote)
删掉
RemoteTransport.aggregate()里的.toLowerCase(),查表键改为调用方写的原始拼写。AggregationFunction是大小写敏感的z.enum——AggregationFunction.parse('COUNT')直接抛错,这条已由packages/spec/src/data/query.test.ts钉住。所以COUNT是协议从未声明的拼写,remote 此前多认的是一种私有方言,属 PD#12 明确反对的宽容消费端;不需要新增任何分类逻辑,已确认。 #5907(PR #6204)已经把两面的分类改成按调用方原始拼写判定,所以查表不再归一化之后,
COUNT自然落进第 1 类INVALID_QUERY/ 400,措辞与 local 逐字相同。信封、措辞、降级表、#6210 的签名、条件层与 NULL/undefined 闸一律未动;driver-memory / driver-mongodb 零改动。默认 alias 的拼法对所有仍能编译的输入字节不变 —— 只有已在编译表里的名字才走到那一行,而表里每个键都是小写。
测试
Unsupported aggregate function两面都是裸Error(code/status 皆 undefined),且三个 spec 已声明的聚合函数无任何 SQL 后端编译 #5907 留下的[filed, not fixed] COUNT still compiles HERE …用例翻面成[#6203]parity 组:COUNT/Count/COUNT_DISTINCT/Median四条,断言两面同码同 status 同首句同全文,并断言消息回显的是调用方自己的字节。该用例钉的正是本次删掉的那条肢体,所以是整条替换而不是改拼写;count在两面依然照常编译(remote 出 SQL、local 返回行)—— 避免「靠全拒收也能满足 parity」;code与status([skill] 拒收类用例必须断言 code+status,不能只断言「它抛了」—— 否则在裸 Error 的驱动上恒绿(#6142 实测) #6144):local 侧四条在改动前后都会抛,只断言「它抛了」全程是绿的,对整个缺陷完全失明;反向验证(方向先判后跑,四条并不同向,如实记录)
把
.toLowerCase()放回去,预判:COUNT、CounttoLowerCase()搬动的全部人口COUNT_DISTINCT、Median实测与预判完全一致:
2 failed | 806 passed,两条失败均为expected the transport to refuse "COUNT"/"Count", but it compiled to [...]。两条不敏感的用例保留:这一族断言的是「任何大小写变体都不会因连接串拿到不同答案」,而它们是 #5907 那一半的常驻守卫 —— 归一化若从分类侧(而非查表侧)回来,只有它们看得见。
影响面 / 消费半径
function: 'COUNT'等零命中;service-analytics 的 measure 词汇本身就是小写 enum);AggregationNodeSchema就被拒,到不了驱动;验证
消费半径按
--filter '...pkg'(前缀=下游)清扫,未用后缀(#6218)。附:driver-sql 的注释订正(仅注释)
sql-driver.ts里undeclaredAggregateFunctionError的 docblock 把「remote transport lowercases it before its own lookup」写成了现状事实 —— 本 PR 之后不再成立。改为交代其历史并指出:大小写敏感的判定不是这条分叉的副产品,而是 enum 本身的语义。行为零改动,local 侧mapAggregateFunc的归一化行为未触碰。Generated by Claude Code