Pogoji in poslovna pravila
Source:
tests/schemas/03-guards.orb
Guards are conditions that must be true for a transition to fire. They act as the gatekeepers of your business rules — written once, enforced everywhere, for both the UI and the API.
Kaj je pogoj?
A guard is an S-expression on a transition. If it evaluates to false, the transition is blocked:
{
"from": "active",
"event": "WITHDRAW",
"to": "active",
"guard": [">=", "@entity.balance", "@payload.amount"],
"effects": [...]
}
The user can only withdraw if balance >= amount. If not, the transition is silently blocked (the UI can surface a disabled state or error message).
Sintaksa S-izrazov
Guards are written as nested arrays where the first element is the operator:
[operator, arg1, arg2, ...]
Arguments can be:
- Literals:
100,"active",true - Bindings:
"@entity.field","@payload.field","@state","@now" - Nested expressions:
["+", "@entity.count", 1]
Primerjalni operatorji
| Operator | Meaning | Example |
|---|---|---|
= | Equal | ["=", "@entity.status", "active"] |
!= | Not equal | ["!=", "@entity.role", "guest"] |
> | Greater than | [">", "@entity.score", 0] |
>= | Greater or equal | [">=", "@entity.balance", "@payload.amount"] |
< | Less than | ["<", "@entity.attempts", 3] |
<= | Less or equal | ["<=", "@entity.age", 65] |
Logicni operatorji
Combine conditions with and, or, not:
["and",
[">=", "@entity.balance", "@payload.amount"],
["=", "@entity.isVerified", true]
]
["or",
["=", "@entity.role", "admin"],
["=", "@entity.role", "manager"]
]
["not", ["=", "@entity.status", "frozen"]]
Celoten primer: upravljalnik racunov
This is the complete AccountManager from 03-guards.orb. It demonstrates:
- A guard using
andto combine two conditions - Using
@payload.amountto check against user input - Simple state transitions (freeze/unfreeze) without guards
orbital AccountManager {
entity Account [persistent: accounts] {
id : string!
balance : number
isVerified : boolean
}
trait AccountActions -> Account [interaction] {
initial: active
state active {
INIT -> active
(fetch Account)
(render-ui main { type: "entity-table", entity: "Account", fields: ["balance", "isVerified"], columns: ["balance", "isVerified"], itemActions: [{ event: "WITHDRAW", label: "Withdraw" }, { event: "FREEZE", label: "Freeze" }] })
WITHDRAW -> active
when (and (>= @entity.balance @payload.amount) (= @entity.isVerified true))
(set @entity.balance (- @entity.balance @payload.amount))
FREEZE -> frozen
}
state frozen {
UNFREEZE -> active
}
}
page "/accounts" -> AccountActions
}
Reading the WITHDRAW guard:
["and",
[">=", "@entity.balance", "@payload.amount"], // Account has enough funds
["=", "@entity.isVerified", true] // Account is verified
]
Both conditions must be true. If the account is unverified, or the balance is too low, the withdrawal is blocked.
Pogoji z izracenimi vrednostmi
Guards can use arithmetic operators — the result of a nested expression is used as an argument:
// Only allow if balance after withdrawal stays above minimum
[">=",
["-", "@entity.balance", "@payload.amount"],
100
]
// Only allow if item count is within limit
["<",
["+", "@entity.itemCount", 1],
50
]
Pogosti vzorci pogojev
Dostop na osnovi vlog
// Only admins can delete
{
"from": "listing",
"event": "DELETE",
"to": "listing",
"guard": ["=", "@currentUser.role", "admin"],
"effects": [["persist", "delete", "Task", "@entity.id"]]
}
Preverjanje lastnistva
// Only the assignee can start the task
{
"from": "Pending",
"event": "START",
"to": "InProgress",
"guard": ["=", "@entity.assigneeId", "@currentUser.id"],
"effects": [["persist", "update", "Task", "@entity"]]
}
Preverjanje polj
// Score must be between 0 and 100
{
"guard": ["and",
[">=", "@payload.score", 0],
["<=", "@payload.score", 100]
]
}
Predpogoj statusa
// Can only approve if currently in review
{
"guard": ["=", "@entity.status", "review"]
}
Pogoji v primerjavi z ucinki
Guards run before the transition. Effects run after. Never use effects to enforce business rules — that's what guards are for.
// ❌ Wrong: using effects to simulate a guard
"effects": [
["if", ["<", "@entity.balance", 0], ["notify", "error", "Insufficient funds"]]
]
// ✅ Correct: guard blocks the transition entirely
"guard": [">=", "@entity.balance", "@payload.amount"]
Naslednji koraki
- Cross-Orbital Communication — guards can reference data from other orbitals
- UI Patterns & render-ui — rendering feedback when guards block actions
- Building a Full App — guards in a real multi-orbital application