node package manager
Easy collaboration. Discover, share, and reuse code in your team. Create a free org »

@wizeapps/rule-engine

@wizeapps/rule-engine

Description

Engine to process business rules.

Models

  • WizeActivity: Stores all activities
  • WizeTask: Stores all tasks
  • WizeEventRegistry: Stores event registry

APIs

  • [GET] /api/rule-metadata - Lists all metadata for setting rules
  • [POST] /api/execute-rules - Executes rules
  • [POST] /api/wizeeventregistries - Registers events/hooks for data changes
  • [DELETE] /api/wizeeventregistries/:id - De-registers events

Usage

Installation

npm install --save @wizeapps/rule-engine

Initialize

import wizeRuleEngine from '@wizeapps/rule-engine';
.
.
.
/*
app: koa-app returned from 'const app = createServer({});'
sequelizeSource: sequelize object returned from 'import sequelizeSource from './sources/postgresql';'
*/
wizeRuleEngine(app, sequelizeSource);

Features

import {runRule} from '@wizeapps/rule-engine';

Execute Rule

Example with JSON rules

const fact = {fld1: 'F1', fld2: 100};
const jsonRules = [
  {
    name: 'Rule 2.1: FLD1 is F1 AND FLD2 > 50',
    condition: `this.fld1 === 'F1' && this.fld2 > 50`,
    consequence: `const rule = Object.assign({}, R.rule()); delete rule.condition; delete rule.consequence; delete rule.on;
  this.eligibility = this.eligibility || []; this.eligibility.push(rule);`
  },
  {
    name: 'Rule 2.2: FLD2 >= 50',
    condition: `this.fld2 >= 50`,
    consequence: `const rule = Object.assign({}, R.rule()); delete rule.condition; delete rule.consequence; delete rule.on;
  this.eligibility = this.eligibility || []; this.eligibility.push(rule);`
  },
  {
    name: 'Rule 2.3: FLD2 > 100',
    condition: `this.fld2 > 100`,
    consequence: `const rule = Object.assign({}, R.rule()); delete rule.condition; delete rule.consequence; delete rule.on;
  this.eligibility = this.eligibility || []; this.eligibility.push(rule);`
  }
];
const result = await runRule(jsonRules, fact);

Result

{
  fld1: 'F1',
  fld2: 100,
  result: true,
  eligibility: [
    {name: 'Rule 2.1: FLD1 is F1 AND FLD2 > 50'},
    {name: 'Rule 2.2: FLD2 >= 50'}
  ],
  matchPath: ['Rule 2.1: FLD1 is F1 AND FLD2 > 50', 'Rule 2.2: FLD2 >= 50']
};

Example with PMT function

const fact = {fld1: 'F1', fld2: 100};
const jsonRule = {
  name: 'Rule 1',
  condition: `this.fld1 === 'F1' && this.fld2 > 50`,
  consequence: `const rule = Object.assign({}, R.rule()); delete rule.condition; delete rule.consequence; delete rule.on;
  this.eligibility = this.eligibility || []; this.eligibility.push(rule); this.monthlyfld2 = -1* this.helper.pmt(0.05/12, 5*12,this.fld2,0,0);`
};
const result = await util.runRule(jsonRule, fact);
expect(Number(Number(result.monthlyfld2).toFixed(2))).to.equal(1.89);

Example with actual rules

const fact = {
      fld1: 'F1',
      InnerArray: [{
        fld2: 'Field 2',
        amount: 200,
      }],
    };
const eligibilityRules = [
  {
    name: 'F1 and Amount >= 200',
    condition: function (R) {
      const fld2Query =  this.InnerArray ? this.InnerArray.find(i => i.fld2 === 'Field 2') : null;
      R.when(this.fld1 === 'F1' && (fld2Query ? fld2Query.amount : 0) >= 200);
    },
    consequence: function (R) {
      this.remarks = 'Scenario 1';
      R.stop();
    },
  },
  {
    name: 'Other',
    condition: function (R) {
      const fld2Query =  this.InnerArray ? this.InnerArray.find(i => i.fld2 === 'Field 2') : null;
      R.when(fld2Query);
    },
    consequence: function (R) {
      this.remarks = 'Other';
      R.stop();
    },
  },
];
const result = await util.runActualRule(eligibilityRules, fact);
expect(result.remarks).to.equal('Scenario 1');

Result

{ 
  fld1: 'F1',
  InnerArray: [ { fld2: 'Field 2', amount: 200 } ],
  result: true,
  remarks: 'Scenario 1',
  matchPath: [ 'F1 and Amount >= 200' ] 
};

Test

npm run test

License

MIT License