-
Notifications
You must be signed in to change notification settings - Fork 490
/
Copy path07-rule-chaining.mts
162 lines (149 loc) · 4.74 KB
/
07-rule-chaining.mts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
* This is an advanced example demonstrating rules that passed based off the
* results of other rules by adding runtime facts. It also demonstrates
* accessing the runtime facts after engine execution.
*
* Usage:
* node ./examples/07-rule-chaining.js
*
* For detailed output:
* DEBUG=json-rules-engine node ./examples/07-rule-chaining.js
*/
import "colors";
import { Almanac, Engine } from "json-rules-engine";
import apiClient from "./support/account-api-client.mjs";
async function start() {
/**
* Setup a new engine
*/
const engine = new Engine();
/**
* Rule for identifying people who may like screwdrivers
*/
const drinkRule = {
conditions: {
all: [
{
fact: "drinksOrangeJuice",
operator: "equal",
value: true,
},
{
fact: "enjoysVodka",
operator: "equal",
value: true,
},
],
},
event: { type: "drinks-screwdrivers" },
priority: 10, // IMPORTANT! Set a higher priority for the drinkRule, so it runs first
onSuccess: async function (_event: unknown, almanac: Almanac) {
almanac.addFact("screwdriverAficionado", true);
// asychronous operations can be performed within callbacks
// engine execution will not proceed until the returned promises is resolved
const accountId = await almanac.factValue<string>("accountId");
const accountInfo = await apiClient.getAccountInformation(accountId);
almanac.addFact("accountInfo", accountInfo);
},
onFailure: function (_event: unknown, almanac: Almanac) {
almanac.addFact("screwdriverAficionado", false);
},
};
engine.addRule(drinkRule);
/**
* Rule for identifying people who should be invited to a screwdriver social
* - Only invite people who enjoy screw drivers
* - Only invite people who are sociable
*/
const inviteRule = {
conditions: {
all: [
{
fact: "screwdriverAficionado", // this fact value is set when the drinkRule is evaluated
operator: "equal",
value: true,
},
{
fact: "isSociable",
operator: "equal",
value: true,
},
{
fact: "accountInfo",
path: "$.company",
operator: "equal",
value: "microsoft",
},
],
},
event: { type: "invite-to-screwdriver-social" },
priority: 5, // Set a lower priority for the drinkRule, so it runs later (default: 1)
};
engine.addRule(inviteRule);
/**
* Register listeners with the engine for rule success and failure
*/
engine
.on("success", async (event, almanac) => {
const accountInfo = await almanac.factValue<{ company: string }>(
"accountInfo",
);
const accountId = await almanac.factValue("accountId");
console.log(
`${accountId}(${accountInfo.company}) ` +
"DID".green +
` meet conditions for the ${event.type.underline} rule.`,
);
})
.on("failure", async (event, almanac) => {
const accountId = await almanac.factValue("accountId");
console.log(
`${accountId} did ` +
"NOT".red +
` meet conditions for the ${event.type.underline} rule.`,
);
});
// define fact(s) known at runtime
let facts = {
accountId: "washington",
drinksOrangeJuice: true,
enjoysVodka: true,
isSociable: true,
accountInfo: {},
};
// first run, using washington's facts
let results = await engine.run(facts);
// isScrewdriverAficionado was a fact set by engine.run()
let isScrewdriverAficionado = await results.almanac.factValue<boolean>(
"screwdriverAficionado",
);
console.log(
`${facts.accountId} ${isScrewdriverAficionado ? "IS".green : "IS NOT".red} a screwdriver aficionado`,
);
facts = {
accountId: "jefferson",
drinksOrangeJuice: true,
enjoysVodka: false,
isSociable: true,
accountInfo: {},
};
results = await engine.run(facts); // second run, using jefferson's facts; facts & evaluation are independent of the first run
isScrewdriverAficionado = await results.almanac.factValue(
"screwdriverAficionado",
);
console.log(
`${facts.accountId} ${isScrewdriverAficionado ? "IS".green : "IS NOT".red} a screwdriver aficionado`,
);
}
export default start();
/*
* OUTPUT:
*
* loading account information for "washington"
* washington(microsoft) DID meet conditions for the drinks-screwdrivers rule.
* washington(microsoft) DID meet conditions for the invite-to-screwdriver-social rule.
* washington IS a screwdriver aficionado
* jefferson did NOT meet conditions for the drinks-screwdrivers rule.
* jefferson did NOT meet conditions for the invite-to-screwdriver-social rule.
* jefferson IS NOT a screwdriver aficionado
*/