Skip to content

HookContext.input 的契约注释声明批量写携带 input.ast,引擎从不设置它(AST 只在 opCtx 上);同一张表也未描述 #5038 后 after 事件的按行形状 #5273

Description

@os-zhuang

#5038(批量写按行语义)实现过程中发现,PD #10 单独记录。落在 packages/spec/**(spec 车道所有),#5038 未触碰该文件。

事实(对 origin/main 核实)

packages/spec/src/data/hook.zod.tsHookContext.input 的契约注释逐条列出每种操作的 input 形状:

   - find (also fires for findOne): { ast: QueryAST, options: DriverOptions }
   - insert: { doc: Record, options: DriverOptions }
   - update (single id): { id: ID, data: Record, options: DriverOptions }
   - update (bulk, multi:true): { ast: QueryAST, data: Record, options: DriverOptions }
   - delete (single id): { id: ID, options: DriverOptions }
   - delete (bulk, multi:true): { ast: QueryAST, options: DriverOptions }

并在下方重申「the row-scoping predicate is carried in input.ast」。

packages/objectql/src/engine.tsinput: { ast: ... } 只出现两处,都是读路径(beforeFind / afterFind)。写路径构造的是:

  • update():input: { id, data: opCtx.data, options: opCtx.options }
  • delete():input: { id, options: opCtx.options }

批量分支消费的 AST 是 opCtx.ast(#2982 为让中间件合成的行级过滤真正绑定 driver 而设的那条缝),它从不进 hookContext.input。所以照契约写 ctx.input.ast 的 hook 作者在批量写上拿到的是 undefined —— 而这恰恰是注释点名让人去读的那个字段。

hook-wrappers.tsinstallFlatInputast 当作 wrapper key 特判(不下放到 data),说明这个形状曾被当真过;今天在写路径上它是一个没有生产者的消费口。

第二处漂移(#5038 之后)

同一张表把 update (bulk, multi:true) 描述为单一形状。#5038 落地后,批量写的 after 型事件按匹配行派发,每行的 input单记录形状({ id, data, options });仍然整批触发一次的只有 before*。下方那句「A bulk (multi: true) update/delete fires the SAME beforeUpdate/beforeDelete events as a single-id write」本身仍然成立(它只谈 before),但这张表读起来会让人以为 after 事件在批量写上也没有 per-row id

Zod 契约本身不受影响 —— inputz.record(z.string(), z.unknown()),开放形状,#5038 因此无需改 spec 即可实现按行语义(这一点已在 PR #5270 里核实过)。纯属注释与实现的漂移,不是 schema 变更。

分级说明

finding:今天没有用户会撞上它——写路径 hook 作者拿 AST 的实际写法是 ctx.input.options / 引擎内部,仓内没有任何 ctx.input.ast 的写路径消费者(已 grep 确认)。但它是一条明确写下来、却从未兑现的契约陈述,正是 ADR-0049 「declared = enforced」路线要清掉的那一类;而且它会主动误导下一个照文档写 hook 的人(含 AI 作者)。

建议

由 spec 车道一次改掉两处:把批量写的 input 描述改成引擎实际给的形状({ id?, data?, options },并说明 after 事件在批量写上按行携带 id),删掉「the row-scoping predicate is carried in input.ast」这句,或者反过来让引擎真的把 opCtx.ast 放进批量写的 input(后者要评估是否有人会改它 —— input 是 mutable 的,把安全过滤后的 AST 交给 hook 改写需要单独想清楚,因此倾向改注释而不是改引擎)。

关联

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions