Code Monkey home page Code Monkey logo

json-rules-engine's Introduction

json-rules-engine js-standard-style Build Status

npm version install size npm downloads

A rules engine expressed in JSON

Synopsis

json-rules-engine is a powerful, lightweight rules engine. Rules are composed of simple json structures, making them human readable and easy to persist.

Features

  • Rules expressed in simple, easy to read JSON
  • Full support for ALL and ANY boolean operators, including recursive nesting
  • Fast by default, faster with configuration; priority levels and cache settings for fine tuning performance
  • Secure; no use of eval()
  • Isomorphic; runs in node and browser
  • Lightweight & extendable; 17kb gzipped w/few dependencies

Installation

$ npm install json-rules-engine

Docs

Examples

See the Examples, which demonstrate the major features and capabilities.

Basic Example

This example demonstrates an engine for detecting whether a basketball player has fouled out (a player who commits five personal fouls over the course of a 40-minute game, or six in a 48-minute game, fouls out).

const { Engine } = require('json-rules-engine')


/**
 * Setup a new engine
 */
let engine = new Engine()

// define a rule for detecting the player has exceeded foul limits.  Foul out any player who:
// (has committed 5 fouls AND game is 40 minutes) OR (has committed 6 fouls AND game is 48 minutes)
engine.addRule({
  conditions: {
    any: [{
      all: [{
        fact: 'gameDuration',
        operator: 'equal',
        value: 40
      }, {
        fact: 'personalFoulCount',
        operator: 'greaterThanInclusive',
        value: 5
      }]
    }, {
      all: [{
        fact: 'gameDuration',
        operator: 'equal',
        value: 48
      }, {
        fact: 'personalFoulCount',
        operator: 'greaterThanInclusive',
        value: 6
      }]
    }]
  },
  event: {  // define the event to fire when the conditions evaluate truthy
    type: 'fouledOut',
    params: {
      message: 'Player has fouled out!'
    }
  }
})

/**
 * Define facts the engine will use to evaluate the conditions above.
 * Facts may also be loaded asynchronously at runtime; see the advanced example below
 */
let facts = {
  personalFoulCount: 6,
  gameDuration: 40
}

// Run the engine to evaluate
engine
  .run(facts)
  .then(({ events }) => {
    events.map(event => console.log(event.params.message))
  })

/*
 * Output:
 *
 * Player has fouled out!
 */

This is available in the examples

Advanced Example

This example demonstates an engine for identifying employees who work for Microsoft and are taking Christmas day off.

This demonstrates an engine which uses asynchronous fact data. Fact information is loaded via API call during runtime, and the results are cached and recycled for all 3 conditions. It also demonstates use of the condition path feature to reference properties of objects returned by facts.

const { Engine } = require('json-rules-engine')

// example client for making asynchronous requests to an api, database, etc
import apiClient from './account-api-client'

/**
 * Setup a new engine
 */
let engine = new Engine()

/**
 * Rule for identifying microsoft employees taking pto on christmas
 *
 * the account-information fact returns:
 *  { company: 'XYZ', status: 'ABC', ptoDaysTaken: ['YYYY-MM-DD', 'YYYY-MM-DD'] }
 */
let microsoftRule = {
  conditions: {
    all: [{
      fact: 'account-information',
      operator: 'equal',
      value: 'microsoft',
      path: '$.company' // access the 'company' property of "account-information"
    }, {
      fact: 'account-information',
      operator: 'in',
      value: ['active', 'paid-leave'], // 'status' can be active or paid-leave
      path: '$.status' // access the 'status' property of "account-information"
    }, {
      fact: 'account-information',
      operator: 'contains', // the 'ptoDaysTaken' property (an array) must contain '2016-12-25'
      value: '2016-12-25',
      path: '$.ptoDaysTaken' // access the 'ptoDaysTaken' property of "account-information"
    }]
  },
  event: {
    type: 'microsoft-christmas-pto',
    params: {
      message: 'current microsoft employee taking christmas day off'
    }
  }
}
engine.addRule(microsoftRule)

/**
 * 'account-information' fact executes an api call and retrieves account data, feeding the results
 * 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
 * and fewer network requests.
 */
engine.addFact('account-information', function (params, almanac) {
  console.log('loading account information...')
  return almanac.factValue('accountId')
    .then((accountId) => {
      return apiClient.getAccountInformation(accountId)
    })
})

// define fact(s) known at runtime
let facts = { accountId: 'lincoln' }
engine
  .run(facts)
  .then(({ events }) => {
    console.log(facts.accountId + ' is a ' + events.map(event => event.params.message))
  })

/*
 * OUTPUT:
 *
 * loading account information... // <-- API call is made ONCE and results recycled for all 3 conditions
 * lincoln is a current microsoft employee taking christmas day off
 */

This is available in the examples

Debugging

To see what the engine is doing under the hood, debug output can be turned on via:

Node

DEBUG=json-rules-engine

Browser

// set debug flag in local storage & refresh page to see console output
localStorage.debug = 'json-rules-engine'

Related Projects

https://github.com/vinzdeveloper/json-rule-editor - configuration ui for json-rules-engine:

rule editor 2

License

ISC

json-rules-engine's People

Contributors

andycoopcode avatar arpitbatra123 avatar bertday avatar brianphillips avatar cachecontrol avatar chamm-stripe avatar chris-pardy avatar feenst avatar hartzis avatar hemang-thakkar avatar ilanskogan avatar juan2357 avatar knalbandianbrightgrove avatar leocabrallce avatar mahirk avatar mattcopenhaver avatar ozanerturk avatar professorkolik avatar saschadewaal avatar saurabhshri avatar shivajivarma avatar valyouw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

json-rules-engine's Issues

Failure Callback

Is there a way to determine, on failure, which rule/condition failed?

Almanac not resetting with each run()

I've come across an issue in which I'm using a single Engine instance to run multiple times with each run using different facts and expecting each run to be using a clean Almanac, but it appears the Almanac is reused or caching previous run() facts.

Reading the documentation for the Almanac I expected that facts added in the first run would not exist ("DNE") in subsequent runs.

Every time engine.run() is invoked, a new almanac is instantiated.

To recreate the issue I'm seeing, I modified the test for verifying independent runs in json-rules-engine (engine-run.test.js), From documentation, I expected that the 'age' fact would have activated only 1 time across the 6 runs, since the last 3 runs are for fact 'shoesize' and don't include an 'age' fact. That being the second proof of the Almanac caching across runs, because this test fails to throw exceptions for Undefined fact 'age' over the last 3 runs.

describe('SLMMM: independent runs', () => {
it('treats each run() independently', async () => {
await Promise.all([0, 0, 0, 30].map((age) => engine.run({age})))
await Promise.all([7, 9, 5].map((shoesize) => engine.run({shoesize})))
expect(eventSpy).to.have.been.calledOnce
})
})

Instead, the test fails because there are 4 activations instead of 1.

1 failing

  1. Engine: run SLMMM: independent runs treats each run() independently:
    expected spy to have been called exactly once, but it was called 4 times
    spy({ type: "generic" }, [Almanac] { factMap: [Map] { }, factResultsCache: [Map] { } }) at emitTwo (events.js:106:13)
    spy({ type: "generic" }, [Almanac] { factMap: [Map] { }, factResultsCache: [Map] { } }) at emitTwo (events.js:106:13)
    spy({ type: "generic" }, [Almanac] { factMap: [Map] { }, factResultsCache: [Map] { } }) at emitTwo (events.js:106:13)
    spy({ type: "generic" }, [Almanac] { factMap: [Map] { }, factResultsCache: [Map] { } }) at emitTwo (events.js:106:13)
    AssertionError: expected spy to have been called exactly once, but it was called 4 times

Feature request - Decision Tables

@CacheControl I was wondering if this rule engine can support decision tables.

What do I mean by that:
So a decision table is composed of many rules that differ usually by one or more conditions. So, for example, I will create a decision table to implement this logic:

Colour - Price
Blue - 10
Red - 11
Green - 13
Yellow - 14
Pink - 8
White - 13
Black - 20

So, you will read it like this, if a color is "Blue" then the price is $10. So instead of creating 7 separate rules, I will only create one rule, a decision table rule. Let me know what do you think.

Nested facts values

Hi, this is a good library. But we need nested fact values, o use objects as facts, can be done?

Example:

var facts = {
test: {
a: "a",
b: "true"
},
displayMessage: true
}

rule.setConditions({
any: [{
fact: 'test.b',
operator: 'equal',
value: true
}]
})

Support IE8

Thank you for the great solution!

Is it possible to support IE8?

The issue is

getters & setters can not be defined on this javascript engine

Provision of a function/method while defining rules

@CacheControl So consider we need to have a rule which needs to check whether the volume of an item is bigger than say 100 and it takes three arguments:

  1. Length
  2. Breadth
  3. Height

How can we write this kind of rule that needs to multiply the three arguments to check the condition?

Rule returning multiple events

Hello,

thanks for this great lib! πŸ‘

Is there a reason why the rule can't return multiple events when it succeed ?

Details about failure

Hey there,

Thanks for this great lib.

Is there anyway to have details about condition failure.
I would like to know precisely which fact is failing in a large set.

Question: Returning the custom added param in successes

Hi
we have the number of a rule set for single questions like below

`conditions:

{
any: [{
    all: [{
      fact: 'gameDuration',
      operator: 'equal',
      value: '1',
factResult: [
{
"action": "do-something for gameDuration show ",
// i can add my custom params
}]
  },
    {
      fact: 'personalFoulCount',
      operator: 'equal',
      value: '2',
factResult: [
{
"action": "do-something for personalFoulCount show",
}]
    }],
  },
  {
     all: [{
      fact: 'gameDuration',
      operator: 'Equal',
      value: '2',
factResult: [
{
"action": "do-something for gameDuration hide",
}]
    },
      {
      fact: 'personalFoulCount',
      operator: 'equal',
      value: '4',
factResult: [
{
"action": "do-something for personalFoulCount hide",
}]
    }]
  },
{
     all: [{
      fact: 'gameDuration',
      operator: 'Equal',
      value: '8',
factResult: [
{
"action": "do-something for gameDuration hide show",
}]
    },
      {
      fact: 'personalFoulCount',
      operator: 'equal',
      value: '6',
factResult: [
{
"action": "do-something for gameDuration show hide",
}]
    }]
  },
]
  },
event: {
type: 'json rule',
params: {
message: 'json rule example'
}
}`

and

let facts = { gameDuration: '2', personalFoulCount: '4' }

the rule will success for given facts

on success, i want the success "factResult" separately. is there any way we can access the succeed custom param.we tried with below example
https://github.com/CacheControl/json-rules-engine/blob/master/examples/09-rule-results.js
but could not able to succeed.

Problem with JSON serialization of rule result

Summary:

I have an issue when serializing the rule result, namely the conditions inside this result.

Version

2.0.0

Example code

  let engine = new Engine();
  engine.addRule({
    "priority": 4,
    "event": {
      "type": "something"
    },
    "conditions": {
      "any": [{
        "fact": "data",
        "path": ".age",
        "operator": "lessThan",
        "value": 18
      }]
    }
  });
  engine.on("success", (event: any, almanac: any, result: any) => {
    console.log(JSON.stringify(result))
  })
  engine.run({
    data: {
      age: 16
    }
  });

The console will show:

{
	"conditions": "{\"priority\":1,\"any\":[\"{\\\"operator\\\":\\\"lessThan\\\",\\\"value\\\":18,\\\"fact\\\":\\\"data\\\",\\\"path\\\":\\\".age\\\"}\"]}",
	"event": {
		"type": "something"
	},
	"priority": 4,
	"result": true
}

If I look into the debugger it looks fine:
image

Cause

I did not really dig into this, but based solely on the debugger contents, I guess you "reused" the Condition class for the rule results (at least of the conditions inside it). The custom serialization of this class is most likely causing the issue. IMO, you should make a different "class" for the rule results (condition) object.

Score on Rules

Call it a "score" or "weight" or both, but would it be interesting to others using json-rules-engine to obtain a score on the number of success/failed events based on a score?

That is if Rule A, and B pass but Rule C fails a score can be calculated in the Events definition or better the Conditions?

I've worked around this issue to some extent, but I'd be more motivated if others see this need and are willing to participate and advance a sort of weight/score based solution where we can push this module towards features for machine learning. Yet I understand that json-rules-engine is a rules engine, I guess I'm asking if our community/contributors see a layer above or features in json-rules-engine. See this as a request for features and/or input please.

Ignoring the fact condition when the fact is not passed in

Hi:

I would have liked the rule engine to ignore the fact condition if it is in "ANY" when the fact is not passed in, e.g.,

If my facts are these:

let facts = {
    gameDuration: 40
  };

And my rule is:

engine.addRule({
    conditions: {
      any: [{
        fact: 'personalFoulCount',
        operator: 'greaterThanInclusive',
        value: 5
      },
        {
          fact: 'gameDuration',
          operator: 'equal',
          value: 40
        }]
    },
    event: {  // define the event to fire when the conditions evaluate truthy
      type: 'fouledOut',
      params: {
        message: 'Player has fouled out!'
      }
    }
  });

I would have preferred the rule engine would not have errored out and ignore the fact that personalFoulCount is not there as it was in ANY condition clause.

Incomplete ruleResult.conditions, empty almanac in Node-Red

Hi there... I tried and loved your json rules engine in node.js, so I tried installing it into the node-red environment using:

functionGlobalContext: {
        rulesEngine:require("json-rules-engine")
 }

Using a function node, I got the engine processing rules immediately... but strange things happen after the event has finished processing. Although it evaluates all the conditions accurately and fires a success or failure event, ruleResult.conditions received by the callback function is a strangely coded string (as though it's been double-stringified) and incomplete (it carries no evaluation status info, just the original conditions). Additionally, the almanac object is empty.

This is what it looks like:

conditions: "{"priority":1,"all":["{\"operator\":\"greaterThanInclusive\",\"value\":43,\"fact\":\"brian\"}","{\"operator\":\"greaterThanInclusive\",\"value\":23,\"fact\":\"sally\"}"]}"
Obviously this lack of information makes it hard to debug rules. Any ideas?

Failed compile script 'babel --stage 1 -d dist/ src/'

After installing json-rules-engine from npm, attempted to install the --dev dependencies in order to run tests (i.e. npm test). Receiving these errord from npm install --dev

INITIAL ERROR
> babel --stage 1 -d dist/ src/

src/ doesn't exist

npm ERR! Windows_NT 10.0.10586
npm ERR! argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "run" "compile"
npm ERR! node v6.2.1
npm ERR! npm v3.9.3
npm ERR! code ELIFECYCLE
npm ERR! [email protected] compile: babel --stage 1 -d dist/ src/
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the [email protected] compile script 'babel --stage 1 -d dist/ src/'.

npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the json-rules-engine package,
npm ERR! not with npm itself.

FOLLOWED BY ERROR
npm WARN optional Skipping failed optional dependency /chokidar/fsevents:
npm WARN notsup Not compatible with your operating system or architecture: [email protected]
npm WARN [email protected] requires a peer of webpack@1 || ^2.1.0-beta but none was installed.
npm ERR! Windows_NT 10.0.10586
npm ERR! argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "install" "--only=dev"
npm ERR! node v6.2.1
npm ERR! npm v3.9.3
npm ERR! code ELIFECYCLE
npm ERR! [email protected] prepublish: npm run compile
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] prepublish script 'npm run compile'.

LOG
npm-debug.txt

Is there any operator for checking the nested JSON facts.

Let us say, we have the following JSON object. It is like looping through the nested JSON payload and looking for a value match. Here in the below example, indexes being hard-coded, which I wanted to avoid.

JSON Fact Payload :

{
"ObjectA": {
"ObjectA1": {
"dt": "2017-01-10T16:45:20.071Z",
"ObjectA1Array": [
{
"var1": "value1",
"ObjectA1ArrayObject1": {"var2": "value2"}
"ObjectA1ArrayObject2": {
"ObjectA1ArrayObject2Array": [
{
"var3": "value3",
"ObjectA1ArrayObject2ArrayObject1": {"var4": "value4"}
},
{
"var4": "value4",
"ObjectA1ArrayObject2ArrayObject2": {"var5": "value5"}
}
]
}
},
{
"var6": "value6",
"ObjectA1ArrayObject3": {"var7": "value"}
}
]
}
}
}

let exampleRule = {
conditions: {
all: [{
fact: 'JSONPayLoad',
operator: 'equal',
value: 'value1',
path: '.ObjectA.ObjectA1.ObjectA1Array[0].var1'
}, {
fact: 'JSONPayLoad',
operator: 'in',
value: ['value5', 'value10'],
path: '.ObjectA.ObjectA1.ObjectA1Array[1].var5'
}, {
fact: 'JSONPayLoad',
operator: 'greaterThanInclusive',
value: 'value5',
path: '.ObjectA.ObjectA1.ObjectA1Array[0].ObjectA1ArrayObject2.ObjectA1ArrayObject2Array[1].ObjectA1ArrayObject2ArrayObject2.var5'
},
event: {
type: 'something',
params: {
message: 'Some message'
}
},
priority: 100
}

Dynamic values inside rules

I am trying to do the following. Please let me know if its possible in any other way.

{
conditions:{
...
..
...
}
event: {
type: sendEmail,
params: {
from_email: $fact.from_email,
subject: "Test subject $fact.subject"
}

I want to place the values from the fact to the rules's event params dynamically.
I am ok with the solution having placeholders too.

Thanks in advance.

write condition: (fact1.value > (fact2.value + fact3.value))

Hi! First of all, thank you for this library! But I'm stuck at a very basic step of rules implementation.

let's say we have the following rule that is the equivalent of if (fact1.value > fact2.value) (fact comparison as seen in exemples)

let facts = {
	"fact1" : {
		"value": 3
	},
	"fact2" : {
		"value": 2
	},
	"fact3" : {
		"value": 2
	}
}

let rule = {
  conditions: {
    all: [{
      fact: 'fact1',
      path: '.value',
      operator: 'greaterThan',
      value: {
        fact: 'fact2',
        path: '.value',
      }
    }]
  },
  event: { type: 'fact1-greaterthan-fact2' }
}

But how to include fact3.value to write the following condition: (fact.fact1.value > (fact.fact2.value + fact.fact3.value)) ?

If it is supported it would be great to add an exemple to the fact-comparison exemple file.

Thank you for your support

"allowUndefinedFacts" doesn't work for dynamic facts

@CacheControl

So consider I have a rule like this:

let factDimensionsCheck = new Fact('fact-dimensions-check', function (params, almanac) {
  return Promise.all([almanac.factValue(params.fact1), almanac.factValue(params.fact2)])
    .then(factValues => {
      let fact1Value = factValues[0];
      let fact2Value = factValues[1];
      let operator = params.operator; // "greaterThan"
      // each engine stores a registry of operators, which can be called to test one value against another
      // just make sure to stick to the official operator names inside "params"; "equal", "notEqual", etc
      return new Engine().operators.get(operator).evaluate(fact1Value, fact2Value);// returns true
    })
});

let ruleDimensionsCheck = new Rule({
  conditions: {
    all: [{
      fact: 'fact-dimensions-check',
      operator: 'equal',
      value: true,
      params: {
        fact1: '/data/consitem/length',
        fact2: '/data/consitem/width',
        operator: 'greaterThan'
      }
    }]
  },
  event: {  }
...

And I am passing only one fact say "/data/consitem/length". I get an error like this on the console that the other fact is missing:

(node:14804) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: Undefined fact: /data/consitem/width

This is possibly coming from this statement for fact2 which was not passed:

almanac.factValue(params.fact2)

Expected Results:
I am expecting that rule should not fire without throwing any warnings or error for facts being missing.

SyntaxError: Unexpected token import

I get this error "SyntaxErrorL: Unexpected token import" in node.js v7.7.4 and v6.10.1 while running. How do you run this? Would be useful to add this information the readme

Is rule chaining supported?

I have spent a few hours coming to understand your engine and I really like what I've seen so far. However, I do not understand if and how rule chaining works. That is, how do I trigger rules based on the results from other rules?

Question: How do I specify a rule which compares two facts?

Ex: Say the facts are
{ "avg_def_density_tolerance_hit": "yes", "tot_developers": 900, "tot_defects": 1003, "open_stories": 12 }
And I want to write a rule that will pass if tot_defects > open_stories

Suggestion: If this is not easy to implement or you'd rather not support it, please consider enhancing the addOperator method to pass in the complete rule and all the facts: that way others can add the logic necessary.

Async actions on a rule's onSuccess?

Hi,
I noticed that promises were not being observed on an onSuccess of rule callback. Seems this way in the code as well. Is there a workaround to this?

Also, what I may be struggling with is the approach to using rules-engines in general and wanting the truthy state of a rule to fire off an action and update the event parameters with the results. Is there a better approach to this?

    {
        conditions: {
            all: [
                {
                    fact: 'result',
                    path: '.parameters.email',
                    operator: 'notEqual',
                    value: ''
                }
            ]
        },
        event: { },
        onSuccess: ((event, almanac) => {     
            return almanac.factValue('result')
                .then((result) => {
                    // Do something async. Rule engine completes run before this action completes.
                })
        })
    }

Thanks,
Steve

How to save dynamic facts into database

@CacheControl @slmmm
As part of my project, I have to save rules and their dynamic facts in the database. I am able to save and retrieve the rules OK from the database (as they are JSON), wondering how can I do this when my fact is a javascript function like this:

let factDimensionsCheck = new Fact('fact-dimensions-check', function (params, almanac) { return Promise.all([almanac.factValue(params.fact1), almanac.factValue(params.fact2)]) .then(factValues => { let fact1Value = factValues[0]; let fact2Value = factValues[1]; let operator = params.operator; return engine.operators.get(operator).evaluate(fact1Value, fact2Value); }) });

license missing

I've looked through the tree here and don't see a license for this. My legal department is pretty strict and I'd love to use this in my next project.

synchronous run function?

Can you please add a synchronous run function? I am not making any I/O calls and everything is in memory in node so your parallel processing provides no benefit and it greatly complicates implementation.
Or provide me with access your github and I will do it.

Returning results of a listener on run?

I was wondering if there was a way to pass the results of a listener on engine.run? So if I did something like this:

    engine.on('fouledOut', (params) => {
        // Great!
        const fouledOutDist = 20;
        return { fouledOut: fouledOutDist }
    });
    return engine
        .run(facts)
        .then((events) => {
            // I would want to get { fouledOut: 20 } to be accessed and pushed through the promise
            return events.map(event => console.log(event.params.message))
        });    

Any way to do this idiomatically within the framework?

Steve

Question: How do I stop engine after first matched rule?

We have large number of rule set say 150-200, All of them contains priority for execution.
We only want to retrieve only highest priority rule event, Thats why we want to run the entire rule engine and want to have functionality like findFirst.

Is there a way to achieve this?

troubles to run basic.js example

I'm farirly new to node world but I'm facing troubles running the basic.js example. I'm sure I'm just looking in the wrong direction.

I've followed the script from travis (https://travis-ci.org/CacheControl/json-rules-engine) in order to copy-cat the setup of the json-rules-engine. I've successfully ran into unit test with success.

however, how I could run basic.js ? if I go in ./examples folder and run node basic.js. I'm getting following message
image

any idea or direction to look for ?
many thanks.

Missing license

I'm evaluating rules engine to include in my application. What software license does your project fall under?

Cannot find module 'babel-core/register'

Attempting to run basic example of Rule Engine in a simple express server app, but unable to use json-rules-engine after npm install.

At first require
const Engine = require('json-rules-engine');

Getting error

Error: Cannot find module 'babel-core/register'
at Function.Module._resolveFilename (module.js:440:15)

Looking at stacktrace, requesting babel-core/register from json-rules-engine index.js
image

To work-around error, went into json-rules-engine module directory and did an npm install --dev. But don't believe this is intended resolution.

Possible to run rules against dynamic values?

We are looking into using your library for a product hierarchy. We have the need to run a rule based on a dynamic quantity value, where the quantity of a child product cannot exceed the existing quantity of a parent product. I'm not seeing anything in your examples where value is dynamic. Is this possible?

Thanks!

Optional condition value

Hello,

I have some operators that doesn't require a condition value (EXISTS, NOT EXISTS)

Could it be made optional ? I can pass value: null but would be better to just not pass it at all. πŸ‘

Synchronous run

Hi! I'm currently using the engine and it looks really good so far, congratulations!

I have a couple of questions related to the design, is this using Promises for any specific reason ? I did a quick look through the code but I couldn't find any I/O call/nextTick/timer usage,

I also saw you response on #14, and be glad to help in case you want to move forward to do a sync approach but adding a Promised interface for run method.

Thanks!

Returning both successes and failures

The README says that "// run() returns events with truthy conditions" in this example:

// Run the engine to evaluate
engine
  .run(facts)
  .then(events => { // run() returns events with truthy conditions
    events.map(event => console.log(event.params.message))
  })

What about when the result is false?

What I am trying to achieve is something like:

// Run the engine to evaluate
engine
  .run(facts)
  .then(events => { 
    return true // return false
  })

I want my function to return true if the conditions are met, false if they are not.
What's the way to achieve this?

Slow performance?

I have integrated json-rules-engine with a project I am working on and the performance seems much slower than I would expect. With 37 rules, it takes about 49ms to execute. The rules are very simple - simple regular expression checks. We are expecting to load 100s of rules and were hoping to have it execute more in the range of 10ms or so but we can't even hit that with a small number of rules. I haven't looked at the code yet, but I wanted to check and see what kind of performance is expected and if there are known performance issues in the code that could be improved. If there are known performance issues, I might take a stab at making some improvements. Thanks

Rule Success/Failure Callback

Currently I'm getting the complete rule object back as part of rule failurecallback but for rule successCallback, I only get the event object. Is it possible to get the full rule object back as part of the successCallback.

Give name to a rule (and may be an id??)

@CacheControl Is there a way we can give names to our rules? So for example:

let volumeRule = new Rule({
  **name: myVolumeRule  //----- Note the name here** 
  conditions: {
    all: [{
      fact: 'volume',
      operator: 'greaterThanInclusive',
      value: 100
    }]
  },
  event: {  // define the event to fire when the conditions evaluate truthy
    type: 'fouledOut',
    params: {
      message: 'Player has fouled out!'
    }
  }
  ,
  priority: 100
});

So the reason for this is that when you are writing 100s of rules, you may want to give them name to identify which rule you are talking about. Also, if we are saving them into a database, we can save them in rows and identified by their names. Its helpful when you are managing a large number of rules.

Want to get in contact

Hey Cache,

Can't find any other way to DM you so I'm logging an issue Β―_(ツ)_/Β―. I'm building my own version of a json-rules-engine (https://github.com/dlombardi/rules_engine) that's very much inspired by yours. It's mainly for an educational purpose but I'm hoping to find a niche for it through dynamic forms based on rules. I was hoping to pick your brain a bit on the design philosophy behind the json-rules-engine especially related to the almanac, but also other things. Sorry again to do this through an issue. If theres anytime we can have a convo It would certainly help me grow as a developer and would be very much appreciated. I've learned a lot by looking at your code already.

fact to evaluate expression

I want to be able to do math in a fact. Adding to the trickiness the expression variables have different path. eg: i have object obj that has 2 sub objects a and b and i want to do a fact: obj.a.x * obj.b.y.

Is this possible with custom fact?

Can we have new operator forEach?

It would be great if we can check facts by looping through inner array.

Sample use case, where student should score greaterThanInclusive of 48 in all subjects.

{
	conditions: {
		any: [{
				all: [{
						fact: 'student.age',
						operator: 'equal',
						value: 40
					}, {
						fact: 'student.name',
						operator: 'greaterThanInclusive',
						value: 'john'
					}
				]
			}, {
				forEach: {
					array: 'student.subjects',
					as: 'subject'
					all: [{
							fact: 'subject.mark',
							operator: 'greaterThanInclusive',
							value: 48
						}, {
							fact: 'subject.name',
							operator: 'equal',
							value: 'maths'
						}
					]
				}

			}
		]
	}
}

it's just a thought ...

Object hash version memory leak

The object-hash version included your package has a known memory leak issue with new Node versions.
puleos/object-hash#39

We have seen performance drops and possible root cause of our app crashing using your rules engine crash our app. Any possibility to update the dependency version for object-hash?

Adding custom operators

It would be nice to add custom operators to engine that can be used by the rules. For instance I need to check if my fact value as date is with in some range.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.