Skip to content

Commit 9cb1148

Browse files
author
beatnory
committed
Added remove funtions
1 parent 8c076dd commit 9cb1148

File tree

3 files changed

+164
-0
lines changed

3 files changed

+164
-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 | Object options)
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: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,26 @@ class Engine extends EventEmitter {
5757
return this
5858
}
5959

60+
/**
61+
* Remove a rule from the engine
62+
* @param {object|Rule} properties - rule definition. can be JSON representation, or instance of Rule
63+
* @param {Object} properties.conditions - conditions to evaluate when processing this rule
64+
*/
65+
removeRule (properties) {
66+
if (!properties) throw new Error('Engine: removeRule() requires options')
67+
if (!properties.hasOwnProperty('conditions')) throw new Error('Engine: removeRule() argument requires "conditions" property')
68+
69+
let index
70+
if (properties instanceof Rule) {
71+
index = this.rules.indexOf(properties)
72+
} else {
73+
index = this.rules.indexOf(r => r.conditions === properties.conditions)
74+
}
75+
76+
if (index === -1) throw new Error('Engine: removeRule() Rule was not found')
77+
this.rules.splice(index, 1)
78+
}
79+
6080
/**
6181
* Add a custom operator definition
6282
* @param {string} operatorOrName - operator identifier within the condition; i.e. instead of 'equals', 'greaterThan', etc
@@ -73,6 +93,23 @@ class Engine extends EventEmitter {
7393
this.operators.set(operator.name, operator)
7494
}
7595

96+
/**
97+
* Remove a custom operator definition
98+
* @param {string} operatorOrName - operator identifier within the condition; i.e. instead of 'equals', 'greaterThan', etc
99+
* @param {function(factValue, jsonValue)} callback - the method to execute when the operator is encountered.
100+
*/
101+
removeOperator (operatorOrName) {
102+
let operatorName
103+
if (operatorOrName instanceof Operator) {
104+
operatorName = operatorOrName.name
105+
} else {
106+
operatorName = operatorOrName
107+
}
108+
109+
if (!this.operators.has(operatorName)) throw new Error('Engine: removeOperator() Operator was not found')
110+
this.operators.delete(operatorName)
111+
}
112+
76113
/**
77114
* Add a fact definition to the engine. Facts are called by rules as they are evaluated.
78115
* @param {object|Fact} id - fact identifier or instance of Fact
@@ -93,6 +130,21 @@ class Engine extends EventEmitter {
93130
return this
94131
}
95132

133+
/**
134+
* Add a fact definition to the engine. Facts are called by rules as they are evaluated.
135+
* @param {object|Fact} id - fact identifier or instance of Fact
136+
*/
137+
removeFact (factOrId) {
138+
let factId
139+
if (!(factOrId instanceof Fact)) {
140+
factId = factOrId
141+
} else {
142+
factId = factOrId.id
143+
}
144+
if (!this.facts.has(factId)) throw new Error('Engine: removeFact() Fact was not found')
145+
this.facts.delete(factId)
146+
}
147+
96148
/**
97149
* Iterates over the engine rules, organizing them by highest -> lowest priority
98150
* @return {Rule[][]} two dimensional array of Rules.

test/engine.test.js

Lines changed: 70 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,36 @@ 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+
let rule = factories.rule()
91+
delete rule.conditions
92+
expect(() => {
93+
engine.removeRule(rule)
94+
}).to.throw(/Engine: removeRule\(\) argument requires "conditions" property/)
95+
})
96+
})
97+
98+
it('can only remove added rules', () => {
99+
expect(engine.rules.length).to.equal(0)
100+
let rule = new Rule(factories.rule())
101+
expect(() => {
102+
engine.removeRule(rule)
103+
}).to.throw(/Engine: removeRule\(\) Rule was not found/)
104+
})
105+
})
106+
74107
describe('addOperator()', () => {
75108
it('adds the operator', () => {
76109
expect(engine.operators.size).to.equal(10)
@@ -91,6 +124,25 @@ describe('Engine', () => {
91124
})
92125
})
93126

127+
describe('removeOperator()', () => {
128+
it('removes the operator', () => {
129+
expect(engine.operators.size).to.equal(10)
130+
engine.addOperator('startsWithLetter', (factValue, jsonValue) => {
131+
return factValue[0] === jsonValue
132+
})
133+
expect(engine.operators.size).to.equal(11)
134+
engine.removeOperator('startsWithLetter')
135+
expect(engine.operators.size).to.equal(10)
136+
})
137+
138+
it('can only remove added operators', () => {
139+
expect(engine.operators.size).to.equal(10)
140+
expect(() => {
141+
engine.removeOperator('nonExisting')
142+
}).to.throw(/Engine: removeOperator\(\) Operator was not found/)
143+
})
144+
})
145+
94146
describe('addFact()', () => {
95147
const FACT_NAME = 'FACT_NAME'
96148
const FACT_VALUE = 'FACT_VALUE'
@@ -142,6 +194,24 @@ describe('Engine', () => {
142194
})
143195
})
144196

197+
describe('removeFact()', () => {
198+
it('removes a Fact', () => {
199+
expect(engine.facts.size).to.equal(0)
200+
let fact = new Fact('newFact', 50, { cache: false })
201+
engine.addFact(fact)
202+
expect(engine.facts.size).to.equal(1)
203+
engine.removeFact('newFact')
204+
expect(engine.facts.size).to.equal(0)
205+
})
206+
207+
it('can only remove added facts', () => {
208+
expect(engine.facts.size).to.equal(0)
209+
expect(() => {
210+
engine.removeFact('newFact')
211+
}).to.throw(/Engine: removeFact\(\) Fact was not found/)
212+
})
213+
})
214+
145215
describe('run()', () => {
146216
beforeEach(() => {
147217
let conditions = {

0 commit comments

Comments
 (0)