@allgemein/expressions
Version:
Library for mango expressions
303 lines • 10.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExpressionInterpreter = void 0;
const LikeDesc_1 = require("../descriptors/LikeDesc");
const LtDesc_1 = require("../descriptors/LtDesc");
const GtDesc_1 = require("../descriptors/GtDesc");
const InDesc_1 = require("../descriptors/InDesc");
const NeqDesc_1 = require("../descriptors/NeqDesc");
const EqDesc_1 = require("../descriptors/EqDesc");
const LeDesc_1 = require("../descriptors/LeDesc");
const KeyDesc_1 = require("../descriptors/KeyDesc");
const ValueDesc_1 = require("../descriptors/ValueDesc");
const GeDesc_1 = require("../descriptors/GeDesc");
const GroupDesc_1 = require("../descriptors/GroupDesc");
const AndDesc_1 = require("../descriptors/AndDesc");
const OrDesc_1 = require("../descriptors/OrDesc");
const lodash_1 = require("lodash");
class ExpressionInterpreter {
constructor() {
//rootEntityDef:EntityDef;
this.groupLevel = 0;
this.ops = [
{
name: 'visitGroup',
regex: /\(/,
method: this.visitGroup,
after: [null, 'visitGroup', 'onBool']
},
{
name: 'leaveGroup',
regex: /\)/,
method: this.leaveGroup,
condition: () => {
return this.groupLevel > 0;
},
after: ['onValue', 'leaveGroup']
},
{
name: 'onKey',
regex: /('[^']+')|("[^"]+")|(\w|\.|\d)+/,
method: this.onKey,
skipIndex: 3,
after: [null, 'visitGroup', 'onBool']
},
{
name: 'onBool',
regex: / (and|AND|or|OR) /,
method: this.onBool,
skipIndex: 1,
after: ['leaveGroup', 'onValue']
},
{
name: 'onOperator',
regex: /(>=|<=|<>|>|<|=| in | IN | like | LIKE )/,
method: this.onOperator,
skipIndex: 1,
after: ['onKey']
},
{
name: 'onValue',
regex: /('[^']*')|("[^"]*")|\d+|\d+.\d+|(\(((('[^']*')|("[^"]*")|\d+|\d+.\d+)\s*,?\s*)+\))/,
method: this.onValue,
skipIndex: 7,
after: ['onOperator']
},
];
this.res = [];
this.queue = [];
//this.rootEntityDef = entityDef;
}
interprete(str) {
this.fragmentize(str);
return (0, lodash_1.first)(this.res);
}
fragmentize(str) {
let lastState = (0, lodash_1.last)(this.queue);
let currentOps = this.ops.filter(x => {
let _true = true;
if (x.condition) {
_true = x.condition();
}
if ((0, lodash_1.isEmpty)(x.after)) {
return _true;
}
if (!lastState) {
return _true && x.after.indexOf(null) > -1;
}
else {
return _true && x.after.indexOf(lastState.state) > -1;
}
});
//console.log(currentOps.map(x => x.name));
let inc = 0;
let map = {};
currentOps.map((x, index) => {
map[inc] = index;
inc = x.skipIndex ? inc + x.skipIndex : inc + 1;
});
const regex = new RegExp('^\\s*' + currentOps.map(x => '(' + x.regex.source + ')').join('|'), 'gim');
let arr = regex.exec(str);
if (arr) {
// let index = arr.findIndex(x => !isUndefined(x));
let index = (0, lodash_1.findIndex)(arr, x => !(0, lodash_1.isUndefined)(x), 1) - 1;
if (index > -1) {
let opId = map[index];
let op = currentOps[opId];
// console.log(map, regex, arr, regex.lastIndex,op.name);
op.method.apply(this, [arr[index + 1], str]);
const nextStr = str.substring(regex.lastIndex);
if (!(0, lodash_1.isEmpty)(nextStr)) {
this.fragmentize(nextStr);
}
}
else {
throw new Error('no match found at "' + JSON.stringify(arr) + '"');
}
}
else {
throw new Error('nothing found at "' + str + '" with regex ' + regex.source);
}
}
/*
escape(x: string) {
const specials = [
'/', '.', '*', '+', '?', '|',
'(', ')', '[', ']', '{', '}', '\\'
];
const regex = new RegExp('(\\' + specials.join('|\\') + ')', 'gim');
return x.replace(regex, '\\$1');
}
*/
onKey(match, str) {
let key = match.replace(/^('|")|('|")$/g, '');
this.queue.push({
group: this.groupLevel,
value: key,
state: 'onKey'
});
}
onOperator(match, str) {
this.queue.push({
group: this.groupLevel,
value: match,
state: 'onOperator'
});
}
onValue(match, str) {
let value;
if (/^('|")|('|")$/.test(match)) {
value = match.replace(/^('|")|('|")$/g, '');
}
else if (/^\d+$/.test(match)) {
value = parseInt(match);
}
else if (/^\d+\.\d+$/.test(match)) {
value = parseFloat(match);
}
else if (/^\(.*\)$/.test(match)) {
value = match.replace(/^\(|\)$/g, '').split(',').map(x => x.trim())
.map(x => {
let value2 = x;
if (/^('|")|('|")$/.test(x)) {
value2 = x.replace(/^('|")|('|")$/g, '');
}
else if (/^\d+$/.test(x)) {
value2 = parseInt(x);
}
else if (/^\d+\.\d+$/.test(x)) {
value2 = parseFloat(x);
}
return value2;
});
}
let op = this.queue.pop();
let key = this.queue.pop();
let erg;
if (op.state == 'onOperator' && key && key.state == 'onKey') {
switch (op.value.trim().toLowerCase()) {
case '=':
erg = (0, EqDesc_1.Eq)((0, KeyDesc_1.Key)(key.value), (0, ValueDesc_1.Value)(value));
break;
case 'like':
erg = (0, LikeDesc_1.Like)((0, KeyDesc_1.Key)(key.value), (0, ValueDesc_1.Value)(value));
break;
case '<=':
erg = (0, LeDesc_1.Le)((0, KeyDesc_1.Key)(key.value), (0, ValueDesc_1.Value)(value));
break;
case '>=':
erg = (0, GeDesc_1.Ge)((0, KeyDesc_1.Key)(key.value), (0, ValueDesc_1.Value)(value));
break;
case '<':
erg = (0, LtDesc_1.Lt)((0, KeyDesc_1.Key)(key.value), (0, ValueDesc_1.Value)(value));
break;
case '>':
erg = (0, GtDesc_1.Gt)((0, KeyDesc_1.Key)(key.value), (0, ValueDesc_1.Value)(value));
break;
case 'in':
erg = (0, InDesc_1.In)((0, KeyDesc_1.Key)(key.value), (0, ValueDesc_1.Value)(value));
break;
case '<>':
erg = (0, NeqDesc_1.Neq)((0, KeyDesc_1.Key)(key.value), (0, ValueDesc_1.Value)(value));
break;
default:
throw new Error('operator not found');
}
}
else {
throw new Error('operator not found');
}
this.queue.push({
group: this.groupLevel,
value: value,
state: 'onValue',
op: op,
key: key,
desc: erg
});
let res = (0, lodash_1.last)(this.res);
if (res instanceof GroupDesc_1.GroupDesc) {
res.values.push(erg);
}
else {
this.res.push(erg);
}
}
visitGroup() {
this.groupLevel++;
let groupDesc = new GroupDesc_1.GroupDesc();
groupDesc.id = this.groupLevel;
this.res.push(groupDesc);
this.queue.push({
group: this.groupLevel,
desc: groupDesc,
state: 'visitGroup'
});
}
leaveGroup() {
let group = this.res.find(g => g instanceof GroupDesc_1.GroupDesc ? g.id == this.groupLevel : false);
if (group && group.type == 'group') {
(0, lodash_1.remove)(this.res, g => g instanceof GroupDesc_1.GroupDesc ? g.id == this.groupLevel : false);
// embedded withotu bool
let prevGid = this.groupLevel - 1;
let prevGroup = this.res.find(g => g instanceof GroupDesc_1.GroupDesc ? g.id == prevGid : false);
if (prevGroup) {
group.values.forEach((v) => prevGroup.values.push(v));
group.values = [];
}
else {
throw new Error('cant find previous group to move values to ... ');
}
}
this.queue.push({
group: this.groupLevel,
state: 'leaveGroup',
desc: group
});
//this.
this.groupLevel--;
}
onBool(match) {
let bool = match.trim().toLocaleUpperCase();
let last = this.res.pop();
let group;
if (last instanceof GroupDesc_1.GroupDesc && last.id == this.groupLevel && last.type.toLowerCase() == bool.toLowerCase()) {
// DO NOTTING
group = last;
this.res.push(group);
}
else if (last instanceof GroupDesc_1.GroupDesc && last.type == 'group') {
// undefined
switch (bool) {
case 'AND':
group = (0, AndDesc_1.And)(...last.values);
break;
case 'OR':
group = (0, OrDesc_1.Or)(...last.values);
break;
}
group.id = this.groupLevel;
this.res.push(group);
}
else {
switch (bool) {
case 'AND':
group = (0, AndDesc_1.And)(last);
break;
case 'OR':
group = (0, OrDesc_1.Or)(last);
break;
}
group.id = this.groupLevel;
this.res.push(group);
}
this.queue.push({
group: this.groupLevel,
value: match.trim().toLocaleUpperCase(),
state: 'onBool',
desc: group
});
}
}
exports.ExpressionInterpreter = ExpressionInterpreter;
//# sourceMappingURL=ExpressionInterpreter.js.map