ObjectOS
參考

CEL 表示式

用於公式、謂詞、排程和模板字串的表示式語言 —— 通過五個標籤模板暴露。

ObjectOS 在所有需要小型、安全、沙箱化表示式的地方使用 CEL(Common Expression Language):公式欄位、校驗規則、可見性謂詞、共享條件、流程守衛、排程和模板字串。

編寫通過從 @objectstack/spec 匯入的五個標籤模板完成。它們都生成一個由執行時解析的小型 JSON 物件:

{ dialect: 'cel' | 'template' | 'cron', source: string }

Schema 原始碼: packages/spec/src/shared/expression.zod.ts

五個標籤模板

模板Dialect用途示例
F`...`cel公式欄位 —— 與記錄一同儲存的派生值F`record.amount * 0.1`
P`...`cel謂詞 —— 用於校驗/共享/可見性/條件的布林值P`record.status == "open"`
cel`...`cel通用 CEL —— 當 F 或 P 都不合適時(例如引數值)cel`now() + duration("P30D")`
tmpl`...`template{{var}} 插值的字串模板tmpl`Order from {{record.customer.name}}`
cron`...`cron排程 —— 標準 5 欄位 cron 語法cron`0 9 * * 1-5`

FPcel 在求值時沒有功能差異 —— 它們都執行 CEL。區分的存在是為了讓 schema(和 AI Agent)知道表示式扮演什麼角色,並讓編輯器能進行型別檢查(公式必須返回值,謂詞必須返回 bool)。

匯入

import { F, P, cel, tmpl, cron } from '@objectstack/spec'

各自的使用位置

Spec 上的欄位標籤示例位置
Field.expression(formula 型別)F*.object.ts 公式欄位
Field.conditionalRequiredP物件欄位
Validation.predicateP物件校驗
SharingRule.conditionP共享規則
View.conditionalFormatting[].conditionP檢視
Flow.step.when / Flow.transition.whenP流程
Action.guardPAction
通知主題/訊息正文tmpl通知
Schedule.croncron排程流程/報表
任意值引數cel流程步驟輸入

變數作用域

CEL 表示式在帶有以下頂級變數的上下文中求值:

變數何時可用內容
record幾乎總是當前正在求值的記錄
previous更新 Hook/變更檢測記錄變更前的狀態(或 null
inputAction、流程步驟使用者提交的輸入載荷
os.user總是{ id, roles: string[], permissions: string[] }
os.org總是組織/租戶上下文
os.env總是暴露給表示式的環境變數

舊的 OLD / NEW 變數已在 M9.5 中移除。請使用 previousrecord

標準庫

註冊位置: packages/formula/src/stdlib.ts。 最常用的內建函式:

時間

函式返回說明
now()Timestamp釘在求值上下文 —— 單次查詢內穩定
today()TimestampUTC 當日開始
daysFromNow(int)Timestamp未來日期
daysAgo(int)Timestamp過去日期

CEL 還包含原生 timestamp(...)duration(...)date.getDayOfWeek() 等 —— 參見 CEL spec

工具

函式用途
isBlank(x)nullundefined"" 或空列表時為 true
coalesce(a, b)第一個非空值
trim(s)去除空白
joinNonEmpty(list, sep)拼接非空條目

原生 CEL 字串輔助函式(.contains(...).startsWith(...).matches(...).size())始終可用。

示例

公式欄位 —— 行專案合計:

{ name: 'subtotal', type: 'formula', expression: F`record.quantity * record.unit_price` }

校驗 —— 關閉日期必須在今日之後:

{ message: 'Close date must be in the future', predicate: P`record.close_date > today()` }

可見性 —— 僅向經理顯示欄位:

{ visibleIf: P`'manager' in os.user.roles` }

流程守衛 —— 金額小時跳過步驟:

{ when: P`record.amount >= 1000` }

排程 —— 工作日 9 點:

{ schedule: cron`0 9 * * 1-5` }

模板 —— 通知主題:

{ subject: tmpl`[{{record.priority}}] {{record.subject}}` }

錯誤

表示式在載入時編譯。失敗以帶原始碼位置的 VALIDATION_ERROR 呈現:

{ "code": "VALIDATION_ERROR", "message": "CEL: unknown field 'amout' on Record", "details": { "field": "subtotal", "expression": "record.amout * 0.1" } }

無效表示式不會靜默失敗。畸形或引用未知欄位的表示式會讓 os compile 失敗,並給出上面那條帶定位的訊息(對拼錯的欄位還包含 did-you-mean 提示)。執行時遇到壞表示式會丟擲一個帶歸屬資訊的錯誤,而不是靜默求值為 nullfalse,因此該失敗會在日誌和審計軌跡中可見,而不會悄悄汙染一個公式值或一個守衛判定。

參見

On this page