Skip to content

schema 中的可选字段从 Optional 迁到 Option - #87

Merged
tiye merged 1 commit into
mainfrom
migrate/optional-to-option
Oct 29, 2026
Merged

tiye merged 1 commit into
mainfrom
migrate/optional-to-option

Conversation

@tiye

@tiye tiye commented Oct 29, 2026

Copy link
Copy Markdown
Member

Requested by Jon · project thread

改动

calcit 0.32 计划删除旧的 Optional<T>(calcit-lang/calcit#2233,calcit 0.33.0 里程碑)。本仓库 13 处命中全部在 app.schema 和一个测试的 hint 里,现在都改成 Option:

  • ClientStore 的 :user、:diary
  • ClientUser、User 的 :avatar
  • CursorPatch 的 :year / :month / :day
  • Diary 的 :date、:time,Page 的 :time
  • Router 的 :data,Session 的 :user-id

构造、updater 和视图都改为显式写 Option :some / Option :none,读取用 match / .unwrap-or / option:some?,这些字段上的 nil->option 都去掉了。改完后 calcit.cirru 中不再有 Optional。

兼容旧数据(需要重点看)

  • 存储文件:线上 storage.cirru 里是 nil(旧 map 或这次之前写出的 typed record)。它们在 typed 解析时会失败,走已有的 legacy 迁移流程(先备份再原子替换)。normalize-stored-struct 现在会丢掉值为 nil 的字段,于是解码得到 Option :none;原来的 :time 123 等值得到 Option :some。新增测试 migrates-typed-storage-written-with-nil-optionals 用这次之前的真实 typed 格式文本验证,normalizes-empty-legacy-records 也补了断言和迁移后 typed 往返。部署后第一次启动会触发一次迁移并生成 .legacy-backup.cirru。
  • 旧客户端 map 载荷:normalize-client-payload 同样丢掉 nil 字段。
  • websocket:Option 经过 format-cirru-edn / recollect 传到客户端后变成没有名义声明的 :some / :none 变体,0.31.0 的 decode-map-as 不认。normalize-wire-value 现在会丢掉 :none 条目、拆开 :some,再解码 ClientStore。新增 wire-option? 辅助函数。

测试

  • 新增 twig-container#optional-fields-round-trip-over-wire:服务端 twig → diff-twig → 文本 → 客户端 try-client-message,覆盖登录和未登录两种 store。
  • 新增 parse-client-op#preserves-optional-diary-fields-in-typed-payload。
  • 客户端 wire 测试的 raw map 按新的线上形状去掉了缺省字段;tests/credentials-host.mjs 的 fixture 同步更新,月份/年份按钮的断言改读 Option,并加了一段从 socket 收到 :some/:none 变体的检查。

本地验证(calcit 0.31.0,与 deps 钉的版本一致)

  • caps --ci、yarn install --immutable、caps verify --toolchain
  • fix --workflow strict --verify:passed,无 diagnostics
  • edit format 后无 diff
  • 默认入口和 server 入口 --check-only,以及两组 --ns 检查都通过
  • yarn test-boundaries 通过(server 入口 79 个测试 + JS 重放)
  • yarn compile-page + release-page 构建成功

另外用 0.32.1 试了一下:项目在升级到 0.32 前还有别的阻塞(比如 E_LEGACY_TYPE_SYNTAX),和这次改动无关。


Generated by Claude Code

calcit 0.32 schedules the legacy `Optional<T>` for removal
(calcit#2233). All 13 uses in app.schema now declare `Option`:
ClientStore :user/:diary, ClientUser and User :avatar, CursorPatch
fields, Diary :date/:time, Page :time, Router :data, Session :user-id.

Constructors, updaters and views write and read `Option` explicitly
instead of nil, so `nil->option` around these fields is gone.

Boundaries keep accepting older data:
- Stored databases that hold nil (legacy maps or typed records written
  before this change) fail the typed parse and go through the existing
  legacy migration; `normalize-stored-struct` now drops nil fields so
  they decode as `Option :none`.
- Legacy client map payloads drop nil fields the same way.
- Option values lose their nominal declaration on the websocket, so
  `normalize-wire-value` drops `:none` entries and unwraps `:some`
  before decoding the ClientStore.

New tests cover the server-to-client round trip, typed diary payloads,
and migration of nil-era storage; the JS boundary fixture now uses the
new wire shape and checks Option variants arriving over the socket.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bPdumddHcfQCCCVRuVyXS
@tiye tiye self-assigned this Oct 29, 2026
@tiye
tiye merged commit 7e1b8f2 into main Oct 29, 2026
1 check passed
@tiye
tiye deleted the migrate/optional-to-option branch October 29, 2026 12:40
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.

2 participants