Skip to content

refactor(spec)!: IDataDriver 的 query 参数改为 DriverQuery,对象名只写一遍 (#5181) - #6076

Draft
qq9340100 wants to merge 3 commits into
mainfrom
claude/issue-5181-datadriver-query-omit-object
Draft

refactor(spec)!: IDataDriver 的 query 参数改为 DriverQuery,对象名只写一遍 (#5181)#6076
qq9340100 wants to merge 3 commits into
mainfrom
claude/issue-5181-datadriver-query-omit-object

Conversation

@qq9340100

Copy link
Copy Markdown
Collaborator

Fixes #5181

前提核实(先证,后写)

对着 origin/main 逐条核过,issue 的前提成立

  • packages/spec/src/contracts/data-driver.tsfind / findOne / count / updateMany / deleteMany / explain 六个方法都声明 (object: string, query: QueryAST, …)
  • packages/spec/src/data/query.zod.tsBaseQuerySchemaobject: z.string()必填(无 .optional())。

对象名确实被要求写两遍。而且这份冗余上层已经在为它付账:

  • packages/objectql/src/engine.ts:4755 把键序刻意写成 { ...query, object },并留了注释说明「spread-first 会让一个夹带的 query.object 覆盖掉已解析的名字,把 AST 的对象和真正查的表劈成两半」;
  • packages/metadata-protocol/src/protocol.ts:5280 用一条具名 400 QUERY_OBJECT_MISMATCH 拒绝两者不一致,注释写着「a mismatch is refused, never resolved by picking a winner」。

改了什么

packages/spec/src/contracts/data-driver.ts

export type DriverQuery = Omit< QueryAST, 'object' >;

六个签名改用它。packages/spec/src/data/query.zod.tsBaseQuerySchema 一个字没动 —— object 在引擎与 hook 那一层是被读的(engine.ts 那条注释自己说了「every middleware and hook reading ast.object」),改的只是驱动契约的参数类型expand 条目里的 object 同样保留:那里它命名的是关联对象,没有任何实参携带这个事实,不是冗余。

Omit vs optional:按实测定案,不靠偏好

派单把这个取舍留作实现内决策,判据是「哪个让驱动实现与直接消费者的类型面最诚实、迁移面最小」。两条我都量了。

迁移面 —— 直接跑出来的,不是估的。 先按 Omit 改,再跑全仓 pnpm typecheck,让编译器把迁移面点出来:

src/utils/history-cleanup.ts(129,13): error TS2353: Object literal may only specify known properties, and 'object' does not exist in type 'DriverQuery'.
src/utils/history-cleanup.ts(151,17): error TS2353: …
src/utils/history-cleanup.ts(195,48): error TS2353: …
src/utils/history-cleanup.ts(273,11): error TS2353: …
src/utils/history-cleanup.ts(281,11): error TS2353: …
src/utils/history-cleanup.ts(300,13): error TS2353: …

全仓迁移面 = 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,说的是「你可以传,可传可不传」。这句话是假的:它不是「有时被读」,而是从来不被读。实测:

grep -rn "query\.object" packages/drivers/*/src --include=*.ts   # 零命中

一个没有任何读者的可选键,正是 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,没动)。实跑:

src/contracts/data-driver.test.ts(185,12): error TS2322: Type 'string' is not assignable to type 'never'.
… 同行 6 个位置,共 6 条;其余 pin 无报错

正是 6 条、且只在 perMethod 那一行 —— 这条 pin 是特意加的:只判别名的话,「把某一个签名偷偷退回 QueryAST、别名照留」会一路绿灯过去。

B —— 保留签名,把别名塌成 = QueryAST 预测:别名侧的 pin 也跟着红,且必然包含 TS2578(@ts-expect-error 未被使用),总数严格多于 6。实跑 11 条,含:

src/contracts/data-driver.test.ts(203,7):  error TS2578: Unused '@ts-expect-error' directive.
src/contracts/data-driver.test.ts(193,13): error TS2322: Type '{ where: …; limit: number; }' is not assignable to type 'QueryAST'.

一处如实说明:本 PR 没有$like 这类错误挡在类型层

issue 正文(转录自已关闭的 #4860)称「cloud#1030 的 $like 本可在类型层拦住」。实测不成立,写在这里而不是留给下一个读者去踩:FilterCondition 的 TS 类型是开放索引签名([key: string]: any | …,因为任意字段名都是合法键),所以

const unknownOperator: DriverQuery = { where: { name: { $like: 'acme%' } } };   // 无 cast,tsc 绿

删掉 cast 恢复的是 orderBySortNode#4721 起已封闭,direction 拼法重新报错)、fieldslimit$and/$or/$not 结构这几条;where 里的未知 $ 算子这一条从来没被打开过,它由校验层在运行时响亮拒收。测试里把这两半都固化成了断言,免得后人把这次修复读得比它实际做到的更大。已另立观察类单 #6074 记录。

验证

结果
pnpm typecheck --concurrency=2(全仓) 125 successful, 125 total,exit 0
pnpm --filter @objectstack/spec test 325 files / 8316 passed
pnpm --filter @objectstack/metadata test 25 files / 508 passed
pnpm --filter @objectstack/objectql test 130 files / 2147 passed
pnpm --filter @objectstack/driver-memory test 17 files / 518 passed
check:generated gen:api-surface 一处新增(+ DriverQuery (type),0 breaking),已重生成并提交
check:nul-bytes / check:query-options-erasure / check:slot-lookup / check:engine-double-contract / check:driver-conformance 全 OK
ESLint(改动文件) 无输出

顺带一提,check:api-surface 只看见新增的 DriverQuery 导出、看不见参数类型的收窄(它记录导出是否存在,不记录签名),所以 changeset 里的 FROM → TO 是这次破坏性变更唯一的下游载体。

顺带记录(未在本 PR 修)

边界

⛔ 未动 cloud(其整批删 cast 归 cloud#1053 在本 PR 落地后处理)。⛔ 未动 data/query.zod.ts。⛔ 未动任何 driver 实现代码。


Generated by Claude Code

claude added 3 commits August 6, 2026 16:07
…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
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 6, 2026 5:44pm

Request Review

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/metadata, @objectstack/spec.

113 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata, packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via packages/metadata, @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/metadata, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/metadata, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/metadata-service.mdx (via @objectstack/metadata)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/metadata, @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/metadata, @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[spec] IDataDriver 的 query 参数要求 QueryAST.object 与第一实参重复 —— 下游被迫 as any(20 处实测),提议 Omit/optional 化

2 participants