refactor(spec)!: IDataDriver 的 query 参数改为 DriverQuery,对象名只写一遍 (#5181) - #6076
Draft
qq9340100 wants to merge 3 commits into
Draft
refactor(spec)!: IDataDriver 的 query 参数改为 DriverQuery,对象名只写一遍 (#5181)#6076qq9340100 wants to merge 3 commits into
qq9340100 wants to merge 3 commits into
Conversation
…bject'>) 第一实参已经是对象名,AST 再要一遍是纯冗余,也给了同一事实两处互相矛盾的余地。 消费端为此要么写两遍,要么 as any —— 后者把 where/orderBy 的类型检查一并关掉。 Refs #5181 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011M7UwH25Unfi73UHim7ajY
Refs #5181 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011M7UwH25Unfi73UHim7ajY
…adriver-query-omit-object
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 113 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
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 #5181
前提核实(先证,后写)
对着
origin/main逐条核过,issue 的前提成立:packages/spec/src/contracts/data-driver.ts的find/findOne/count/updateMany/deleteMany/explain六个方法都声明(object: string, query: QueryAST, …);packages/spec/src/data/query.zod.ts的BaseQuerySchema里object: z.string()是必填(无.optional())。对象名确实被要求写两遍。而且这份冗余上层已经在为它付账:
packages/objectql/src/engine.ts:4755把键序刻意写成{ ...query, object },并留了注释说明「spread-first 会让一个夹带的query.object覆盖掉已解析的名字,把 AST 的对象和真正查的表劈成两半」;packages/metadata-protocol/src/protocol.ts:5280用一条具名 400QUERY_OBJECT_MISMATCH拒绝两者不一致,注释写着「a mismatch is refused, never resolved by picking a winner」。改了什么
packages/spec/src/contracts/data-driver.ts:六个签名改用它。
packages/spec/src/data/query.zod.ts的BaseQuerySchema一个字没动 ——object在引擎与 hook 那一层是被读的(engine.ts 那条注释自己说了「every middleware and hook readingast.object」),改的只是驱动契约的参数类型。expand条目里的object同样保留:那里它命名的是关联对象,没有任何实参携带这个事实,不是冗余。Omit vs optional:按实测定案,不靠偏好
派单把这个取舍留作实现内决策,判据是「哪个让驱动实现与直接消费者的类型面最诚实、迁移面最小」。两条我都量了。
迁移面 —— 直接跑出来的,不是估的。 先按
Omit改,再跑全仓pnpm typecheck,让编译器把迁移面点出来:全仓迁移面 = 1 个文件 6 处,全部形如
driver.find(historyTableName, { object: historyTableName, … })—— 即 issue 描述的那个冗余本身。已在本 PR 里删掉那 6 个键。没有被点到的,比它被点到的更说明问题:
driver.find(object, ast, …)传的是一个QueryAST值,它具备DriverQuery要求的全部属性,多出来的那个在非新鲜字面量上 TypeScript 一律接受。被重新判定的只有写在调用点上的内联字面量 —— 也就是冗余本身。lifecycle-service.ts/packages/verify里那几处{ object, where }也没红:它们的接收者是具体驱动类而非IDataDriver,解析到的是类自己的签名。所以
Omit的迁移面实测是 6 行删除,optional 是 0 行。差距在这个量级上不构成取舍依据。诚实性 —— 这才是分野。 让
object转 optional,说的是「你可以传,可传可不传」。这句话是假的:它不是「有时被读」,而是从来不被读。实测:一个没有任何读者的可选键,正是 Prime Directive #10 点名的 declared ≠ enforced 形状,本仓为这一类专门养了一套退役 playbook。optional 还会让
driver.find('a', { object: 'b' })继续合法且静默 —— 而这恰好是引擎用键序、wire 层用 400 分别堵过的那个矛盾;在最底下这一层把门重新敞开,等于让上面两道防线守一个本可以不存在的洞。Omit则把它变成编译错误,错误信息直接点名(TS2353'object' does not exist in type 'DriverQuery'),是「让 AI 写的代码在创作期就错不了」那条轴上的结构性预防,而不是消费端容忍。结论:
Omit。 迁移面两者实测同量级(6 行 vs 0 行),诚实性上 optional 会新造一个无消费方的可选键 —— 所以按判据没有平局,不构成needs_decision。反向验证(方向先定,再跑)
两个方向都事先写下了预测,两次都对上:
A —— 只把六个签名退回
QueryAST,保留别名。 预测:绑到契约签名的那条 pin 变红(6 个位置各一条),而绑到别名的@ts-expect-error那几条保持绿(它们判的是DriverQuery,没动)。实跑:正是 6 条、且只在
perMethod那一行 —— 这条 pin 是特意加的:只判别名的话,「把某一个签名偷偷退回QueryAST、别名照留」会一路绿灯过去。B —— 保留签名,把别名塌成
= QueryAST。 预测:别名侧的 pin 也跟着红,且必然包含 TS2578(@ts-expect-error未被使用),总数严格多于 6。实跑 11 条,含:一处如实说明:本 PR 没有把
$like这类错误挡在类型层issue 正文(转录自已关闭的 #4860)称「cloud#1030 的
$like本可在类型层拦住」。实测不成立,写在这里而不是留给下一个读者去踩:FilterCondition的 TS 类型是开放索引签名([key: string]: any | …,因为任意字段名都是合法键),所以删掉 cast 恢复的是
orderBy(SortNode,#4721 起已封闭,direction拼法重新报错)、fields、limit、$and/$or/$not结构这几条;where里的未知$算子这一条从来没被打开过,它由校验层在运行时响亮拒收。测试里把这两半都固化成了断言,免得后人把这次修复读得比它实际做到的更大。已另立观察类单 #6074 记录。验证
pnpm typecheck --concurrency=2(全仓)pnpm --filter @objectstack/spec testpnpm --filter @objectstack/metadata testpnpm --filter @objectstack/objectql testpnpm --filter @objectstack/driver-memory testcheck:generatedgen:api-surface一处新增(+ DriverQuery (type),0 breaking),已重生成并提交check:nul-bytes/check:query-options-erasure/check:slot-lookup/check:engine-double-contract/check:driver-conformance顺带一提,
check:api-surface只看见新增的DriverQuery导出、看不见参数类型的收窄(它记录导出是否存在,不记录签名),所以 changeset 里的 FROM → TO 是这次破坏性变更唯一的下游载体。顺带记录(未在本 PR 修)
FilterCondition的索引签名让未知$算子永远不是类型错误 —— 「$like本可在类型层拦住」是实测不成立的 #6074(finding):FilterCondition索引签名让未知$算子永远不是类型错误 —— 上面那半的存档。find/count/…仍声明query: QueryAST,而调用方已可省略object—— 双变让它编译,但声明开始说谎 #6075(finding):五个驱动仍声明query: QueryAST/any,双变让它编译,但声明开始说谎。派单 ⛔ 不改 driver 代码,故单独立单。边界
⛔ 未动 cloud(其整批删 cast 归 cloud#1053 在本 PR 落地后处理)。⛔ 未动
data/query.zod.ts。⛔ 未动任何 driver 实现代码。Generated by Claude Code