Statement 目录
最后更新:2026年7月23日
statements 数组的每个元素都是一个语句(statement)。本文整理了 17 种语句的字段、行为与结果。所有取值位置都遵循值表达式的规则(引用、字面量、JsonLogic、Locale 映射)。
语句概览
| 分类 | type | 一句话概要 |
|---|---|---|
| 资源写入 | ResourceCreate | 创建 Content/Media(可选择发布) |
ResourceUpdate | 整体替换 Content/Media 字段(未提供的 field·locale 会被删除) | |
ResourcePatch | 部分合并 Content/Media 字段(仅指定的 field·locale;字面量 null 表示删除) | |
ResourceDelete | 删除(仅 Draft·Archived;若为 Published 需先 unpublish) | |
ResourcePublish / ResourceUnpublish | 发布 / 取消发布 | |
ResourceArchive / ResourceUnarchive | 归档 / 取消归档 | |
| 资源读取 | ResourceRead | 按 id 单条查询 |
ResourceFind | 按过滤条件返回首个匹配的单条(无则为 null) | |
ResourcePageRead | 过滤/排序/分页查询({ items, next }) | |
| 外部 | Http | 外部 HTTP 调用({ status, body })。仅限 Async |
| 变量 | SetVar | 声明/更新 script 作用域变量 |
| 控制流 | If | 条件分支 |
Loop | 循环(foreach / while / counted) | |
Parallel | 分支并发执行 | |
Return | 返回结果并提前结束 | |
Try | 异常处理(catch/finally) |
循环调用最多 3 次。 上面的资源写入语句(
ResourceCreate、ResourceUpdate、ResourcePublish等)会触发变更事件,而这些事件可能通过 Webhook 再次运行 Script。这样的链条(Script → 事件 → Webhook → Script → …)最多只持续 3 次,超过后平台会自动中断以防止无限循环。
公共字段
{ "type": "<StatementType>", "name": "<可选,script 内唯一>", /* ...各类型专属字段... */ }type:判别符。取上表中的某个值(必填)。name:可选。指定后,结果会以/<name>绑定到上下文,后续 statement 可通过{ /<name>/... }引用。若不使用结果则可省略。- 绑定名称规则:
name(以及Loop的as)是直接叠加到上下文根上的键,因此在保存时会被校验。它不能为空字符串,不能包含/·~(须可用作 JSON Pointer 键),不能与保留根(payload·vars·error)相同,且在同一个 Script 内必须唯一。违反时会分别以WGL400033(格式)·WGL400032(保留字)·WGL400034(重复)拒绝保存。
实体引用形态
contentType、target 等实体引用统一为 { "sys": { "id": <值表达式> } } 一种形态。只需 sys.id,目标类型由 resource 推断(sys.type 与 sys.targetType 均省略)。
contentType.sys.id通常是字面量(例如"ct_post")。target.sys.id通常是{ /ptr }值表达式(运行时 resolve,例如{ /payload/sys/id })。
resource
资源类语句通过 resource: "Content" | "Media" 指定目标种类。
资源写入
所有写入语句都带有 propagateEvents(默认 false)。设为 true 时,该写入会发布自身的 EntityEvent(触发搜索索引、Webhook 等后续动作)。默认不发布(静默的系统写入)。
ResourceCreate
创建 Content 或 Media。Content 与 Media 共享 fields 模型,值为 Locale 映射。
| 字段 | 目标 | 说明 |
|---|---|---|
resource | 通用 | "Content" 或 "Media"(必填) |
contentType | Content | 要创建的 Content Type({ sys: { id } })。resource 为 Content 时必填 |
fields | 通用 | 字段映射 { "<field>": { "<locale>": 值 } }。每个填充的字段都必须包含默认 Locale 桶。Content 的键遵循 Content Type 定义,Media 的键是固定的(title·description·file) |
locale | 通用 | (便捷项)提供后会将 fields 的各个值自动包装为 { <locale>: 值 } |
publish | 通用 | 写入后发布(在 CDA/ACDA 上可见)。默认 true |
Mediafile:fields.file.{locale}的值是摄取指令{ "source": <值表达式>, "encoding": "url"|"base64" }(两者均必填)。包含文件的 Media 写入仅限 Async(在后台由引擎内联处理后发布,url 与 base64 通用)。也可以创建不含文件(fileless)的 Media。若publish:true但没有文件或处理未完成,则会在发布阶段报错;若publish:false则保持Draft。- 结果(
name绑定):创建出的资源。{ /<name>/sys/id }、{ /<name>/fields/<field>/<locale> }。
// Content
{ "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
"fields": { "title": { "en-US": "{ /payload/fields/title }" } }, "publish": true, "name": "post" }
// Media。file 是摄取指令(仅限 Async)
{ "type": "ResourceCreate", "resource": "Media",
"fields": {
"title": { "en-US": "{ /payload/fields/prompt }" },
"file": { "en-US": { "source": "{ /gen/body/data/0/url }", "encoding": "url" } }
}, "name": "img" }ResourceUpdate
对目标 Content 或 Media 的字段进行整体替换(PUT)。fields 中给出的内容会原样成为新字段,这里未列出的 field 与 locale 会被清除。若只想改动一部分,请使用 ResourcePatch。
| 字段 | 说明 |
|---|---|
resource | "Content" 或 "Media" |
target | 目标({ sys: { id } },必填)。id 通常为 { /ptr } |
fields | 写入的全部字段。值为 Locale 映射。因为是整体替换,这里未列出的 field 与 locale 会被移除。Media file 是摄取指令(参见上文 ResourceCreate)。列出的文件总是重新摄取,未提供的 locale 文件会被删除 |
locale | (便捷项)自动包装 fields |
version | (可选)值表达式(Int)。乐观锁。提供后,仅当与目标当前的 sys.version 一致时才更新;不一致则以版本冲突错误 abort(可用 Try catch)。省略时不做检查(last-write-wins) |
publish | 更新后 republish。默认 true |
在 Media 上若仅为修改 metadata 而使用 Update,会因缺少 file 而导致文件全部被删除(因为是整体替换)。部分变更请务必使用 ResourcePatch。包含文件的 Update 仅限 Async。
{ "type": "ResourceUpdate", "resource": "Content", "target": { "sys": { "id": "{ /payload/sys/id }" } },
"fields": { "title": { "en-US": "Hello", "ko-KR": "안녕" }, "status": { "en-US": "published" } } }ResourcePatch
对目标 Content 或 Media 的字段进行部分合并(PATCH)。只覆盖 fields 中给出的字段(及其中的 Locale),而未提及的字段与 Locale 保持不变。值形态、locale、version、publish 与 ResourceUpdate 相同。
| 字段 | 说明 |
|---|---|
resource | "Content" 或 "Media" |
target | 目标({ sys: { id } },必填)。id 通常为 { /ptr } |
fields | 要覆盖的字段。值为 Locale 映射。仅更新指定的字段与 Locale 桶(其余保持不变)。若值为字面量 null,则删除该 (field, locale)。Media file 是摄取指令(参见上文 ResourceCreate) |
locale | (便捷项)自动包装 fields |
version | (可选)与 ResourceUpdate 相同(乐观锁) |
publish | 更新后 republish。默认 true |
- 删除特定 Locale 或文件:将值设为字面量
null。例如"title": { "fr-FR": null }(删除 fr-FR 标题)、"file": { "en-US": null }(删除 en-US 文件)。值表达式在运行时求值为 null 并不会删除,而是报错(只有字面量 null 才会删除)。 - 若对 Media
file给出摄取指令,则会替换该 locale 的文件(仅限 Async)。不提供文件则保持不变。
// 仅将 viewCount(en-US) +1。title、其他 locale 等其余内容保持不变
{ "type": "ResourcePatch", "resource": "Content", "target": { "sys": { "id": "{ /payload/sys/id }" } },
"fields": { "viewCount": { "en-US": { "+": [ "{ /payload/fields/viewCount }", 1 ] } } } }ResourceDelete
删除目标。仅 Draft 与 Archived 状态可以删除。若为 Published 或 Changed 会被拒绝,因此必须先 ResourceUnpublish(Media 在文件处理中(busy)时会被拒绝)。不会 auto-unpublish(与 CMA/ACMA 相同)。
| 字段 | 说明 |
|---|---|
resource | "Content" 或 "Media" |
target | 目标({ sys: { id } },必填) |
{ "type": "ResourceDelete", "resource": "Content", "target": { "sys": { "id": "{ /payload/sys/id }" } } }ResourcePublish, ResourceUnpublish, ResourceArchive, ResourceUnarchive
独立控制目标的发布与归档状态。四者的字段完全相同。各操作的 status 前提条件与 CMA/ACMA 相同(publish 不能用于 Archived 且需文件处理完成,unpublish 仅限 Published·Changed,archive 仅限 Draft,unarchive 仅限 Archived)。
| 字段 | 说明 |
|---|---|
resource | "Content" 或 "Media" |
target | 目标({ sys: { id } },必填) |
version | (可选)值表达式(Int)。乐观锁。提供后仅当与当前 sys.version 一致时才执行 |
{ "type": "ResourcePublish", "resource": "Content", "target": { "sys": { "id": "{ /payload/sys/id }" } } }
{ "type": "ResourceUnpublish", "resource": "Content", "target": { "sys": { "id": "{ /payload/sys/id }" } } }
{ "type": "ResourceArchive", "resource": "Media", "target": { "sys": { "id": "{ /m/sys/id }" } } }资源读取
读取语句不改变状态(没有 propagateEvents)。
这三种读取语句都通过 from(可选,默认 Current)来决定读取哪一份存储版本。Current 是内容工作室所看到的最新草稿(CMA/ACMA 读取的值),Published 是发布快照(CDA/ACDA 所传递的、最后一次发布时刻的值)。
ResourceFind 与 ResourcePageRead 在此基础上还可以通过 advanced(可选,默认 false)开启高级搜索(Advanced Search)。它仅限 Content,因此在 Media 读取中会被忽略。开启时,where 可使用 regex、near、within 运算符与全文检索(对已开启全文检索的 LongText 字段,eq 还能通过部分、近似匹配找到包含该值的项目),且 order 可按 fields.* 排序。关闭时,这三个运算符会被拒绝,文本的 eq 为精确匹配,而 prefix 及比较、列表运算符与高级搜索无关,始终可用。刚刚创建或修改的项目,需要短暂片刻(约 1 秒)才会反映到高级搜索中,因此紧接着的下一次高级搜索查询可能查不到它。若需立即读取刚写入的项目,请按 id 使用 ResourceRead(基本存储版本,无反映延迟),或用写入返回的 sys.id 查询。
在 where 和 order 中,内容字段要写成 fields.<field>(仅凭字段名本身无法识别)。fields.<field> 的 Space 默认 Locale 会被自动应用,因此无需直接附加 Locale。下方示例中的 fields.status、fields.slug 就是默认 Locale 查询。只有在需要针对特定(非默认)Locale 时,才用 fields.<field>.<locale>(例如 fields.title.ko-KR)明确指定。sys.*(如 sys.createdAt)与 createdBy(:self)则不加 fields.,直接书写。详细规则见值表达式的 where 与 order 中的 Locale。
ResourceRead
按 id 单条查询(get-by-id)。结果会将整个资源绑定到名称上。
| 字段 | 说明 |
|---|---|
resource | "Content" 或 "Media" |
target | 目标({ sys: { id } })。id 为值表达式 |
from | (可选)Current(默认,最新草稿)或 Published(发布快照) |
- 结果:直接引用
{ /<name>/sys/id }、{ /<name>/fields/<field>/<locale> }(无需items/0)。 - 目标不存在时报错。可用
Try包裹处理。
{ "type": "ResourceRead", "resource": "Content",
"target": { "sys": { "id": "{ /payload/fields/orderId }" } }, "name": "order" }ResourceFind
读取按过滤条件匹配的首个单条。若无则为 null。用于以唯一业务键(slug、email、sku)查找单条记录时。
| 字段 | 说明 |
|---|---|
resource | "Content" 或 "Media" |
contentType | (Content)检索范围 Content Type({ sys: { id } }) |
where | 过滤条件({ "<field>": { "<op>": <值> } })。可用运算符遵循运算符列表(regex/near/within 需要 advanced)。支持 createdBy: ":self" |
order | 在多个匹配时决定“第一个”的排序(例如 "-sys.createdAt") |
from | (可选)Current(默认,最新草稿)或 Published(发布快照) |
advanced | (可选)通过高级搜索(Advanced Search)执行。仅限 Content(Media 忽略)。默认 false。参见上文 资源读取 说明 |
- 结果:将首个匹配的资源绑定到名称上。可通过
{ /<name>/fields/<field>/<locale> }直接引用。若无则为null,因此可用{ "==": [ "{ /<name> }", null ] }判断是否存在来分支(find-then-upsert 的典型做法)。
{ "type": "ResourceFind", "resource": "Content", "contentType": { "sys": { "id": "ct_article" } },
"where": { "fields.slug": { "eq": "{ /payload/fields/slug }" } }, "name": "found" }ResourcePageRead
过滤、排序、分页查询。
| 字段 | 说明 |
|---|---|
resource | "Content" 或 "Media" |
contentType | (Content)检索范围 Content Type |
where | 过滤条件({ "<field>": { "<op>": <值> } })。可用运算符遵循运算符列表(regex/near/within 需要 advanced)。支持 createdBy: ":self" |
order | 排序(例如 "-sys.createdAt") |
limit | 分页大小(不超过 100) |
cursor | 下一页使用上次结果的 next |
from | (可选)Current(默认,最新草稿)或 Published(发布快照) |
advanced | (可选)通过高级搜索(Advanced Search)执行。仅限 Content(Media 忽略)。默认 false。参见上文 资源读取 说明 |
- 结果:
{ items, next }。{ /<name>/items/0/... },下一页为{ /<name>/next }。 - 完整遍历通过
Loop while "{ /vars/hasMore }"配合cursor、SetVar累加来实现(参见烹饪书)。
{ "type": "ResourcePageRead", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
"where": { "fields.status": { "eq": "draft" } }, "order": "-sys.createdAt", "limit": 100, "name": "page" }外部
Http
调用外部 HTTP。只要存在 Http,executionMode 就必须是 Async(ExternalIo)。
| 字段 | 说明 |
|---|---|
method | "GET"、"POST"、"PUT"、"PATCH"、"DELETE" |
url | 目标 URL(值表达式,可插入 { /ptr }) |
headers | [{ "key", "value", "secret"? }]。value 为值表达式。secret:true 的请求头被视为 CMA(管理员)专用,不会向最终用户暴露,且仅在发送前才解密 |
body | 请求 body(值表达式或 JSON) |
timeoutMs | 本次调用的超时时间(ms) |
retry | 响应 status 大于等于 400 时的重试次数。默认 0,上限为 maxHttpRetry(默认 2) |
ignoreStatusCode | (重试结束后的)最终 status 大于等于 400 时是否将本次调用视为失败。默认 false 时会按失败处理,成为 Try/catch 的对象。为 true 时则不视为失败,而是将 { status, body } 原样绑定(由调用方自行按 status 分支) |
- 结果:
{ status, body }。{ /<name>/status }、{ /<name>/body/... }。 - 响应大小上限:响应 body 最大为 10MiB。超过时本次调用会以异常失败,可像其他运行时失败一样用
Try/catch处理(这是基于大小的失败,因此不会被ignoreStatusCode忽略)。
{ "type": "Http", "method": "POST", "url": "https://api.llm.com/v1/gen",
"headers": [ { "key": "Authorization", "value": "Bearer sk-...", "secret": true } ],
"body": { "prompt": "{ /payload/fields/prompt }" }, "timeoutMs": 15000, "retry": 1, "name": "resp" }变量
SetVar
声明或更新 script 作用域的可变变量。通过 { /vars/<var> } 引用(JsonLogic 本身没有变量声明,因此作为 statement 提供)。
| 字段 | 说明 |
|---|---|
var | 变量名。通过 { /vars/<var> } 引用 |
value | 值表达式。可引用自身以进行累加 |
{ "type": "SetVar", "var": "total", "value": 0 }
{ "type": "SetVar", "var": "total", "value": { "+": [ "{ /vars/total }", "{ /row/qty }" ] } } // 累加
{ "type": "SetVar", "var": "ids", "value": { "merge": [ "{ /vars/ids }", [ "{ /row/sys/id }" ] ] } } // 收集数组控制流
If
条件分支。condition 是 JsonLogic,真与假遵循真值判定的规则。
| 字段 | 说明 |
|---|---|
condition | JsonLogic(求值为 boolean) |
then | 为真时执行的 Statement 数组 |
else | (可选)为假时执行的 Statement 数组 |
{ "type": "If",
"condition": { "<": [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] },
"then": [ { "type": "Return", "value": { "ok": false, "reason": "insufficient credit" } } ],
"else": [ /* ... */ ] }Loop
循环。选择一种模式:over(foreach)、while(条件)、for(计数)。无论哪种模式,引擎都会以 maxIterations 强制上限(防止无限循环)。body 内禁止外部调用(Http、Media 文件摄取)。
| 字段 | 说明 |
|---|---|
over | foreach:resolve 为数组的值表达式 |
while | 条件:JsonLogic(为真时持续循环) |
for | 计数:{ "from", "to", "step"? }。从 from 到 to(含两端),step 默认 1 |
maxIterations | 引擎强制的最大循环次数(必填) |
as | 用于绑定当前项或索引的名称({ /<as> }) |
body | 循环体 Statement 数组 |
// foreach
{ "type": "Loop", "over": "{ /payload/fields/items }", "as": "item", "maxIterations": 100,
"body": [ { "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_item" } },
"fields": { "name": { "en-US": "{ /item/name }" } } } ] }
// while
{ "type": "Loop", "while": "{ /vars/hasMore }", "maxIterations": 1000, "body": [ /* ... */ ] }
// counted (1..10 step 2)
{ "type": "Loop", "for": { "from": 1, "to": 10, "step": 2 }, "as": "i", "maxIterations": 100, "body": [ /* ... */ ] }Parallel
并发执行各分支,join 后再继续。分支之间不可相互引用(若存在依赖,请改为顺序排列)。
| 字段 | 说明 |
|---|---|
branches | Statement[][]。每个元素为一个分支(语句数组) |
{ "type": "Parallel", "branches": [
[ { "type": "Http", "method": "GET", "url": "https://api.a.com/x", "name": "a" } ],
[ { "type": "Http", "method": "GET", "url": "https://api.b.com/y", "name": "b" } ]
] }Return
相当于一般编程中的 return。 Script 的结果返回给调用方,并在该处正常结束。
| 字段 | 说明 |
|---|---|
value | (可选)要返回的值表达式 |
isError | 默认 false。为 true 时,value 会作为响应的 error 输出(否则为 return) |
statusCode | 响应状态码。默认 200 |
- 若未到达
Return,则没有返回值。要给出结果,请显式指定value。 - 它是正常结束,而非异常或 throw,因此不属于
catch的对象(即使在Try内,也会结束整个 Script,但仍会执行finally)。 - guard 也用该语句表达。即
If加then:[Return](违反条件时返回,之后不再执行),这只是其众多用途之一。
{ "type": "Return", "value": { "orderId": "{ /order/sys/id }", "status": "paid" }, "statusCode": 201 }
{ "type": "Return", "value": { "reason": "payment failed" }, "isError": true, "statusCode": 402 }Try
异常处理。
| 字段 | 说明 |
|---|---|
body | 要尝试执行的 Statement 数组 |
catch | (可选)body 失败时执行。在 /error 中暴露 { message, statement } |
finally | (可选)无论成功或失败始终执行 |
- 若
catch处理了错误,则 Script 不会中断。只有没有catch的失败才会中断 Script(包括补偿尝试)。 - 什么算“失败”,以及补偿(compensation)的限制,详见执行语义、约束与安全。
{ "type": "Try",
"body": [ { "type": "Http", "method": "POST", "url": "https://primary.api/gen", "name": "resp" },
{ "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_result" } },
"fields": { "text": { "en-US": "{ /resp/body/text }" } } } ],
"catch": [ { "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_result" } },
"fields": { "text": { "en-US": "生成失败" }, "error": { "en-US": "{ /error/message }" } } } ],
"finally": [ /* 始终执行 */ ] }相关文档
- 值表达式:上述所有字段遵循的取值规则。
- 执行语义、约束与安全:执行顺序、错误、静态约束与安全。
- 烹饪书:组合这些语句的完整示例。
- Script 概述:顶层结构与执行模式。
