Skip to content

Commit 8d1fe0a

Browse files
author
Cache Hamm
committed
Rework engine.removeRule to be based off of rule name
1 parent f636f1a commit 8d1fe0a

File tree

7 files changed

+90
-96
lines changed

7 files changed

+90
-96
lines changed

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
#### 7.0.0 / 2021-06-03
2-
* Rules now receive a default `id` property, when none is passed to the constructor.
1+
#### 6.1.0 / 2021-06-03
2+
* engine.removeRule() now supports removing rules by name
3+
* Added engine.updateRule(rule)
34

45
#### 6.0.1 / 2021-03-09
56
* Updates Typescript types to include `failureEvents` in EngineResult.

docs/engine.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ engine.removeFact('speed-of-light')
7474
### engine.addRule(Rule instance|Object options)
7575

7676
Adds a rule to the engine. The engine will execute the rule upon the next ```run()```
77-
if the rule doesn't have value set at rule.id, a random string will be set instead.
7877

7978
```js
8079
let Rule = require('json-rules-engine').Rule
@@ -93,9 +92,11 @@ let rule = new Rule()
9392
engine.addRule(rule)
9493
```
9594

96-
### engine.removeRule(Rule instance)
95+
### engine.removeRule(Rule instance | Any ruleName) -> Boolean
9796

98-
Removes a rule from the engine.
97+
Removes a rule from the engine, either by passing a rule object or a rule name. When removing by rule name, all rules matching the provided name will be removed.
98+
99+
Method returns true when rule was successfully remove, or false when not found.
99100

100101
```javascript
101102
// adds a rule
@@ -105,7 +106,7 @@ engine.addRule(rule)
105106
//remove it
106107
engine.removeRule(rule)
107108
//or
108-
engine.removeRule(rule.id)
109+
engine.removeRule(rule.name)
109110
```
110111

111112
### engine.updateRule(Rule instance|Object options)

src/engine.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class Engine extends EventEmitter {
6060
* @param {object|Rule} rule - rule definition. Must be a instance of Rule
6161
*/
6262
updateRule (rule) {
63-
const ruleIndex = this.rules.findIndex(ruleInEngine => (ruleInEngine.id === rule.id) && rule.id)
63+
const ruleIndex = this.rules.findIndex(ruleInEngine => ruleInEngine.name === rule.name)
6464
if (ruleIndex > -1) {
6565
this.rules.splice(ruleIndex, 1)
6666
this.addRule(rule)
@@ -75,19 +75,21 @@ class Engine extends EventEmitter {
7575
* @param {object|Rule|string} rule - rule definition. Must be a instance of Rule
7676
*/
7777
removeRule (rule) {
78+
let ruleRemoved = false
7879
if (!(rule instanceof Rule)) {
79-
const filteredRules = this.rules.filter(ruleInEngine => ruleInEngine.id !== rule)
80-
const ruleRemoved = filteredRules.length !== this.rules.length
80+
const filteredRules = this.rules.filter(ruleInEngine => ruleInEngine.name !== rule)
81+
ruleRemoved = filteredRules.length !== this.rules.length
8182
this.rules = filteredRules
82-
this.prioritizedRules = null
83-
return ruleRemoved
8483
} else {
85-
if (!rule) return false
8684
const index = this.rules.indexOf(rule)
87-
if (index === -1) return false
85+
if (index > -1) {
86+
ruleRemoved = Boolean(this.rules.splice(index, 1).length)
87+
}
88+
}
89+
if (ruleRemoved) {
8890
this.prioritizedRules = null
89-
return Boolean(this.rules.splice(index, 1).length)
9091
}
92+
return ruleRemoved
9193
}
9294

9395
/**

src/rule.js

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ class Rule extends EventEmitter {
1515
* @param {string} options.event.params - parameters to pass to the event listener
1616
* @param {Object} options.conditions - conditions to evaluate when processing this rule
1717
* @param {any} options.name - identifier for a particular rule, particularly valuable in RuleResult output
18-
* @param {any} options.id - identifier for a particular rule, particularly valuable in RuleResult output
1918
* @return {Rule} instance
2019
*/
2120
constructor (options) {
@@ -36,13 +35,6 @@ class Rule extends EventEmitter {
3635
this.setName(options.name)
3736
}
3837

39-
if (!options || options.id === undefined) {
40-
// auto generate an id if none was provided
41-
this.setId('_' + Math.random().toString(36).substr(2, 9))
42-
} else {
43-
this.setId(options.id)
44-
}
45-
4638
const priority = (options && options.priority) || 1
4739
this.setPriority(priority)
4840

@@ -61,15 +53,6 @@ class Rule extends EventEmitter {
6153
return this
6254
}
6355

64-
/**
65-
* Sets the unique id of the rule
66-
* @param {any} id - any truthy input
67-
*/
68-
setId (id) {
69-
this.id = id
70-
return this
71-
}
72-
7356
/**
7457
* Sets the name of the rule
7558
* @param {any} name - any truthy input and zero is allowed

test/engine.test.js

Lines changed: 71 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -86,78 +86,113 @@ describe('Engine', () => {
8686

8787
describe('updateRule()', () => {
8888
it('updates rule', () => {
89-
const rule = new Rule(factories.rule())
90-
engine.addRule(rule)
89+
let rule1 = new Rule(factories.rule({ name: 'rule1' }))
90+
let rule2 = new Rule(factories.rule({ name: 'rule2' }))
91+
engine.addRule(rule1)
92+
engine.addRule(rule2)
9193
expect(engine.rules[0].conditions.all.length).to.equal(2)
92-
rule.conditions = { all: [] }
93-
engine.updateRule(rule)
94-
expect(engine.rules[0].conditions.all.length).to.equal(0)
94+
expect(engine.rules[1].conditions.all.length).to.equal(2)
95+
96+
rule1.conditions = { all: [] }
97+
engine.updateRule(rule1)
98+
99+
rule1 = engine.rules.find(rule => rule.name === 'rule1')
100+
rule2 = engine.rules.find(rule => rule.name === 'rule2')
101+
expect(rule1.conditions.all.length).to.equal(0)
102+
expect(rule2.conditions.all.length).to.equal(2)
95103
})
96104

97105
it('should throw error if rule not found', () => {
98-
const rule1 = new Rule(factories.rule())
106+
const rule1 = new Rule(factories.rule({ name: 'rule1' }))
99107
engine.addRule(rule1)
100-
const rule2 = new Rule(factories.rule())
108+
const rule2 = new Rule(factories.rule({ name: 'rule2' }))
101109
expect(() => {
102110
engine.updateRule(rule2)
103111
}).to.throw(/Engine: updateRule\(\) rule not found/)
104112
})
105113
})
106114

107115
describe('removeRule()', () => {
108-
context('rule instance', () => {
109-
it('removes the rule', () => {
110-
const rule = new Rule(factories.rule())
111-
engine.addRule(rule)
112-
expect(engine.rules.length).to.equal(1)
116+
function setup () {
117+
const rule1 = new Rule(factories.rule({ name: 'rule1' }))
118+
const rule2 = new Rule(factories.rule({ name: 'rule2' }))
119+
engine.addRule(rule1)
120+
engine.addRule(rule2)
121+
engine.prioritizeRules()
122+
123+
return [rule1, rule2]
124+
}
125+
context('remove by rule.name', () => {
126+
it('removes a single rule', () => {
127+
const [rule1] = setup()
128+
expect(engine.rules.length).to.equal(2)
113129

114-
const isRemoved = engine.removeRule(rule)
130+
const isRemoved = engine.removeRule(rule1.name)
115131

116132
expect(isRemoved).to.be.true()
117-
expect(engine.rules.length).to.equal(0)
133+
expect(engine.rules.length).to.equal(1)
118134
expect(engine.prioritizedRules).to.equal(null)
119135
})
120136

121-
it('can only remove added rules', () => {
122-
expect(engine.rules.length).to.equal(0)
123-
const rule = new Rule(factories.rule())
137+
it('removes multiple rules with the same name', () => {
138+
const [rule1] = setup()
139+
const rule3 = new Rule(factories.rule({ name: rule1.name }))
140+
engine.addRule(rule3)
141+
expect(engine.rules.length).to.equal(3)
124142

125-
const isRemoved = engine.removeRule(rule)
143+
const isRemoved = engine.removeRule(rule1.name)
126144

127-
expect(isRemoved).to.equal(false)
145+
expect(isRemoved).to.be.true()
146+
expect(engine.rules.length).to.equal(1)
147+
expect(engine.prioritizedRules).to.equal(null)
128148
})
129149

130-
it('clears the "prioritizedRules" cache', () => {
131-
const rule = new Rule(factories.rule())
132-
engine.addRule(rule)
133-
engine.prioritizeRules()
134-
engine.removeRule(rule)
135-
expect(engine.prioritizedRules).to.equal(null)
150+
it('returns false when rule cannot be found', () => {
151+
setup()
152+
expect(engine.rules.length).to.equal(2)
153+
154+
const isRemoved = engine.removeRule('not-found-name')
155+
156+
expect(isRemoved).to.be.false()
157+
expect(engine.rules.length).to.equal(2)
158+
expect(engine.prioritizedRules).to.not.equal(null)
136159
})
137160
})
161+
context('remove by rule object', () => {
162+
it('removes a single rule', () => {
163+
const [rule1] = setup()
164+
expect(engine.rules.length).to.equal(2)
138165

139-
context('rule id', () => {
140-
it('removes rule based on rule id', () => {
141-
const rule = new Rule(factories.rule())
142-
engine.addRule(rule)
166+
const isRemoved = engine.removeRule(rule1)
167+
168+
expect(isRemoved).to.be.true()
143169
expect(engine.rules.length).to.equal(1)
170+
expect(engine.prioritizedRules).to.equal(null)
171+
})
144172

145-
const isRemoved = engine.removeRule(rule.id)
173+
it('removes a single rule, even if two have the same name', () => {
174+
const [rule1] = setup()
175+
const rule3 = new Rule(factories.rule({ name: rule1.name }))
176+
engine.addRule(rule3)
177+
expect(engine.rules.length).to.equal(3)
178+
179+
const isRemoved = engine.removeRule(rule1)
146180

147181
expect(isRemoved).to.be.true()
148-
expect(engine.rules.length).to.equal(0)
182+
expect(engine.rules.length).to.equal(2)
149183
expect(engine.prioritizedRules).to.equal(null)
150184
})
151185

152186
it('returns false when rule cannot be found', () => {
153-
const rule = new Rule(factories.rule())
154-
engine.addRule(rule)
155-
expect(engine.rules.length).to.equal(1)
187+
setup()
188+
expect(engine.rules.length).to.equal(2)
156189

157-
const isRemoved = engine.removeRule('not-found-id')
190+
const rule3 = new Rule(factories.rule({ name: 'rule3' }))
191+
const isRemoved = engine.removeRule(rule3)
158192

159193
expect(isRemoved).to.be.false()
160-
expect(engine.rules.length).to.equal(1)
194+
expect(engine.rules.length).to.equal(2)
195+
expect(engine.prioritizedRules).to.not.equal(null)
161196
})
162197
})
163198
})

test/rule.test.js

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -54,27 +54,6 @@ describe('Rule', () => {
5454
expect(rule.ruleEvent).to.eql(opts.event)
5555
expect(rule.name).to.eql(opts.name)
5656
})
57-
58-
context('id', () => {
59-
it('autogenerates an id if none was provided', () => {
60-
const rule = new Rule()
61-
expect(rule.id).to.have.lengthOf(10)
62-
})
63-
64-
it('sets the id if provided', () => {
65-
let rule = new Rule({ id: 'test-id' })
66-
expect(rule.id).to.equal('test-id')
67-
68-
rule = new Rule({ id: 0 })
69-
expect(rule.id).to.equal(0)
70-
71-
rule = new Rule({ id: '' })
72-
expect(rule.id).to.equal('')
73-
74-
rule = new Rule({ id: null })
75-
expect(rule.id).to.equal(null)
76-
})
77-
})
7857
})
7958

8059
describe('event emissions', () => {
@@ -117,14 +96,6 @@ describe('Rule', () => {
11796
})
11897
})
11998

120-
describe('setId()', () => {
121-
it('changes the rule id', () => {
122-
const newId = 'test-id-123'
123-
rule.setId(newId)
124-
expect(rule.id).to.equal(newId)
125-
})
126-
})
127-
12899
describe('setEvent()', () => {
129100
it('throws if no argument provided', () => {
130101
expect(() => rule.setEvent()).to.throw(/Rule: setEvent\(\) requires event object/)

test/support/rule-factory.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
module.exports = (options) => {
44
options = options || {}
55
return {
6+
name: options.name,
67
priority: options.priority || 1,
78
conditions: options.conditions || {
89
all: [{

0 commit comments

Comments
 (0)