Skip to content

Commit 6b2e92a

Browse files
author
Cache Hamm
committed
fix almanac.factValue incorrectly interpretting path
1 parent 6b295f1 commit 6b2e92a

File tree

3 files changed

+46
-14
lines changed

3 files changed

+46
-14
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"scripts": {
77
"test": "mocha && npm run lint --silent",
88
"lint": "standard --verbose | snazzy || true",
9+
"lint:fix": "standard --fix",
910
"prepublish": "npm run compile",
1011
"compile": "babel --stage 1 -d dist/ src/ && regenerator --no-cache-dir --include-runtime src/generator-runtime.js > dist/generator-runtime.js"
1112
},

src/almanac.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { UndefinedFactError } from './errors'
1717
export default class Almanac {
1818
constructor (factMap, runtimeFacts = {}) {
1919
this.factMap = new Map(factMap)
20-
this.factResultsCache = new Map()
20+
this.factResultsCache = new Map() // { cacheKey: Promise<factValu> }
2121

2222
for (let factId in runtimeFacts) {
2323
let fact
@@ -89,15 +89,17 @@ export default class Almanac {
8989
* @return {Promise} a promise which will resolve with the fact computation.
9090
*/
9191
async factValue (factId, params = {}, path = '') {
92+
let factValue
9293
let fact = this._getFact(factId)
9394
let cacheKey = fact.getCacheKey(params)
9495
let cacheVal = cacheKey && this.factResultsCache.get(cacheKey)
9596
if (cacheVal) {
96-
cacheVal.then(val => debug(`almanac::factValue cache hit for fact:${factId} value: ${JSON.stringify(val)}<${typeof val}>`))
97-
return cacheVal
97+
factValue = await cacheVal
98+
debug(`almanac::factValue cache hit for fact:${factId} value: ${JSON.stringify(factValue)}<${typeof factValue}>`)
99+
} else {
100+
verbose(`almanac::factValue cache miss for fact:${factId}; calculating`)
101+
factValue = await this._setFactValue(fact, params, fact.calculate(params, this))
98102
}
99-
verbose(`almanac::factValue cache miss for fact:${factId}; calculating`)
100-
let factValue = await this._setFactValue(fact, params, fact.calculate(params, this))
101103
if (path) {
102104
if (isPlainObject(factValue) || Array.isArray(factValue)) {
103105
factValue = selectn(path)(factValue)

test/engine-fact.test.js

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,12 @@ describe('Engine: fact evaluation', () => {
5757
}
5858
let successSpy = sinon.spy()
5959
let failureSpy = sinon.spy()
60-
function setup (conditions = baseConditions(), engineOptions = {}) {
60+
beforeEach(() => {
6161
successSpy.reset()
6262
failureSpy.reset()
63+
})
64+
65+
function setup (conditions = baseConditions(), engineOptions = {}) {
6366
engine = engineFactory([], engineOptions)
6467
let rule = factories.rule({ conditions, event })
6568
engine.addRule(rule)
@@ -157,14 +160,40 @@ describe('Engine: fact evaluation', () => {
157160
expect(successSpy).to.not.have.been.called()
158161
})
159162

160-
it('emits when complex object paths meet the conditions', async () => {
161-
let complexCondition = conditions()
162-
complexCondition.any[0].path = '.address.occupantHistory[0].year'
163-
complexCondition.any[0].value = 2011
164-
complexCondition.any[0].operator = 'equal'
165-
setup(complexCondition)
166-
await engine.run()
167-
expect(successSpy).to.have.been.calledWith(event)
163+
context('complex paths', () => {
164+
it('correctly interprets "path" when dynamic facts return objects', async () => {
165+
let complexCondition = conditions()
166+
complexCondition.any[0].path = '.address.occupantHistory[0].year'
167+
complexCondition.any[0].value = 2011
168+
complexCondition.any[0].operator = 'equal'
169+
setup(complexCondition)
170+
await engine.run()
171+
expect(successSpy).to.have.been.calledWith(event)
172+
})
173+
174+
it('correctly interprets "path" with runtime fact objects', async () => {
175+
let fact = { x: { y: 1 }, a: 2 }
176+
let conditions = {
177+
all: [{
178+
fact: 'x',
179+
path: '.y',
180+
operator: 'equal',
181+
value: 1
182+
}]
183+
}
184+
let event = {
185+
type: 'runtimeEvent'
186+
}
187+
188+
engine = engineFactory([])
189+
let rule = factories.rule({ conditions, event })
190+
engine.addRule(rule)
191+
engine.on('success', successSpy)
192+
engine.on('failure', failureSpy)
193+
await engine.run(fact)
194+
expect(successSpy).to.have.been.calledWith(event)
195+
expect(failureSpy).to.not.have.been.calledWith(event)
196+
})
168197
})
169198

170199
it('does not emit when complex object paths fail the condition', async () => {

0 commit comments

Comments
 (0)