Skip to content

Commit 9cf31d7

Browse files
author
Cache Hamm
committed
Add rule event emissions; formalize rule chaining
1 parent df85a37 commit 9cf31d7

4 files changed

Lines changed: 79 additions & 6 deletions

File tree

docs/almanac.md

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ almanac
2222
.then( values => console.log(values))
2323
```
2424

25+
### almanac.addRuntimeFact(String factId, Mixed value)
26+
27+
Sets a constant fact mid-run. Often used in conjunction with rule and engine event emissions.
28+
29+
```js
30+
almanac.addRuntimeFact('account-id', 1)
31+
```
32+
2533
## Common Use Cases
2634

2735
### Fact dependencies
@@ -101,4 +109,39 @@ engine.on('success', (event, almanac) => {
101109
return request.post({ url: `http://my-service/toggle?funded=${!info.funded}`)
102110
})
103111
})
104-
```
112+
```
113+
114+
### Rule Chaining
115+
116+
The `almanac.addRuntimeFact()` method may be used in conjunction with event emissions to
117+
set fact values during runtime, effectively enabling _rule-chaining_. Note that ordering
118+
of rule execution is enabled via the `priority` option, and is crucial component to propertly
119+
configuring rule chaining.
120+
121+
```js
122+
engine.addRule({
123+
conditions,
124+
event,
125+
onSuccess: function (event, almanac) {
126+
almanac.addRuntimeFact('rule-1-passed', true) // track that the rule passed
127+
},
128+
onFailure: function (event, almanac) {
129+
almanac.addRuntimeFact('rule-1-passed', false) // track that the rule failed
130+
},
131+
priority: 10 // a higher priority ensures this rule will be run prior to subsequent rules
132+
})
133+
134+
// in a later rule:
135+
engine.addRule({
136+
conditions: {
137+
all: [{
138+
fact: 'rule-1-passed',
139+
operator: 'equal',
140+
value: true
141+
}
142+
},
143+
priority: 1 // lower priority ensures this is run AFTER its predecessor
144+
}
145+
```
146+
147+
See the [full example](../examples/07-rule-chaining.js)

docs/engine.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ let Rule = require('json-rules-engine').Rule
4343
engine.addRule({
4444
conditions: {},
4545
event: {},
46-
priority: 1
46+
priority: 1, // optional, default: 1
47+
onSuccess: function (event, almanac) {}, // optional
48+
onFailure: function (event, almanac) {}, // optional
4749
})
4850

4951
// or rule instance:

docs/rules.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,29 @@ let rule = new Rule(jsonString) // restored rule; same conditions, priority, eve
7676
let jsonObject = rule.toJSON(false) // object: {conditions:{ all: [] }, priority: 50 ...
7777
```
7878

79+
### Events
80+
81+
Listen for 'success' and 'failure' events emitted when rule is evaluated.
82+
83+
#### ```rule.on('success', Function(Object event, Almanac almanac))```
84+
85+
```js
86+
// whenever rule is evaluated and the conditions pass, 'success' will trigger
87+
rule.on('success', function(event, almanac) {
88+
console.log(event) // { type: 'my-event', params: { id: 1 }
89+
})
90+
```
91+
92+
#### ```rule.on('failure', Function(Object event, Almanac almanac))```
93+
94+
Companion to 'success', except fires when the rule fails.
95+
96+
```js
97+
engine.on('failure', function(event, almanac) {
98+
console.log(event) // { type: 'my-event', params: { id: 1 }
99+
})
100+
```
101+
79102
## Conditions
80103

81104
Each rule condition must begin with a boolean operator(```all``` or ```any```) at its root.

examples/07-rule-chaining.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,13 @@ let drinkRule = {
3535
}]
3636
},
3737
event: { type: 'drinks-screwdrivers' },
38-
priority: 10 // IMPORTANT! Set a higher priority for the drinkRule, so it runs first
38+
priority: 10, // IMPORTANT! Set a higher priority for the drinkRule, so it runs first
39+
onSuccess: function (event, almanac) {
40+
almanac.addRuntimeFact('screwdriverAficionado', true)
41+
},
42+
onFailure: function (event, almanac) {
43+
almanac.addRuntimeFact('screwdriverAficionado', false)
44+
},
3945
}
4046
engine.addRule(drinkRule)
4147

@@ -68,18 +74,17 @@ let facts
6874
engine
6975
.on('success', (event, almanac) => {
7076
console.log(facts.accountId + ' DID '.green + 'meet conditions for the ' + event.type.underline + ' rule.')
71-
almanac.addRuntimeFact('screwdriverAficionado', true)
7277
})
7378
.on('failure', rule => {
7479
console.log(facts.accountId + ' did ' + 'NOT'.red + ' meet conditions for the ' + rule.event.type.underline + ' rule.')
7580
})
7681

7782
// define fact(s) known at runtime
78-
facts = { accountId: 'washington', drinksOrangeJuice: true, enjoysVodka: true, isSociable: true, screwdriverAficionado: false }
83+
facts = { accountId: 'washington', drinksOrangeJuice: true, enjoysVodka: true, isSociable: true }
7984
engine
8085
.run(facts) // first run, using washington's facts
8186
.then(() => {
82-
facts = { accountId: 'jefferson', drinksOrangeJuice: true, enjoysVodka: false, isSociable: true, screwdriverAficionado: false }
87+
facts = { accountId: 'jefferson', drinksOrangeJuice: true, enjoysVodka: false, isSociable: true }
8388
return engine.run(facts) // second run, using jefferson's facts; facts & evaluation are independent of the first run
8489
})
8590
.catch(console.log)

0 commit comments

Comments
 (0)