|
1 | 1 | 'use strict' |
2 | 2 |
|
3 | | -import params from 'params' |
4 | | -import selectn from 'selectn' |
5 | | - |
| 3 | +let params = require('params') |
6 | 4 | let debug = require('debug')('json-rules-engine') |
7 | | -let warn = require('debug')('json-rules-engine:warn') |
| 5 | +let isPlainObject = require('lodash.isplainobject') |
8 | 6 |
|
9 | 7 | export default class Condition { |
10 | 8 | constructor (properties) { |
@@ -61,33 +59,39 @@ export default class Condition { |
61 | 59 | return props |
62 | 60 | } |
63 | 61 |
|
| 62 | + /** |
| 63 | + * Interprets .value as either a primitive, or if a fact, retrieves the fact value |
| 64 | + */ |
| 65 | + async _getValue(almanac) { |
| 66 | + let value = this.value |
| 67 | + if (isPlainObject(value) && value.hasOwnProperty('fact')) { // value: { fact: 'xyz' } |
| 68 | + value = await almanac.factValue(value.fact, value.params, value.path) |
| 69 | + } |
| 70 | + return value |
| 71 | + } |
| 72 | + |
64 | 73 | /** |
65 | 74 | * Takes the fact result and compares it to the condition 'value', using the operator |
66 | | - * @param {mixed} comparisonValue - fact result |
| 75 | + * LHS OPER RHS |
| 76 | + * <fact + params + path> <operator> <value> |
| 77 | + * |
| 78 | + * @param {Almanac} almanac |
67 | 79 | * @param {Map} operatorMap - map of available operators, keyed by operator name |
68 | 80 | * @returns {Boolean} - evaluation result |
69 | 81 | */ |
70 | | - evaluate (comparisonValue, operatorMap) { |
71 | | - // for any/all, simply comparisonValue that the sub-condition array evaluated truthy |
72 | | - if (this.isBooleanOperator()) return comparisonValue === true |
73 | | - |
74 | | - // if the fact has provided an object, and a path is specified, retrieve the object property |
75 | | - if (this.path) { |
76 | | - if (typeof comparisonValue === 'object') { |
77 | | - comparisonValue = selectn(this.path)(comparisonValue) |
78 | | - debug(`condition::evaluate extracting object property ${this.path}, received: ${comparisonValue}`) |
79 | | - } else { |
80 | | - warn(`condition::evaluate could not compute object path(${this.path}) of non-object: ${comparisonValue} <${typeof comparisonValue}>; continuing with ${comparisonValue}`) |
81 | | - } |
82 | | - } |
| 82 | + async evaluate (almanac, operatorMap) { |
| 83 | + if (!almanac) throw new Error('almanac required') |
| 84 | + if (!operatorMap) throw new Error('operatorMap required') |
| 85 | + if (this.isBooleanOperator()) throw new Error('Cannot evaluate() a boolean condition') |
83 | 86 |
|
84 | 87 | let op = operatorMap.get(this.operator) |
85 | 88 | if (!op) throw new Error(`Unknown operator: ${this.operator}`) |
86 | 89 |
|
87 | | - let evaluationResult = op.evaluate(comparisonValue, this.value) |
88 | | - if (!this.isBooleanOperator()) { |
89 | | - debug(`condition::evaluate <${comparisonValue} ${this.operator} ${this.value}?> (${evaluationResult})`) |
90 | | - } |
| 90 | + let rightHandSideValue = await this._getValue(almanac) |
| 91 | + let leftHandSideValue = await almanac.factValue(this.fact, this.params, this.path) |
| 92 | + |
| 93 | + let evaluationResult = op.evaluate(leftHandSideValue, rightHandSideValue) |
| 94 | + debug(`condition::evaluate <${leftHandSideValue} ${this.operator} ${rightHandSideValue}?> (${evaluationResult})`) |
91 | 95 | return evaluationResult |
92 | 96 | } |
93 | 97 |
|
|
0 commit comments