Skip to content

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

Merged
qq9340100 merged 6 commits into
mainfrom
claude/issue-5181-datadriver-query-omit-object
Aug 7, 2026
Merged

refactor(spec)!: IDataDriver 的 query 参数改为 DriverQuery,对象名只写一遍 (#5181)#6076
qq9340100 merged 6 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 7, 2026 1:58am

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.

claude added 2 commits August 7, 2026 00:44
…adriver-query-omit-object

# Conflicts:
#	packages/spec/api-surface.json
单体 api-surface.json 已在 main 删除,本次按 os-regen 纪律接受删除并整体重生成:
16 个分片只动 contracts.json 一行,即 #5837 承诺的 locality。

Refs #5181

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011M7UwH25Unfi73UHim7ajY
@qq9340100
qq9340100 marked this pull request as ready for review August 7, 2026 02:11
@qq9340100
qq9340100 added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit 6513c17 Aug 7, 2026
25 checks passed
@qq9340100
qq9340100 deleted the claude/issue-5181-datadriver-query-omit-object branch August 7, 2026 02:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

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