Skip to content

Commit b31b902

Browse files
author
Christopher Pardy
committed
Allow Named Conditions
Allow Conditions to include names that are emitted as part of events and can be serialized to / from JSON Names are useful to provide human readable tags on the different conditions, especially complex ones made up of nested boolean conditions.
1 parent 919aba5 commit b31b902

File tree

5 files changed

+69
-41
lines changed

5 files changed

+69
-41
lines changed

examples/02-nested-boolean-logic.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ async function start () {
3131
fact: 'personalFoulCount',
3232
operator: 'greaterThanInclusive',
3333
value: 5
34-
}]
34+
}],
35+
name: "short foul limit"
3536
}, {
3637
all: [{
3738
fact: 'gameDuration',
@@ -43,7 +44,8 @@ async function start () {
4344
operator: 'lessThan',
4445
value: 6
4546
}
46-
}]
47+
}],
48+
name: "long foul limit"
4749
}]
4850
},
4951
event: { // define the event to fire when the conditions evaluate truthy

src/condition.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ export default class Condition {
4444
if (this.priority) {
4545
props.priority = this.priority
4646
}
47+
if (this.name) {
48+
props.name = this.name
49+
}
4750
const oper = Condition.booleanOperator(this)
4851
if (oper) {
4952
if (Array.isArray(this[oper])) {

test/condition.test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ function condition () {
1212
return {
1313
all: [{
1414
id: '6ed20017-375f-40c9-a1d2-6d7e0f4733c5',
15+
name: "team participation in form",
1516
fact: 'team_participation',
1617
operator: 'equal',
1718
value: 50,
@@ -29,6 +30,7 @@ describe('Condition', () => {
2930
expect(subject).to.have.property('operator')
3031
expect(subject).to.have.property('value')
3132
expect(subject).to.have.property('path')
33+
expect(subject).to.have.property('name');
3234
})
3335

3436
it('boolean conditions have properties', () => {

test/engine-event.test.js

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,19 @@ describe('Engine: event', () => {
2525
*/
2626
function simpleSetup () {
2727
const conditions = {
28-
any: [{
29-
fact: 'age',
30-
operator: 'greaterThanInclusive',
31-
value: 21
32-
}, {
33-
fact: 'qualified',
34-
operator: 'equal',
35-
value: true
36-
}]
28+
any: [
29+
{
30+
name: 'over 21',
31+
fact: 'age',
32+
operator: 'greaterThanInclusive',
33+
value: 21
34+
},
35+
{
36+
fact: 'qualified',
37+
operator: 'equal',
38+
value: true
39+
}
40+
]
3741
}
3842
engine = engineFactory()
3943
const ruleOptions = { conditions, event, priority: 100 }
@@ -50,25 +54,32 @@ describe('Engine: event', () => {
5054
*/
5155
function advancedSetup () {
5256
const conditions = {
53-
any: [{
54-
fact: 'age',
55-
operator: 'greaterThanInclusive',
56-
value: 21
57-
}, {
58-
fact: 'qualified',
59-
operator: 'equal',
60-
value: true
61-
}, {
62-
all: [{
63-
fact: 'zipCode',
64-
operator: 'in',
65-
value: [80211, 80403]
66-
}, {
67-
fact: 'gender',
68-
operator: 'notEqual',
69-
value: 'female'
70-
}]
71-
}]
57+
any: [
58+
{
59+
fact: 'age',
60+
operator: 'greaterThanInclusive',
61+
value: 21
62+
},
63+
{
64+
fact: 'qualified',
65+
operator: 'equal',
66+
value: true
67+
},
68+
{
69+
all: [
70+
{
71+
fact: 'zipCode',
72+
operator: 'in',
73+
value: [80211, 80403]
74+
},
75+
{
76+
fact: 'gender',
77+
operator: 'notEqual',
78+
value: 'female'
79+
}
80+
]
81+
}
82+
]
7283
}
7384
engine = engineFactory()
7485
const ruleOptions = { conditions, event, priority: 100 }
@@ -91,6 +102,7 @@ describe('Engine: event', () => {
91102
expect(ruleResult.result).to.be.true()
92103
expect(ruleResult.conditions.any[0].result).to.be.true()
93104
expect(ruleResult.conditions.any[0].factResult).to.equal(21)
105+
expect(ruleResult.conditions.any[0].name).to.equal('over 21')
94106
expect(ruleResult.conditions.any[1].result).to.be.false()
95107
expect(ruleResult.conditions.any[1].factResult).to.equal(false)
96108
}
@@ -177,11 +189,13 @@ describe('Engine: event', () => {
177189
params: drinkOrderParams
178190
}
179191
const drinkOrderConditions = {
180-
any: [{
181-
fact: 'canOrderDrinks',
182-
operator: 'equal',
183-
value: true
184-
}]
192+
any: [
193+
{
194+
fact: 'canOrderDrinks',
195+
operator: 'equal',
196+
value: true
197+
}
198+
]
185199
}
186200
const drinkOrderRule = factories.rule({
187201
conditions: drinkOrderConditions,
@@ -193,7 +207,10 @@ describe('Engine: event', () => {
193207
engine.on('success', function (event, almanac, ruleResult) {
194208
switch (event.type) {
195209
case 'setDrinkingFlag':
196-
almanac.addRuntimeFact('canOrderDrinks', event.params.canOrderDrinks)
210+
almanac.addRuntimeFact(
211+
'canOrderDrinks',
212+
event.params.canOrderDrinks
213+
)
197214
break
198215
case 'offerDrink':
199216
expect(event.params).to.eql(drinkOrderParams)
@@ -257,7 +274,9 @@ describe('Engine: event', () => {
257274
expect(ruleResult.conditions.any[1].factResult).to.equal(false)
258275
expect(ruleResult.conditions.any[2].result).to.be.false()
259276
expect(ruleResult.conditions.any[2].all[0].result).to.be.false()
260-
expect(ruleResult.conditions.any[2].all[0].factResult).to.equal(ZIP_CODE)
277+
expect(ruleResult.conditions.any[2].all[0].factResult).to.equal(
278+
ZIP_CODE
279+
)
261280
expect(ruleResult.conditions.any[2].all[1].result).to.be.false()
262281
expect(ruleResult.conditions.any[2].all[1].factResult).to.equal(GENDER)
263282
}
@@ -375,7 +394,8 @@ describe('Engine: event', () => {
375394
rule.on('success', successSpy)
376395
await engine.run()
377396
const ruleResult = successSpy.getCall(0).args[2]
378-
const expected = '{"conditions":{"priority":1,"any":[{"operator":"greaterThanInclusive","value":21,"fact":"age","factResult":21,"result":true},{"operator":"equal","value":true,"fact":"qualified","factResult":false,"result":false}]},"event":{"type":"setDrinkingFlag","params":{"canOrderDrinks":true}},"priority":100,"result":true}'
397+
const expected =
398+
'{"conditions":{"priority":1,"any":[{"name":"over 21","operator":"greaterThanInclusive","value":21,"fact":"age","factResult":21,"result":true},{"operator":"equal","value":true,"fact":"qualified","factResult":false,"result":false}]},"event":{"type":"setDrinkingFlag","params":{"canOrderDrinks":true}},"priority":100,"result":true}'
379399
expect(JSON.stringify(ruleResult)).to.equal(expected)
380400
})
381401
})

types/index.d.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,11 @@ interface ConditionProperties {
152152
path?: string;
153153
priority?: number;
154154
params?: Record<string, any>;
155+
name?: string;
155156
}
156157

157158
type NestedCondition = ConditionProperties | TopLevelCondition;
158-
type AllConditions = { all: NestedCondition[] };
159-
type AnyConditions = { any: NestedCondition[] };
160-
type NotConditions = { not: NestedCondition };
159+
type AllConditions = { all: NestedCondition[]; name?: string; priority?: number; };
160+
type AnyConditions = { any: NestedCondition[]; name?: string; priority?: number; };
161+
type NotConditions = { not: NestedCondition; name?: string; priority?: number; };
161162
export type TopLevelCondition = AllConditions | AnyConditions | NotConditions;

0 commit comments

Comments
 (0)