Skip to content

Commit b556a7e

Browse files
author
Cache Hamm
committed
2 parents 82dccac + f2704cf commit b556a7e

File tree

3 files changed

+150
-0
lines changed

3 files changed

+150
-0
lines changed

docs/engine.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ engine.addFact('account-type', function getAccountType(params, almanac) {
4444
}, { cache: false, priority: 500 })
4545
```
4646

47+
### engine.removeFact(String id)
48+
49+
```js
50+
engine.addFact('speed-of-light', 299792458)
51+
52+
// removes the fact
53+
engine.removeFact('speed-of-light')
54+
```
55+
4756
### engine.addRule(Rule instance|Object options)
4857

4958
Adds a rule to the engine. The engine will execute the rule upon the next ```run()```
@@ -65,6 +74,22 @@ let rule = new Rule()
6574
engine.addRule(rule)
6675
```
6776

77+
### engine.removeRule(Rule instance)
78+
79+
Removes a rule from the engine.
80+
81+
```javascript
82+
// adds a rule
83+
let rule = new Rule()
84+
engine.addRule(rule)
85+
86+
//remove it
87+
engine.removeRule(rule)
88+
```
89+
90+
91+
92+
6893
### engine.addOperator(String operatorName, Function evaluateFunc(factValue, jsonValue))
6994

7095
Adds a custom operator to the engine. For situations that require going beyond the generic, built-in operators (`equal`, `greaterThan`, etc).
@@ -97,6 +122,23 @@ let rule = new Rule(
97122

98123
See the [operator example](../examples/06-custom-operators.js)
99124

125+
126+
127+
### engine.removeOperator(String operatorName)
128+
129+
Removes a operator from the engine
130+
131+
```javascript
132+
engine.addOperator('startsWithLetter', (factValue, jsonValue) => {
133+
if (!factValue.length) return false
134+
return factValue[0].toLowerCase() === jsonValue.toLowerCase()
135+
})
136+
137+
engine.removeOperator('startsWithLetter');
138+
```
139+
140+
141+
100142
### engine.run([Object facts], [Object options]) -> Promise (Events)
101143

102144
Runs the rules engine. Returns a promise which resolves when all rules have been run.

src/engine.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ class Engine extends EventEmitter {
5757
return this
5858
}
5959

60+
/**
61+
* Remove a rule from the engine
62+
* @param {object|Rule} rule - rule definition. Must be a instance of Rule
63+
*/
64+
removeRule (rule) {
65+
if ((rule instanceof Rule) === false) throw new Error('Engine: removeRule() rule must be a instance of Rule')
66+
67+
let index = this.rules.indexOf(rule)
68+
if (index === -1) return false
69+
return Boolean(this.rules.splice(index, 1).length)
70+
}
71+
6072
/**
6173
* Add a custom operator definition
6274
* @param {string} operatorOrName - operator identifier within the condition; i.e. instead of 'equals', 'greaterThan', etc
@@ -73,6 +85,22 @@ class Engine extends EventEmitter {
7385
this.operators.set(operator.name, operator)
7486
}
7587

88+
/**
89+
* Remove a custom operator definition
90+
* @param {string} operatorOrName - operator identifier within the condition; i.e. instead of 'equals', 'greaterThan', etc
91+
* @param {function(factValue, jsonValue)} callback - the method to execute when the operator is encountered.
92+
*/
93+
removeOperator (operatorOrName) {
94+
let operatorName
95+
if (operatorOrName instanceof Operator) {
96+
operatorName = operatorOrName.name
97+
} else {
98+
operatorName = operatorOrName
99+
}
100+
101+
return this.operators.delete(operatorName)
102+
}
103+
76104
/**
77105
* Add a fact definition to the engine. Facts are called by rules as they are evaluated.
78106
* @param {object|Fact} id - fact identifier or instance of Fact
@@ -93,6 +121,21 @@ class Engine extends EventEmitter {
93121
return this
94122
}
95123

124+
/**
125+
* Add a fact definition to the engine. Facts are called by rules as they are evaluated.
126+
* @param {object|Fact} id - fact identifier or instance of Fact
127+
*/
128+
removeFact (factOrId) {
129+
let factId
130+
if (!(factOrId instanceof Fact)) {
131+
factId = factOrId
132+
} else {
133+
factId = factOrId.id
134+
}
135+
136+
return this.facts.delete(factId)
137+
}
138+
96139
/**
97140
* Iterates over the engine rules, organizing them by highest -> lowest priority
98141
* @return {Rule[][]} two dimensional array of Rules.

test/engine.test.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ describe('Engine', () => {
1111

1212
it('has methods for managing facts and rules, and running itself', () => {
1313
expect(engine).to.have.property('addRule')
14+
expect(engine).to.have.property('removeRule')
1415
expect(engine).to.have.property('addOperator')
16+
expect(engine).to.have.property('removeOperator')
1517
expect(engine).to.have.property('addFact')
18+
expect(engine).to.have.property('removeFact')
1619
expect(engine).to.have.property('run')
1720
expect(engine).to.have.property('stop')
1821
})
@@ -71,6 +74,33 @@ describe('Engine', () => {
7174
})
7275
})
7376

77+
describe('removeRule()', () => {
78+
describe('rule instance', () => {
79+
it('removes the rule', () => {
80+
let rule = new Rule(factories.rule())
81+
engine.addRule(rule)
82+
expect(engine.rules.length).to.equal(1)
83+
engine.removeRule(rule)
84+
expect(engine.rules.length).to.equal(0)
85+
})
86+
})
87+
88+
describe('required fields', () => {
89+
it('.conditions', () => {
90+
expect(() => {
91+
engine.removeRule([])
92+
}).to.throw(/Engine: removeRule\(\) rule must be a instance of Rule/)
93+
})
94+
})
95+
96+
it('can only remove added rules', () => {
97+
expect(engine.rules.length).to.equal(0)
98+
let rule = new Rule(factories.rule())
99+
const isRemoved = engine.removeRule(rule)
100+
expect(isRemoved).to.equal(false)
101+
})
102+
})
103+
74104
describe('addOperator()', () => {
75105
it('adds the operator', () => {
76106
expect(engine.operators.size).to.equal(10)
@@ -91,6 +121,24 @@ describe('Engine', () => {
91121
})
92122
})
93123

124+
describe('removeOperator()', () => {
125+
it('removes the operator', () => {
126+
expect(engine.operators.size).to.equal(10)
127+
engine.addOperator('startsWithLetter', (factValue, jsonValue) => {
128+
return factValue[0] === jsonValue
129+
})
130+
expect(engine.operators.size).to.equal(11)
131+
engine.removeOperator('startsWithLetter')
132+
expect(engine.operators.size).to.equal(10)
133+
})
134+
135+
it('can only remove added operators', () => {
136+
expect(engine.operators.size).to.equal(10)
137+
const isRemoved = engine.removeOperator('nonExisting')
138+
expect(isRemoved).to.equal(false)
139+
})
140+
})
141+
94142
describe('addFact()', () => {
95143
const FACT_NAME = 'FACT_NAME'
96144
const FACT_VALUE = 'FACT_VALUE'
@@ -142,6 +190,23 @@ describe('Engine', () => {
142190
})
143191
})
144192

193+
describe('removeFact()', () => {
194+
it('removes a Fact', () => {
195+
expect(engine.facts.size).to.equal(0)
196+
let fact = new Fact('newFact', 50, { cache: false })
197+
engine.addFact(fact)
198+
expect(engine.facts.size).to.equal(1)
199+
engine.removeFact('newFact')
200+
expect(engine.facts.size).to.equal(0)
201+
})
202+
203+
it('can only remove added facts', () => {
204+
expect(engine.facts.size).to.equal(0)
205+
const isRemoved = engine.removeFact('newFact')
206+
expect(isRemoved).to.equal(false)
207+
})
208+
})
209+
145210
describe('run()', () => {
146211
beforeEach(() => {
147212
let conditions = {

0 commit comments

Comments
 (0)