Skip to content

Condition classes #356

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ as failed conditions. (default: false)

`pathResolver` - Allows a custom object path resolution library to be used. (default: `json-path` syntax). See [custom path resolver](./rules.md#condition-helpers-custom-path-resolver) docs.

`conditionConstructor` - The condition constructor class to use when given condition options. Allows for custom conditions to be created by specifying a new condition constructor. (default: new TopLevelConditionConstructor())

### engine.addFact(String id, Function [definitionFunc], Object [options])

```js
Expand Down
2 changes: 2 additions & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ let rule = new Rule(options)

**options.name** : `[Any]` A way of naming your rules, allowing them to be easily identifiable in [Rule Results](#rule-results). This is usually of type `String`, but could also be `Object`, `Array`, or `Number`. Note that the name need not be unique, and that it has no impact on execution of the rule.

**options.conditionConstructor**: [ConditionConstructor] - The condition constructor class to use when given condition options. Allows for custom conditions to be created by specifying a new condition constructor. (default: new TopLevelConditionConstructor())

### setConditions(Array conditions)

Helper for setting rule conditions. Alternative to passing the `conditions` option to the rule constructor.
Expand Down
12 changes: 12 additions & 0 deletions src/almanac.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,18 @@ export default class Almanac {
return factValuePromise
}

/**
* Returns the priority of the fact if one exists.
* @param {string} factId - fact identifier
*/
factPriority (factId) {
const fact = this._getFact(factId)
if (fact === undefined) {
return undefined
}
return fact.priority
}

/**
* Interprets value as either a primitive, or if a fact, retrieves the fact value
*/
Expand Down
156 changes: 0 additions & 156 deletions src/condition.js

This file was deleted.

62 changes: 62 additions & 0 deletions src/condition/all-condition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use strict'

import Condition from './condition'
import prioritizeAndRun from './prioritize-and-run'

export default class AllCondition extends Condition {
constructor (properties, conditionConstructor) {
super(properties)
if (!Object.prototype.hasOwnProperty.call(properties, 'all')) {
throw new Error('AllCondition: constructor "all" property required')
}
if (!Array.isArray(properties.all)) {
throw new Error('AllCondition: constructor "all" must be an array')
}
this.all = properties.all.map((c) => conditionConstructor.construct(c))
this.operator = 'all'
// boolean conditions always have a priority; default 1
this.priority = this.priority || 1
}

/**
* Converts the condition into a json-friendly structure
* @param {Boolean} stringify - whether to return as a json string
* @returns {string,object} json string or json-friendly object
*/
toJSON (stringify = true) {
const props = super.toJSON(false)
props.all = this.all.map((c) => c.toJSON(false))
if (stringify) {
return JSON.stringify(props)
}
return props
}

/**
* Takes the fact result and compares it to the condition 'value', using the operator
* LHS OPER RHS
* <fact + params + path> <operator> <value>
*
* @param {Almanac} almanac
* @param {Map} operatorMap - map of available operators, keyed by operator name
* @returns {Boolean} - evaluation result
*/
evaluate (almanac, operatorMap, conditionMap) {
return Promise.all([
prioritizeAndRun(this.all, 'all', almanac, operatorMap, conditionMap),
super.evaluate(almanac, operatorMap, conditionMap)
]).then(([result, evaluateResult]) => {
evaluateResult.result = result.result
evaluateResult.all = result.conditions
evaluateResult.operator = 'all'
return evaluateResult
})
}

skip () {
const skipResult = super.skip()
skipResult.all = this.all.map((c) => c.skip())
skipResult.operator = 'all'
return skipResult
}
}
62 changes: 62 additions & 0 deletions src/condition/any-condition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use strict'

import Condition from './condition'
import prioritizeAndRun from './prioritize-and-run'

export default class AnyCondition extends Condition {
constructor (properties, conditionConstructor) {
super(properties)
if (!Object.prototype.hasOwnProperty.call(properties, 'any')) {
throw new Error('AnyCondition: constructor "any" property required')
}
if (!Array.isArray(properties.any)) {
throw new Error('AnyCondition: constructor "any" must be an array')
}
this.any = properties.any.map((c) => conditionConstructor.construct(c))
this.operator = 'any'
// boolean conditions always have a priority; default 1
this.priority = this.priority || 1
}

/**
* Converts the condition into a json-friendly structure
* @param {Boolean} stringify - whether to return as a json string
* @returns {string,object} json string or json-friendly object
*/
toJSON (stringify = true) {
const props = super.toJSON(false)
props.any = this.any.map((c) => c.toJSON(false))
if (stringify) {
return JSON.stringify(props)
}
return props
}

/**
* Takes the fact result and compares it to the condition 'value', using the operator
* LHS OPER RHS
* <fact + params + path> <operator> <value>
*
* @param {Almanac} almanac
* @param {Map} operatorMap - map of available operators, keyed by operator name
* @returns {Boolean} - evaluation result
*/
evaluate (almanac, operatorMap, conditionMap) {
return Promise.all([
prioritizeAndRun(this.any, 'any', almanac, operatorMap, conditionMap),
super.evaluate(almanac, operatorMap, conditionMap)
]).then(([result, evaluateResult]) => {
evaluateResult.any = result.conditions
evaluateResult.operator = 'any'
evaluateResult.result = result.result
return evaluateResult
})
}

skip () {
const skipResult = super.skip()
skipResult.any = this.any.map((c) => c.skip())
skipResult.operator = 'any'
return skipResult
}
}
Loading