Skip to Content

column line

column 用穩定 ref 管理 table schema。它的 spec 鏡像 ColumnCreate,唯一重要轉換是所有資源關係都使用 authored refs;伺服器在 plan/apply 時才解析為 table IDs 與 col_<hex> internal keys。

JSONL Line

{"kind":"column","table":"orders","ref":"customer","spec":{"name":"Customer","type":"link","target":"customers","cardinality":"one"}}

欄位契約

頂層對應 IacColumnLine:必填 kind: "column"、table、ref;state 可為 present/absent 且預設 present;renamed_from 可選;present 必須有 object spec,純 rename 可只提供 renamed_from,absent 不得帶 spec。IaC Pydantic model 把 spec 定義為 Dict[str, Any];下列精確欄位矩陣是後續 ColumnCreate 的契約。工作台先檢查可見的 ref graph,伺服器在持久化欄位前仍會套用完整 CRUD model。

spec 鏡像 ColumnCreate 的 authored 欄位:

欄位必填精確契約
name是column display name
type是string、integer、float、decimal、boolean、date、datetime、text、select、multi_select、interval、link、rollup、lookup、formula、attachment、json、principal、principal_list、user、social_client 或 coordinate
required否boolean,預設 false;computed types 禁止 true
default_value否string、integer、float、boolean 或 null;computed types 禁止非 null。decimal 的預設值必須是 decimal 字串,例如 "0.00",並會依欄位的 scale 正規化
max_length否integer 或 null,只適用 string/text;computed types 禁止非 null
description否string 或 null
options否string 陣列或 null,只適用 select/multi_select
sequence否由伺服器指派的 string 選項;見編號序列。REST column 在最外層宣告 sequence,IaC 則宣告 spec.sequence
precision條件式僅限 decimal,且在該型別為必填:1–38 的整數,代表最大有效位數
scale條件式僅限 decimal,且在該型別為必填:0 到 min(18, precision) 的整數,代表固定的小數位數
allow_negative條件式僅限 decimal,且在該型別為必填:boolean
unit否僅儲存 decimal:{kind, fixed} 或 {kind, unit_column}。IaC 轉譯 selector column ref,計算值單位依來源推導。值為 null 的 key 會在比較前被丟掉,所以 {"kind":"currency","fixed":"TWD","unit_column":null} 與 {"kind":"currency","fixed":"TWD"} 是同一個單位,規劃結果為 noop。見decimal 單位
coordinate_system、axes、length_unit、capture條件式僅限 coordinate,傳遞到 ColumnCreate 契約,其中 length_unit.unit_column 會被翻譯成本表的欄位 ref;見座標設定與 IaC 邊界。這四個欄位也可以更新,並計入重量級欄位變更的分流判斷
target條件式link 的目標 table ref;取代 REST target_table_id
cardinality否link 的 "one" 或 "many";省略時 many
link_field條件式outgoing rollup/lookup 所依賴的本 table link-column ref
aggregation條件式rollup 的 count、count_distinct、sum、avg、min 或 max
target_column條件式rollup/lookup 的目標 column ref;count rollup 禁止提供
direction否rollup 的 outgoing 或 incoming;預設 outgoing
source條件式incoming rollup 的來源 table ref;取代 REST source_table_id
match條件式incoming rollup 的 {source-column-ref: own-column-ref-or-$self},1–3 組
filter否最多 10 個 predicate;其中 column 是聚合側 column ref
expression條件式formula expression;欄位 token 必須是可解析 refs
formula_version否僅 FORMULA:1(省略時預設)或 2,請見公式 v2
computation_mode否僅 FORMULA:live(預設)或 stored;stored 要求 v2 及支援的同列相依
pick否Picked-lookup 的 argmax 選擇器 {order_column, direction, as_of?};僅限 LOOKUP
fallback否僅限 LOOKUP:{table, match, target_column} 形式的預設表 fallback。table 是 table ref,取代 REST 的 table_id;match(1–2 組)的 key 與 target_column 是該預設表上的 ref;$row.<ref> 形式的 match 值指向本表的欄位
result_scale條件式僅限對 decimal(或 decimal formula)欄位做 avg 的 rollup,且在該情況為必填:0–18 的整數,代表輸出 scale
rounding_mode條件式與 result_scale 一起提供:half_even、half_up、down、floor 或 ceiling

型別間條件矩陣仍由 ColumnCreate 驗證:link 需要 target;outgoing rollup 需要 link_field/aggregation;incoming rollup 需要 source/match/aggregation;lookup 需要 link_field/target_column;formula 需要 expression。不屬於該 type 的 computed config 會被拒絕;attachment 禁止 default_value、max_length、options 與 computed config。decimal 必須提供 precision、scale 與 allow_negative,禁止 max_length 與 options,而且只有它可以帶這三個欄位;plan 會在該行以 validate-phase 錯誤回報違規(見 decimal 欄位)。

decimal 值永遠是正規形式的 JSON 字串——scale 為 2 時寫成 "12.50"——絕不是 JSON 數字,因為 decimal 輸入永遠不接受二進位浮點數。Record 行與 default_value 遵循同樣規則;export 會原樣輸出 precision、scale、allow_negative、result_scale 與 rounding_mode。

其中四個型別的行為差異大到值得特別說明。json 被排除在 rollup、lookup、formula、row-policy 與 SCP predicate,以及 unique 與 match key 之外——它與 interval 都永遠不能當 record 自然鍵。principal、user 與 social_client 是 principal 欄位:cell 是單一字串,各處一律只支援等值比較,永遠不可排序。user/social_client 的 cell 是原始 ID,在 record 行中接受可攜身分 token;principal 的 cell 是帶標籤的 user:<id>/smc:<id>/room:<id> 字串,接受 $user:、$smc: 與 $room: token,且解析結果正是該帶標籤形式。三者都可以當自然鍵。

pick(Picked Lookup)

pick 會以連結目標表上某個可排序的儲存欄位對被連結的列排名並取第一筆,讓 lookup 具備 argmax 選擇能力:

子鍵契約
order_column透過 link_field 在連結目標表上解析的 column ref,與 target_column 相同;型別必須是 integer、float、decimal、date 或 datetime
direction"asc" 或 "desc"
as_of選填 "$row.<來源欄位 ref>";來源資料表的 date/datetime 截止值,型別必須與 order_column 相同

pick 內禁止額外子鍵。缺少 link_field 時無法決定它所屬的資料表,翻譯會以下列訊息失敗——create line 在 apply 時失敗,更新 live 欄位的 line 則在 plan 時失敗(見驗證錯誤):

pick.order_column requires link_field (picked lookup) to resolve its owning table

編號序列屬性

序列仍使用 type: "string"。IaC 的 spec.sequence 必填 series 與 pattern;scope_columns 預設 [](最多兩個)、reset 預設 never、gap_policy 預設 gapless。pattern.width 必填(嚴格整數 1–12);prefix、date_format 與 separator 預設空字串,pattern.date_column 只有日期部分或 reset 需要它時才必填。日期與 scope 欄位 ref 屬於本表,會翻譯為內部鍵。Record 行不能自行提供序列值。已使用的設定及相依項目刪除會有 typed ct.sequence_* 拒絕;plan 不代表可重新編號既有資料列。公司業務時區 透過 REST 設定,沒有新的 IaC calendar line kind。

{"kind":"column","table":"invoices","ref":"number","spec":{"name":"Number","type":"string","sequence":{"series":"invoice","pattern":{"prefix":"INV-","width":6}}}}

Ref 與身分規則

table、ref、renamed_from、target、source 及欄位 refs 都使用 authored pattern ^[a-z0-9][a-z0-9_-]{0,63}$。table: "orders" + ref: "customer" 的 qualified identity 是 orders.customer。

Column、rule、trigger、view 與 public_read refs,加上固定的 client_access identity,在同一 table 共用 qualified-ref namespace。因此 column orders.status 會和 view orders.status 或 public-read token ref orders.status 碰撞;authored 成 orders.client_access 的 child 也會和單例 client-access resource 碰撞。文件宣告優先於既有 state;所有跨 ref 失敗時 fail closed,不能用 display name 或 col_<hex> 猜測。

target_column 的解析 table 取決於 link/rollup/lookup 方向;match 兩側、filter predicate 與 formula tokens 也依其語意解析。Export 會將 live internal keys反向翻成 refs。

column 行引用的每一張表格,也必須是你有權讀取的表格。Plan 與 apply 對 target、source 以及 lookup 的 fallback.table 一視同仁地授權;自 backend 5.21.0 起,這也涵蓋 spec 中以 raw id(target_table_id 或 source_table_id)指定的表格,以及先前沒有檢查的 fallback.table。Raw id 必須解析成你公司的一張 live 表格、是從該行所在 scope 出發的合法 link target(同一 scope,或包含它的部門或公司),而且你讀得到。不存在、屬於其他公司、超出該 scope 可及範圍或讀不到的 id,會得到與讀不到的 ref 相同的 403 與 code: "iac_permission_denied",所以回應不會透露是哪一種情況(見文件層級的狀態碼)。

生命週期與規劃

Present column 可規劃 create、adopt、move、update 或 noop;state: "absent" 規劃 delete。Spec-less present 只有 renamed_from 純 rename 合法。Plan 先審查 ref/diff 與可見的 live dependency;完整 ColumnCreate/ColumnUpdate model 仍可能在 apply 持久化前回傳 per-line error。

對 live 記錄超過 10,000 筆(刪除欄位時已進垃圾桶的記錄也計入)的既有表格新增或刪除欄位,或變更欄位型別,會透過 ticket 而不是在 request 內套用,整份文件回 202;完整清單與 worker=legacy 規則見重量級欄位變更。

在 company 或 department 文件中,absent 的 column 行也是被中斷的刪除得以收斂的方式。若欄位已離開表格的 schema,但它的 cell 或 state row 還在,plan 會規劃 delete 並附 warning;apply 會在表格鎖之下,從每一筆記錄(包含已進垃圾桶的)移除該欄位剩餘的 cell,再移除 state row;仍在 schema 中的欄位絕不會被這樣清掃。若 state row 指向的表格已不存在、或已被同一 ref 下的另一張表格取代,plan 則在該行規劃 orphaned,而且什麼都不改:原表格的 cell 會保留,直到營運人員清理或 purge 那張表格。

Computed config 一旦上線就不可變

在已存在的 link、rollup、lookup 或 formula 欄位上,只有 name 與 description 可以更新。任何其他變更——target、source、link_field、target_column、match、expression、filter、pick——現在都會在 plan 階段讓該行失敗:

only name/description can be updated on lookup columns (got: pick, target_column); to change computed config delete and recreate the column (state: absent + new line)

這是新行為,而且它是修正正確性,而不是新增限制。過去這類變更會規劃成 update,被 executor 的更新欄位過濾器靜默丟棄,可是 state 卻記下了新的 spec、該行也回報 applied: true——因此像是翻轉 picked lookup 的 pick.direction,看起來套用了,實際上沒有。

唯一忠實的做法是 state: "absent" 加上一行新的。請對審查者明說代價:這會以新的內部 key 重建欄位,並失去該欄位的資料。

機制上的原因是:IaC 的 update 或 move 只會把 name、type、required、default_value、max_length、description、options、precision、scale、allow_negative、unit 與四個座標欄位送給 CRUD。欄位 spec 中其他所有東西都只在建立時有效——這也代表 select 欄位的 options 確實可以更新。

三個 decimal 欄位可以更新,但只能在欄位更新端點允許的範圍內。所有 live 與已刪除(trash)的 cell 都會先預檢,並在同一個 schema transaction 中精確改寫,上限 10,000 筆 record;scale 調降只能去掉值為零的小數位;在已有 record 的表格上把欄位轉型為 decimal,或把 decimal 欄位轉成其他型別,一律拒絕。見欄位更新與轉型。

這是 diff 階段錯誤,因此 apply 回傳 200 且只略過那一行,而不是拒絕整份文件。

IaC state 只擁有 declared spec fields。Display name 改變不改 ref;若要改 ref,使用 renamed_from,不要建立另一欄再刪除原欄;搬移相關錯誤列在 claim 與搬移錯誤。

驗證錯誤

Child lifecycle 與 parent/qualified ref 的精確 detail:

state=absent lines carry no spec (table lines are the sole adopt-then-delete exception) state=present lines require a spec (unless a pure rename via renamed_from) unknown table ref 'orders' duplicate ref 'orders.customer' (already declared in this document)

Computed ref 會依欄位位置加入 context。這些都是 validate 階段錯誤,無法解析的 formula 也是:

unknown table ref 'customers' (target) unknown table ref 'events' (source) unknown column ref 'orders.customer' (link_field) unknown column ref 'customers.email' (target_column) unknown column ref 'customers.placed_at' (pick.order_column) unknown column ref 'events.order_no' (match) unknown column ref 'orders.order_no' (filter) unknown column ref 'orders.total' (expression) unknown table ref 'price_defaults' (fallback.table) unknown column ref 'price_defaults.price' (fallback.target_column) unknown column ref 'price_defaults.sku' (fallback.match) invalid formula expression: <detail> column 'customers.email' resolves to a legacy (non-col_-prefixed) internal key; not addressable by IaC formula translation

最後一則會拒絕這樣的 formula:它的 [link -> target] hop 落在一個被 adopt、內部 key 不以 col_ 開頭的欄位上。

Computed config 不可變是 diff 階段的 plan 錯誤。結構檢查在翻譯該行 ref 時執行:更新 live 欄位的 line 在 plan 時翻譯,訊息以 unresolved ref '{token}': {reason} 掛在該行 action 的 errors;create line 在 apply 時翻譯,失敗時為 line {n}: unresolved ref '{token}': {reason}:

only name/description can be updated on <link|rollup|lookup|formula> columns (got: <fields>); to change computed config delete and recreate the column (state: absent + new line) unresolved ref '<token>': pick.order_column requires link_field (picked lookup) to resolve its owning table

其他 {reason}——target_column、match、filter 與 fallback 的形狀規則,以及 formula 的各種形式——列在錯誤目錄的 Computed 欄位。Formula 內使用的 column ref 不可以 col_ 開頭:這個前綴保留給翻譯寫入的內部 key。

前兩則 lifecycle 訊息來自丟出一般 ValueError 的 validator。plan 與 apply 都以 parse 階段的 400 回應,帶 loc 為 ["column"] 的 typed value_error issue(見 Validator 訊息類別),工作台顯示相同的 detail。ColumnCreate 型別矩陣不會在 plan 時檢查:它在 apply 寫入欄位時執行,違反時只有該行失敗。精確 detail 來源:components/iac/parse.ts。

動手試試

在 IaC 工作台建立 customers、orders 與上面的 link column,再把 target 改成未知 ref。修正後執行 server plan,確認 target 最終解析到預期 table,而不是同名 display name。

Picked lookup cutoff 參照

pick.as_of 是選用的 "$row.<來源 date/datetime column ref>",來源型別必須與 link 目標的 pick.order_column 相同。此欄位不是額外的未知 sub-key;plan/apply/export 會解析並保留 ref。它篩選目前 linked rows,不重建歷史;lookup 設定建立後仍不可變更。另見歷史讀取。

Last updated on