Prehod naj bo odvisen od entitete, tovora ali obiskovalca, vsako pravilo pa na enem mestu.
Pogoj je izraz za when. Če ne drži, je dogodek zavrnjen: brez spremembe stanja, brez učinkov. V pogojih živijo poslovna pravila.
APPROVE -> approved when (<= @entity.amount 500)
(set @entity.note "Approved")PAY -> paid when (> ?amount 0)
(set @entity.total ?amount)?amount je polje prihajajočega dogodka. Navedeno mora biti, bodisi v emits lastnosti, ki ga odda, bodisi v lokalnem vnosu listens, da lahko preverjevalnik preveri njegov tip.
Tu blagajna zavrne plačilo nič, neplačano naročilo pa ne more na pot:
trait Checkout -> Order [interaction, instance] {
state pending {
INIT -> pending
(render-ui main <Stack gap={sm}>
<Typography content={Unpaid} variant={h4} />
<Button action={PAY} actionPayload={{ amount: 40 }} label={"Pay 40"} />
</Stack>)
PAY -> paid when (> ?amount 0)
(set @entity.total ?amount)
(emit MOVED { event: PAY })
(render-ui main <Stack gap={sm}>
<Typography content={"Paid 40"} variant={h4} />
<Button action={SHIP} label={Ship} />
</Stack>)
}
state paid {
INIT -> pending
(render-ui main <Stack gap={sm}>
<Typography content={Unpaid} variant={h4} />
<Button action={PAY} actionPayload={{ amount: 40 }} label={"Pay 40"} />
</Stack>)
SHIP -> shipped
(emit MOVED { event: SHIP })
(render-ui main <Stack gap={sm}>
<Typography content={Shipped} variant={h4} />
<Button action={NEW_ORDER} label={"New order"} />
</Stack>)
}
state shipped {
INIT -> pending
(render-ui main <Stack gap={sm}>
<Typography content={Unpaid} variant={h4} />
<Button action={PAY} actionPayload={{ amount: 40 }} label={"Pay 40"} />
</Stack>)
NEW_ORDER -> pending
(emit MOVED { event: NEW_ORDER })
(render-ui main <Stack gap={sm}>
<Typography content={Unpaid} variant={h4} />
<Button action={PAY} actionPayload={{ amount: 40 }} label={"Pay 40"} />
</Stack>)
}
emits {
PAY {
amount : number!
}
MOVED -> external {
event : string!
}
@description "Each move names the event it took, so a diagram beside the order can follow it."
}
}1app std-orb-sample-checkout "1.0.0"
2"std-orb-sample-checkout — the checkout program shown on orb.almadar.io's home page, running: an order that cannot ship before it is paid. The page shows this file as code beside the running trait, and each move is reported (MOVED) so its state machine can follow along."
3orbital Orders {
4 entity Order [runtime] {
5 id : string!
6 total : number
7 }
8
9 trait Checkout -> Order [interaction, instance] {
10 initial: pending
11
12 state pending {
13 INIT -> pending
14 (render-ui main { type: stack, gap: sm, children: [
15 { type: typography, content: "Unpaid", variant: h4 },
16 { type: button, label: "Pay 40", action: PAY, actionPayload: { amount: 40 } }
17 ] })
18 PAY -> paid when (> ?amount 0)
19 (set @entity.total ?amount)
20 (emit MOVED { event: "PAY" })
21 (render-ui main { type: stack, gap: sm, children: [
22 { type: typography, content: "Paid 40", variant: h4 },
23 { type: button, label: "Ship", action: SHIP }
24 ] })
25 }
26
27 state paid {
28 SHIP -> shipped
29 (emit MOVED { event: "SHIP" })
30 (render-ui main { type: stack, gap: sm, children: [
31 { type: typography, content: "Shipped", variant: h4 },
32 { type: button, label: "New order", action: NEW_ORDER }
33 ] })
34 }
35
36 state shipped {
37 NEW_ORDER -> pending
38 (emit MOVED { event: "NEW_ORDER" })
39 (render-ui main { type: stack, gap: sm, children: [
40 { type: typography, content: "Unpaid", variant: h4 },
41 { type: button, label: "Pay 40", action: PAY, actionPayload: { amount: 40 } }
42 ] })
43 }
44
45 emits {
46 PAY {
47 amount : number!
48 }
49 MOVED -> external {
50 event : string!
51 }
52 @description "Each move names the event it took, so a diagram beside the order can follow it."
53 }
54 }
55
56 page "/checkout" -> Checkout
57}Kaj se zgodi, ko se sproži PAY:
(> @payload.amount 0)(set @entity.total @payload.amount)APPROVE -> approved when (= @user.role "manager")
(set @entity.approvedBy @user.id)@user je prijavljeni obiskovalec. Njegovo obliko enkrat navedi z entiteto [identity], preverjevalnik pa zavrne vlogo, ki je ni v naboru:
▼entity Person [persistent: people, identity] {
id : string! @key
role : "employee" | "manager" = employee
}(and …), (or …) in (not …) združujejo pogoje. Ko naj dogodek naredi različne stvari glede na vrednost, napiši en prehod za vsak primer z izključujočimi pogoji ali pa naj jih zate napiše match:
▼REVIEW -> reviewed match @entity.priority {
"high" -> (notify warning "Escalated")
_ -> (notify info "Queued")
}Pogoj zavrne dogodek; ne skrije gumba, ki ga pošlje. Če se gumb ne sme pokazati, to povej na zaslonu: z when na dejanju vrstice ali z (if …) okoli vozlišča. Nič se ne skrije implicitno, zato se program bere natanko tako, kot se obnaša.
Dogodki med orbitali povežejo ločene orbitale.