Skip to content

os migrate plan/apply forever lists formula (virtual) fields as pending add_columns — the plan promises work apply can never do #3978

Description

@os-zhuang

在复现 #3955 时发现(与已关闭的 #3954 是同一家族、但方向相反的缺陷:#3954 是计划少报了 apply 会做的事,本条是计划多报了 apply 永远做不了的事)。

现象

对一个刚刚由 os migrate apply 完整创建、随后未做任何改动的数据库再次运行 os migrate plan(examples/app-crm,当前 main):

  New (additive — created when you apply)
    + crm_contact [add_columns: full_name]
    + crm_lead [add_columns: is_closed]
    + crm_opportunity [add_columns: expected_revenue, days_to_close]

  ℹ 0 table(s) to create, 4 column(s) to add

这四个字段全部是 Field.formula(...)(虚拟字段,读取时计算)。createColumnformula 直接 return(不物化任何列),所以这 4 个 "add_columns" 每次 plan 都会出现、每次 apply 都"执行"却什么也不发生,永远无法收敛。刚 apply 完立即再 plan,输出如上——操作者会以为 apply 没有生效。

根因

previewDeferredSchemaWork()(packages/plugins/driver-sql/src/sql-driver.ts)对已存在的表用

const declared = Object.keys(obj.fields ?? {});

与物理列做差集,没有把「不会物化的字段」排除掉。真正执行 DDL 的路径(initObjectscreateColumn)对 formula 是跳过的,两条路径对"哪些字段会变成列"的判断不一致——preview 报告的是 apply 永远不会做的工作。create_table 分支同理(列数把 formula 也计入)。

建议方向

preview 与 createColumn 共用同一个「会物化为列」的判定(至少排除 formula;若后续出现其他虚拟类型,应从单一来源导出),使 plan 报告的 additive 工作与 flush 实际执行的 DDL 恒等。可加一个回归测试:apply 后立即 plan,pendingSchemaWork 必须为空。

/cc #3954(同一 PendingSchemaWork 报告面;该条已把「preview 必须如实反映 apply」定为约束)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions