diff --git a/examples/03-dynamic-facts.js b/examples/03-dynamic-facts.js index e7ddc50..58307d8 100644 --- a/examples/03-dynamic-facts.js +++ b/examples/03-dynamic-facts.js @@ -38,7 +38,7 @@ async function start () { }, { fact: 'account-information', operator: 'in', - value: ['active', 'paid-leave'], // 'status'' can be active or paid-leave + value: ['active', 'paid-leave'], // 'status' can be active or paid-leave path: '$.status' // access the 'status' property of "account-information" }, { fact: 'account-information', @@ -61,18 +61,25 @@ async function start () { * into the engine. The major advantage of this technique is that although there are THREE conditions * requiring this data, only ONE api call is made. This results in much more efficient runtime performance. */ - engine.addFact('account-information', function (params, almanac) { - return almanac.factValue('accountId') - .then(accountId => { - return apiClient.getAccountInformation(accountId) - }) + engine.addFact('account-information', async function (params, almanac) { + try { + const accountId = await almanac.factValue('accountId') + return await apiClient.getAccountInformation(accountId) + } catch (err) { + console.error('Error fetching account-information:', err) + throw err + } }) // define fact(s) known at runtime const facts = { accountId: 'lincoln' } const { events } = await engine.run(facts) - console.log(facts.accountId + ' is a ' + events.map(event => event.params.message)) + if (events.length > 0) { + console.log(facts.accountId + ' is a ' + events.map(event => event.params.message).join(', ')) + } else { + console.log(facts.accountId + ' did not meet conditions for the microsoft-christmas-pto rule') + } } start() diff --git a/package.json b/package.json index cb74404..02b1960 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "clone": "^2.1.2", "eventemitter2": "^6.4.4", "hash-it": "^6.0.0", + "json-rules-engine": "^7.3.1", "jsonpath-plus": "^10.3.0" } } diff --git a/src/engine-default-operators.js b/src/engine-default-operators.js index dfe33f2..3789367 100644 --- a/src/engine-default-operators.js +++ b/src/engine-default-operators.js @@ -3,16 +3,20 @@ import Operator from './operator' const Operators = [] +function isCollection (value) { + return !!(value && (Array.isArray(value) || typeof value === 'string')) +} + Operators.push(new Operator('equal', (a, b) => a === b)) Operators.push(new Operator('notEqual', (a, b) => a !== b)) -Operators.push(new Operator('in', (a, b) => b.indexOf(a) > -1)) -Operators.push(new Operator('notIn', (a, b) => b.indexOf(a) === -1)) +Operators.push(new Operator('in', (a, b) => isCollection(b) && b.indexOf(a) > -1)) +Operators.push(new Operator('notIn', (a, b) => !isCollection(b) || b.indexOf(a) === -1)) -Operators.push(new Operator('contains', (a, b) => a.indexOf(b) > -1, Array.isArray)) -Operators.push(new Operator('doesNotContain', (a, b) => a.indexOf(b) === -1, Array.isArray)) +Operators.push(new Operator('contains', (a, b) => a.indexOf(b) > -1, isCollection)) +Operators.push(new Operator('doesNotContain', (a, b) => a.indexOf(b) === -1, isCollection)) function numberValidator (factValue) { - return Number.parseFloat(factValue).toString() !== 'NaN' + return typeof factValue !== 'object' && !Number.isNaN(Number.parseFloat(factValue)) } Operators.push(new Operator('lessThan', (a, b) => a < b, numberValidator)) Operators.push(new Operator('lessThanInclusive', (a, b) => a <= b, numberValidator))