Skip to content

Commit

Permalink
Merge tag 'v1.4.4' of 10.73.97.24:oecloud.io/feel into 1.x-release
Browse files Browse the repository at this point in the history
This release fixes github issue 13, and also a bug in the decision table execution.
  • Loading branch information
vamsee committed Jun 20, 2019
2 parents 4547250 + 661a9f8 commit 7135438
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 13 deletions.
2 changes: 1 addition & 1 deletion dist/feel-ast-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ module.exports = function (ast) {
return fnMeta(...[...values, args.context]);
}
log.debug(options, 'FunctionInvocationNode - Processing in-built function');
return fnMeta(Object.assign({}, args.context, args.kwargs, { graphName: args.graphName }), values);
return fnMeta(Object.assign({}, args.context, args.kwargs, { graphName: args.graphName, decisionMap: args.decisionMap }), values);
});

const processDecision = (fnMeta) => {
Expand Down
6 changes: 4 additions & 2 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ gulp.task('clean:src:feel', () => gulp.src('./src/feel.pegjs', {
})
.pipe(clean()));

gulp.task('generate:parser',['clean:dist:feel'], () => gulp.src('src/feel.pegjs')
gulp.task('generate:parser',['clean:dist:feel', 'concat:feel'], () => gulp.src('src/feel.pegjs')
.pipe(peg({
format: 'commonjs',
cache: true,
Expand Down Expand Up @@ -142,11 +142,13 @@ gulp.task('test-ci-html', ['pre-test-ci'], function () {

gulp.task('build', ['initialize:feel', 'clean:src:feel', 'concat:feel', 'clean:temp']);

gulp.task('default', ['build', 'generate', 'mocha']);
gulp.task('default', ['build', 'generate:parser', 'mocha']);

gulp.task('watch', () => {
gulp.watch('./grammar/*', ['build']);
gulp.watch('./src/*.pegjs',['generate:parser']);
gulp.watch('./src/*.js', ['dist:feel:ast', 'dist:feel:ast:parser']);
gulp.watch('./utils/**/*.js', ['utils:lint']);
});

gulp.task('dist', ['build', 'dist:feel:ast', 'dist:feel:ast:parser', 'generate:parser']);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "js-feel",
"version": "1.4.3",
"version": "1.4.4",
"description": "FEEL(Friendly Enough Expression Language) based on DMN specification 1.1 for conformance level 3",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/feel-ast-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ module.exports = function (ast) {
return fnMeta(...[...values, args.context]);
}
log.debug(options, 'FunctionInvocationNode - Processing in-built function');
return fnMeta(Object.assign({}, args.context, args.kwargs, { graphName: args.graphName }), values);
return fnMeta(Object.assign({}, args.context, args.kwargs, { graphName: args.graphName, decisionMap: args.decisionMap }), values);
});

const processDecision = (fnMeta) => {
Expand Down
4 changes: 4 additions & 0 deletions test/data/sample2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"final dec": "decision table(input expression list : ['test1','name'],outputs : \"outstring\",input values list : [[],[]],output values : [[]],rule list : [['\"Hiii\"','\"Ram\"','\"Hi ram\"'],['\"Hi\"','\"Rajesh\"','\"Hi rajesh\"']],id : 'final dec',hit policy : 'U')",
"test1": "decision table(input expression list : ['msg'],outputs : \"out\",input values list : [[]],output values : [[]],rule list : [['\"Hi\"','\"Hiii\"'],['\"H\"','\"Hi\"']],id : 'test1',hit policy : 'U')"
}
31 changes: 31 additions & 0 deletions test/date-time-expression/misc-date-and-time-related-tests.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
*
* ©2016-2017 EdgeVerve Systems Limited (a fully owned Infosys subsidiary),
* Bangalore, India. All Rights Reserved.
*
*/
const chalk = require('chalk');
const chai = require('chai');
const FEEL = require('../../dist/feel');

const expect = chai.expect;

describe(chalk.blue('misc date-and-time related tests...'), () => {
it('should subtract months from last day of month correctly', (done) => {
debugger;
const text = 'date(date("2018-07-31") - duration("P1M")) = date("2018-06-30")';
try {
const parsedGrammar = FEEL.parse(text);
parsedGrammar.build()
.then((result) => {
expect(result).to.be.true;
done();
}).catch((err) => {
done(err);
});
} catch (err) {
done(err);
}
});

});
60 changes: 60 additions & 0 deletions test/decision-service/decision-table-tests2.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
*
* ©2016-2017 EdgeVerve Systems Limited (a fully owned Infosys subsidiary),
* Bangalore, India. All Rights Reserved.
*
*/

var chai = require('chai');
var expect = chai.expect;
var fs = require('fs');
var { createDecisionGraphAST, executeDecisionService } = require('../../index')().decisionService;

var readJSON = (file) => JSON.parse(fs.readFileSync(file, { encoding: 'utf8' }));

describe('decision table exposed in a service...', function () {
it('should properly execute a decision table with is exposed through a service and one of its input expression references something in the graph', done => {
var decisionMap = readJSON('./test/data/sample2.json');
var ast = createDecisionGraphAST(decisionMap);
var payload = {
"name": "Ram",
"msg": "Hi"
}

executeDecisionService(ast, 'final dec', payload, 'foo')
.then(result => {
expect(result).to.be.object;
expect(result).to.have.property('outstring');
expect(result.outstring).to.equal('Hi ram');
done();
}).
catch(done);
});

it('should error correctly when a decision table with a non-existent input expression is given', done => {
var decisionMap = readJSON('./test/data/sample2.json');

var feelString = decisionMap['final dec'];

decisionMap['final dec'] = feelString.replace('test1', 'test2');
expect(feelString.substr(feelString.indexOf('test'), 5)).to.equal('test1');
var feelString2 = decisionMap['final dec'];
expect(feelString2.substr(feelString2.indexOf('test'), 5)).to.equal('test2');
var ast = createDecisionGraphAST(decisionMap);

var payload = {
"name": "Ram",
"msg": "Hi"
};

executeDecisionService(ast, 'final dec', payload, 'foo2')

.then(() => {
done(new Error('should not execute'));
})
.catch(err => {
expect(err.message).to.include('test2');
done();
});
});
});
1 change: 1 addition & 0 deletions test/decision-service/servicification-tests.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,5 @@ describe('servicification tests...', function() {

// });


});
33 changes: 28 additions & 5 deletions utils/helper/decision-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,35 @@ const traverseDecisionTreeUtil = (root, payload) => {
Promise.all(classArr.map((classKey) => {
const node = root.children[classKey];
const sentinelKeys = Object.keys(node.children);
const { decisionMap } = payload;

return new Promise((resolve, reject) => {
Promise.all(sentinelKeys.map(key => node.children[key].ast.build(payload, {}, 'input'))).then((results) => {
let res = results.map((f, i) => ({ value: f(payload[classKey]), index: i })).filter(d => d.value === true);
res = res.map(obj => obj.index);
resolve(res);
}).catch(err => reject(err));
const inputExpressionValue = payload[classKey];
if (typeof inputExpressionValue !== 'undefined') {
//! the input expression is resolved from payload
Promise.all(sentinelKeys.map(key => node.children[key].ast.build(payload, {}, 'input'))).then((results) => {
let res = results.map((f, i) => ({ value: f(inputExpressionValue), index: i })).filter(d => d.value === true);
res = res.map(obj => obj.index);
resolve(res);
}).catch(err => reject(err));
} else if (decisionMap[classKey]) {
//! the input expression can be resolved from the decisionMap
const decision = decisionMap[classKey];
decision.build(payload)
.then((value) => {
Promise.all(sentinelKeys.map(key => node.children[key].ast.build(payload, {}, 'input')))
.then((results) => {
let res = results.map((f, i) => ({ value, index: i }))
.filter(d => d.value);
res = res.map(obj => obj.index);
resolve(res);
})
.catch(reject);
})
.catch(reject);
} else {
reject(new Error(`Cannot resolve decision table input expression: ${classKey}`));
}
});
})).then(results =>
resolveConflictRules(root, payload, results).then(results =>
Expand Down
13 changes: 10 additions & 3 deletions utils/helper/fn-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const { valueT, valueInverseT, valueDT, valueInverseDT, valueDTD, valueInverseDT
const { date, time, 'date and time': dateandtime } = require('../built-in-functions');
const { logger } = require('../../logger');
const { enableExecutionLogging } = require('../../settings');
const moment = require('moment-timezone');

const $log = logger('fn-generator');
const log = {};
Expand Down Expand Up @@ -267,9 +268,15 @@ const operatorMap = {
} else if (x.isDtd && y.isDtd) {
return valueInverseDTD(valueDTD(x) - valueDTD(y));
} else if ((x.isDateTime || x.isDate) && y.isYmd) {
// return dateandtime(date(x.year - (y.years + Math.floor((x.month - y.months) / 12)), (x.month - y.months) - (Math.floor((x.month - y.months) / 12) * 12), x.day), time(x));
// fix for https://github.com/EdgeVerve/feel/issues/11 by a-hegerath
return dateandtime(date((x.year - y.years) + Math.floor((x.month - y.months) / 12), (x.month - y.months) - (Math.floor((x.month - y.months) / 12) * 12), x.day), time(x));
let { years, months } = y;
const monthOverflow = Math.floor(months / 12);
if (monthOverflow > 0) {
years += monthOverflow;
months -= monthOverflow * 12;
}
const clone = moment(x);
clone.add(-years, 'years').add(-months, 'months');
return dateandtime(date(clone.year(), clone.month(), clone.date()), time(clone.format()));
} else if (x.isYmd && (y.isDateTime || y.isDate)) {
throw new Error(`${x.type} - ${y.type} : operation unsupported for one or more operands types`);
} else if ((x.isDateTime || x.isDate) && y.isDtd) {
Expand Down

0 comments on commit 7135438

Please sign in to comment.