Effects (EffectDecl)
Generated from the doc schema (CatalogDocSchema, @canonify/kernel-catalog/doc): each field’s type, default and description are the schema’s own, and each example is a bundle file that readBundle decodes. A field’s Example is its value in one of those examples.
EffectDecl
An effect: one write, delivery, name or call, in order.
One of, told apart by op:
- EffectDecl.create
- EffectDecl.update
- EffectDecl.delete
- EffectDecl.transition
- EffectDecl.emit
- EffectDecl.let
- EffectDecl.allocate
- EffectDecl.call
- EffectDecl.forEach
EffectDecl.create
Create a row.
| Field | Type | Required | Default | Example | Description |
|---|---|---|---|---|---|
op |
"create" |
yes | — | "create" |
Create a row. |
when |
Expr | no | — | "input.amount > 0" |
The effect runs only while this CX condition holds; absent = always. Unknown refuses the call. |
type |
TypeId | yes | — | "ty_9d4r7t1x5b" |
The type of the new row. |
set |
Record<PropId, Expr> | yes | — | {"pr_0q2s4v6x8z":"this","pr_7e9g1j3m5p":"input.amount"} |
The CX value of each property it sets, by property id. |
as |
Ident | no | — | "line" |
The name later effects and outputs read the new row by. |
An item of effects in an action file (or in an effects function’s body).
{
"op": "create",
"type": "ty_9d4r7t1x5b",
"set": { "pr_0q2s4v6x8z": "this", "pr_7e9g1j3m5p": "input.amount" },
"as": "line"
}
An item of effects in an action file (or in an effects function’s body).
{
"op": "create",
"type": "ty_9d4r7t1x5b",
"when": "input.amount > 0",
"set": { "pr_0q2s4v6x8z": "this", "pr_7e9g1j3m5p": "input.amount" }
}
EffectDecl.update
Update a row.
| Field | Type | Required | Default | Example | Description |
|---|---|---|---|---|---|
op |
"update" |
yes | — | "update" |
Update a row. |
when |
Expr | no | — | "input.note != ''" |
The effect runs only while this CX condition holds; absent = always. Unknown refuses the call. |
target |
Expr | yes | — | "this" |
The row it updates: a CX ref. |
set |
Record<PropId, Expr> | yes | — | {"pr_4p6r8t0v2x":"input.note"} |
The CX value of each property it sets, by property id. |
omitAbsent |
true |
no | — | true |
A property whose value is absent is left as it is, not cleared. |
An item of effects in an action file (or in an effects function’s body).
{
"op": "update",
"target": "this",
"when": "input.note != ''",
"set": { "pr_4p6r8t0v2x": "input.note" },
"omitAbsent": true
}
EffectDecl.delete
Delete a row.
| Field | Type | Required | Default | Example | Description |
|---|---|---|---|---|---|
op |
"delete" |
yes | — | "delete" |
Delete a row. |
when |
Expr | no | — | "isSet(input.line)" |
The effect runs only while this CX condition holds; absent = always. Unknown refuses the call. |
target |
Expr | yes | — | "input.line" |
The row it deletes: a CX ref. |
An item of effects in an action file (or in an effects function’s body).
{ "op": "delete", "target": "input.line", "when": "isSet(input.line)" }
EffectDecl.transition
Move a row along its lifecycle.
| Field | Type | Required | Default | Example | Description |
|---|---|---|---|---|---|
op |
"transition" |
yes | — | "transition" |
Move a row along its lifecycle. |
when |
Expr | no | — | "input.cancel" |
The effect runs only while this CX condition holds; absent = always. Unknown refuses the call. |
target |
Expr | yes | — | "this" |
The row it moves: a CX ref. |
lifecycle |
FsmId | yes | — | "lc_2k4m6p8r0t" |
The lifecycle. |
transition |
TransitionId | yes | — | "tn_4g6j8m0p2r" |
The transition of that lifecycle. |
An item of effects in an action file (or in an effects function’s body).
{
"op": "transition",
"target": "this",
"when": "input.cancel",
"lifecycle": "lc_2k4m6p8r0t",
"transition": "tn_6s8v0x2z4b"
}
EffectDecl.emit
Send a delivery after the commit.
| Field | Type | Required | Default | Example | Description |
|---|---|---|---|---|---|
op |
"emit" |
yes | — | "emit" |
Send a delivery after the commit: the only I/O. |
when |
Expr | no | — | "isSet(input.notify)" |
The effect runs only while this CX condition holds; absent = always. Unknown refuses the call. |
to |
string (matching ^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$) |
yes | — | "webhook.post" |
A delivery operation: the only I/O, sent after commit (e.g. webhook.post). |
input |
Record<string, Expr> | yes | — | {"url":"'https://example.com/hooks/orders'","body":"id"} |
The CX value of each input of the delivery operation. |
maps |
Record<string, Record<string (matching ^[A-Za-z][A-Za-z0-9_]*$), Expr>> |
no | — | {"params":{"order_no":"number","total":"total"}} |
The inputs that hold an object (e.g. params, or a webhook body): each field name with its CX value. |
An item of effects in an action file (or in an effects function’s body).
{
"op": "emit",
"to": "webhook.post",
"when": "isSet(input.notify)",
"input": { "url": "'https://example.com/hooks/orders'", "body": "id" }
}
An item of effects in an action file (or in an effects function’s body).
{
"op": "emit",
"to": "email.send_template",
"input": { "recipient": "customer.email", "template_id": "'order_sent'" },
"maps": { "params": { "order_no": "number", "total": "total" } }
}
EffectDecl.let
Name a value for the effects after it.
| Field | Type | Required | Default | Example | Description |
|---|---|---|---|---|---|
op |
"let" |
yes | — | "let" |
Name a value. |
name |
Ident | yes | — | "net" |
The name later effects read it by. |
value |
Expr | yes | — | "total * 0.8" |
The CX value. |
rights |
Elevated | no | — | (see the example) | A widened read: the value is one aggregate over rows the invoker may not read. |
An item of effects in an action file (or in an effects function’s body).
{ "op": "let", "name": "net", "value": "total * 0.8" }
An item of effects in an action file (or in an effects function’s body).
{
"op": "let",
"name": "open_orders",
"value": "count(customer.orders)",
"rights": {
"discloses": "count",
"reason": { "text": "The order count is shown to every clerk." }
}
}
EffectDecl.allocate
Place an amount over rows in order.
| Field | Type | Required | Default | Example | Description |
|---|---|---|---|---|---|
op |
"allocate" |
yes | — | "allocate" |
Place an amount over rows in order, each row up to its cap. |
when |
Expr | no | — | "input.amount > 0" |
The effect runs only while this CX condition holds; absent = always. Unknown refuses the call. |
amount |
Expr | yes | — | "input.amount" |
The amount it places: a CX number, quantity or money. Blank refuses the call; zero places nothing. |
over |
Expr | yes | — | "customer.orders" |
The rows it places the amount over: a CX collection of rows. |
each |
Ident | yes | — | "o" |
The name the cap and the order keys read each row by. |
cap |
Expr | yes | — | "o.total" |
The most a row takes: a CX value of the amount’s type over the row. Blank or zero takes nothing. |
order |
SortKey[] (at least one) | yes | — | [{"by":"o.created_at","desc":true}] |
The order the rows take their shares in: the first key decides, then the next; ties by the row. |
remainder |
"refuse" | "keep" |
yes | — | "keep" |
refuse: an amount the rows cannot hold refuses the call; keep: what is left stays unplaced. |
as |
Ident | yes | — | "paid" |
The name later effects and outputs read the shares by: the rows that took a share, each with its share. |
message |
MsgRef | no | — | (see the example) | What the refusal says when the rows cannot hold the amount (remainder refuse only). |
An item of effects in an action file (or in an effects function’s body).
{
"op": "allocate",
"when": "input.amount > 0",
"amount": "input.amount",
"over": "customer.orders.where(o => o.status == 'placed')",
"each": "o",
"cap": "o.total",
"order": [{ "by": "o.created_at" }, { "by": "o.total", "desc": true }],
"remainder": "refuse",
"as": "paid",
"message": {
"text": "The open orders take only {placed} of the payment.",
"params": { "placed": "paid.sum(s => s.share)" }
}
}
EffectDecl.call
Run a shared effects function.
| Field | Type | Required | Default | Example | Description |
|---|---|---|---|---|---|
op |
"call" |
yes | — | "call" |
Run an effects function. |
when |
Expr | no | — | "input.close" |
The effect runs only while this CX condition holds; absent = always. Unknown refuses the call. |
fn |
FnId | yes | — | "fn_5j7m9p1r3t" |
The effects function. |
with |
Record<Ident, Expr> | yes | — | {"order":"this"} |
The CX value of each parameter. |
An item of effects in an action file (or in an effects function’s body).
{
"op": "call",
"fn": "fn_5j7m9p1r3t",
"when": "input.close",
"with": { "order": "this" }
}
EffectDecl.forEach
Run effects once per item of a bounded collection.
| Field | Type | Required | Default | Example | Description |
|---|---|---|---|---|---|
op |
"forEach" |
yes | — | "forEach" |
Run the body once per item of a collection. |
over |
Expr | yes | — | "input.lines" |
The collection: a CX collection, at most limit items. |
as |
Ident | yes | — | "item" |
The name the body reads the item by. |
limit |
integer (greater than 0) | yes | — | 50 |
The most items it runs over; more is invoke.foreach_limit. Required: every write has a static bound (P7). |
preconditions |
ItemPreconditionDecl[] | no | — | (see the example) | The conditions each item needs, checked before the body runs for it. |
body |
EffectDecl[] | yes | — | (see the example) | The effects run for each item. |
An item of effects in an action file (or in an effects function’s body).
{
"op": "forEach",
"over": "input.lines",
"as": "item",
"limit": 50,
"preconditions": [
{
"id": "positive_amount",
"holds": "item.amount > 0",
"severity": "refuse",
"message": { "text": "Each line needs an amount above zero." }
}
],
"body": [
{
"op": "create",
"type": "ty_9d4r7t1x5b",
"set": { "pr_0q2s4v6x8z": "this", "pr_7e9g1j3m5p": "item.amount" }
}
]
}
SortKey
One key of the order.
| Field | Type | Required | Default | Example | Description |
|---|---|---|---|---|---|
by |
Expr | yes | — | "o.created_at" |
The CX key over the row; a blank key sorts first ascending, last descending. |
desc |
true |
no | — | true |
Descending; absent = ascending. |
An item of order in an allocate effect of an action file.
{ "by": "o.created_at", "desc": true }