Skip to Content

record line

record 是依 natural key 比對的 seed/upsert line。它讓可重建的基礎資料跟系統宣告一起搬移,但刻意不寫 IaC state,也不支援刪除資料列。

JSONL Line

{"kind":"record","table":"orders","data":{"order_no":"A-100","status":"open","customer":["C-200"]},"on_drift":"skip"}

欄位契約

欄位必填精確契約
kind固定 "record"
tabletarget table ref
data非空 object;keys 全是該 table column refs
on_drift"skip""update",預設 "skip"

沒有 refspecstaterenamed_fromdata values 仍遵守 column types。Link cell 使用目標 table natural-key values 的陣列;解析會延後到所有 records 可用後進行,因此可以指向同一文件稍後宣告的 target row。

Ref 與身分規則

Record 沒有持久 IaC ref;工作台只用 {table}.record:{physical-line} 顯示該輸入行。真正 identity 是 table natural key 的值。Key 先取 table spec.key 的 column ref;若省略,使用第一個 declared non-computed column。Server state 中既有 table/key refs 也可在 real plan 解析,但無 I/O 的工作台看不見它們。

data keys 必須是 authored column refs,不是 display names 或 col_<hex>。Natural key 必須包含值,不能是 booleanjsoninterval 欄位,且在文件新 keys 與 live table 中都必須唯一。Principal(principalusersocial_client)欄位可以當自然鍵,因為 principal cell 就是一個純量字串。

Principal cell 接受身分 token

usersocial_clientprincipal 欄位的 cell 都可以填可攜身分 token 取代原始 ID——user 欄位填 $user:<username>social_client 欄位填 $smc:<platform>:<platform_user_id>principal 欄位可填 $user:$smc:$room:<聊天室名稱>(裸名重複時改用限定形式 $room:<部門名稱>/<聊天室名稱>)。Export 會輸出這些 token,這正是讓「指名人員與聊天室的種子資料」能跨安裝搬移的關鍵。

principal cell 存的是它的文法要求的帶標籤形式,所以 token 會解析成 user:<id>smc:<id>room:<id>——標籤就是 token 前綴去掉 $$dept: 沒有對應的帶標籤 cell 形式,因此仍然只用於 grant:放進任何 cell 都是逐行的 kind 錯誤,principal token '$dept:Sales' does not match the column's type: a principal column expects $user:<...> or $smc:<...> or $room:<...> or a raw id。原始帶標籤 cell 仍然原樣接受,作為同環境的捷徑。

解析限定租戶,並在 record 分類之前逐 cell fail-closed:找不到或已刪除的使用者、活躍於多個聊天室的 social client,以及找不到或名稱模稜兩可的聊天室,每一種都是逐 cell 錯誤,絕不會靜默取第一筆。principal 型別的 cell 裡任何以 $ 開頭的值都會被當成 token,所以格式錯誤的那一個會回報自己的錯誤,而不是以假的原始 ID 流到寫入閘門。任何不以 $ 開頭的字串會原樣通過——usersocial_client 欄位是原始 ID,principal 欄位是原始帶標籤 cell——同環境往返合法,但若打算搬到別處就不建議。

當目標表的自然鍵本身是 usersocial_clientprincipal 欄位時,link cell 也一樣:export 會把自然鍵清單 token 化,plan 與 apply 都透過同一個共用 helper 解析。自然鍵是 principal 型別時,替換後用來查詢的值是帶標籤 cell——正是目標列實際儲存的值——所以 plan、apply 與 export 三方一致,重新匯出仍然 plan 出 0 差異。解析失敗的 token 會被排除在批次查詢之外,因此只會浮現解析器自己的錯誤,不會再多一則 no row … with key value '$room:…'

生命週期與規劃

找不到相同 natural key 時 action 是 insert。找到後:declared cells 相同為 skip;不同時 on_drift: "skip" 保留 live row並回傳 warning,on_drift: "update" 規劃更新 declared cells。未宣告 cells 保留。

Record 不寫 state,重複 apply 依 key 收斂為 skip。IaC 不提供 record deletion;資料刪除必須走 records API 與它自己的授權/稽核流程。

驗證錯誤

空 data 的 byte-exact parse detail:

[{"type": "too_short", "loc": ["record", "data"], "msg": "Dictionary should have at least 1 item after validation, not 0", "ctx": {"field_type": "Dictionary", "min_length": 1, "actual_length": 0}, "url": "https://errors.pydantic.dev/2.12/v/too_short"}]

本機 ref/key validation:

table 'orders' has no resolvable key column for record matching key column 'active' is a boolean column and cannot be a natural key (a two-value domain cannot uniquely match records) key column 'payload' is a json column and cannot be a natural key (json values have no canonical bind representation and cannot uniquely match records) unknown column ref 'missing' in record.data

json 那一則是同一則泛化訊息較新的一半,而且很重要:否則第一個 json 欄位會被選成位置預設 key,讓每次 apply 都重新插入所有種子列。預設 key 選擇器因此會跳過 json 欄位。

身分 token 的失敗以 cell 為單位回報——完整目錄請見可攜身分 token

principal token '$user:bob': no user with username 'bob' in this company principal token '$smc:line:U123': ambiguous — 2 social clients match, in chatrooms ['<id-a>', '<id-b>'] principal token '$room:Support': ambiguous — 2 live chatrooms are named 'Support' (['<id-a>', '<id-b>']); qualify it as '$room:<department name>/Support' principal token '$smc:line:U123' does not match the column's type: a user column expects $user:<...> or a raw id principal token '$dept:Sales' does not match the column's type: a principal column expects $user:<...> or $smc:<...> or $room:<...> or a raw id

若某一行 record 用到的 principal 欄位是在同一份文件較早處宣告、尚未建立的欄位,plan 階段無法分類它。該行會 plan 成 insert、沒有錯誤,只帶一則 warning——record classification deferred to apply (references a same-doc column not yet created)——而且 applyable 維持 true。Executor 會自己重跑一次替換,所以那個欄位上壞掉的 token 改在 apply 階段浮現:回應是 200,出錯的那一行回報 applied: falseprincipal column '<internal key>': <同一則訊息>(用的是內部 key,不是顯示名稱),文件層級的 errors[] 帶同一則 detail 並標記 phase: "apply",而同一個新欄位上的其他行仍然會套用。

Server plan 看見 live rows 後還可能回傳:

record data missing required key column value ('col_a1b2c3') duplicate key value 'A-100': 2 record lines in this document declare the same new key ambiguous key value 'A-100': 2 live records match

精確本機 detail 來源:components/iac/parse.ts。Live duplicate/ambiguity 與身分 token 解析只能由 server plan 判定。

動手試試

IaC 工作台宣告 ordersorder_no 與範例 record,先刪除 table key 與所有可用 columns 觀察 key error,再恢復。對測試 scope plan/apply 後重新 plan,確認 record action 收斂為 skip

Last updated on