Skip to content

[objectql] 字段 defaultValue 解析晚于 beforeInsert hook,派生字段 hook 读到 null #2703

Closed

Description

@baozhoutao

概述

字段 defaultValue(含 Field.user({defaultValue:'current_user'}))由运行时在用户 beforeInsert hook 之后才解析。于是「从被默认的字段派生第二个字段」的 hook,读到的是还未填充的 null。

定位

  • packages/objectql/src/engine.ts:2143 —— 执行 beforeInsert hook。
  • packages/objectql/src/engine.ts:2181 —— applyFieldDefaults(默认值解析)在其后。
    → hook 读到的目标字段仍为 null,依赖它派生的字段算错。

复现(概要)

sales_person: Field.user({ defaultValue: 'current_user' }),POST 不带 sales_person:结果行 sales_person 被正确回填,但 beforeInsert 里派生的 current_status 因当时读到 sales_person == null 而算成 unassigned。显式传 sales_person → hook 看得到 → 正确。

期望

把 defaultValue(尤其 current_user)解析提前到 beforeInsert hook 之前,让派生 hook 能看到默认值;或至少文档明确当前顺序。


来源(项目 dogfood):steedos-labs/os-tianshun-mtc#29 · 与 #31 同族(#31 为 defaultValue 三问汇总)

Activity

  1. baozhoutao commented on Jul 10, 2026

    @baozhoutao
    ContributorAuthor

    处理方式与依据

    已修复,PR #2748。

    根因确认

    engine.ts 的 insert() 里执行顺序颠倒:triggerHooks('beforeInsert') 先跑,applyFieldDefaults() 后跑 —— 派生 hook 读到未回填的 null。

    修法

    把 applyFieldDefaults(单条 + 批量)提前到 beforeInsert hook 之前,回填后数据喂给 hookContext.input.data。Hook 仍在默认值之后运行、可覆盖;applyAutonumbers/加密/校验维持在 hook 之后不变。

    为什么这是平台级正确的顺序(而非仅仅"能跑")

    关键区分:声明式默认值 ≠ 引擎生成值。成熟平台把二者插在 before-hook 两侧:

    • Salesforce:字段默认值(含 $User.Id,对应本仓库 current_user)在记录实例化时就填好,before trigger 的 Trigger.new 已带默认值;而 Auto-Number 在 save 阶段生成、before trigger 里取不到。→ 本 PR 的新顺序(默认值在前、autonumber 在后)与 Salesforce 完全一致。
    • ServiceNow:dictionary default 在 initialize() 时套用,before business rule 天然看得到默认值。
    • Rails / Django:模型层默认值在实例化时套用,before_create/pre_save 看得到;只有 DB 级 default 才滞后。

    多数派都是「声明式默认值先于 before 逻辑」。之前 ObjectQL「默认值晚于 before hook」才是异类,本 PR 把它挪回标准分层:默认值 → before hook → autonumber/加密 → 校验 → 持久化。

    一个预期内的语义翻转(breaking note)

    改后 beforeInsert hook 无法再区分「客户端没传字段」与「默认值填的字段」(对声明 defaultValue 的字段,总是看到已解析的默认值)。这与 Salesforce/ServiceNow 行为一致(before 逻辑看到的是已初始化记录),是本次修复的预期语义;依赖「字段 undefined = 客户端未传」分支的下游 hook 需改判。

    测试

    新增回归测试复刻 steedos-labs/os-tianshun-mtc#29;@objectstack/objectql 全量 63 文件 / 805 tests 全通过。

    后续(未包含在本 PR)

    1. 把这条执行顺序沉淀为公开契约(ADR / spec)—— 对齐本 issue「或至少文档明确顺序」的诉求。
    2. 核对 update 路径默认值处理是否遵循同样「声明式在前」原则,避免 insert/update 两套顺序。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions