https://github.com/abdullah2993/expression-parser
An expression evaluator written in typescript with the goal to support SQL like WHERE clauses.
https://github.com/abdullah2993/expression-parser
expression expression-evaluator filters parser whereclause
Last synced: about 2 months ago
JSON representation
An expression evaluator written in typescript with the goal to support SQL like WHERE clauses.
- Host: GitHub
- URL: https://github.com/abdullah2993/expression-parser
- Owner: abdullah2993
- License: mit
- Created: 2021-08-07T09:21:05.000Z (almost 4 years ago)
- Default Branch: master
- Last Pushed: 2023-11-07T13:33:29.000Z (over 1 year ago)
- Last Synced: 2024-10-29T02:09:08.726Z (7 months ago)
- Topics: expression, expression-evaluator, filters, parser, whereclause
- Language: TypeScript
- Homepage:
- Size: 499 KB
- Stars: 4
- Watchers: 2
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# expression-parser [](https://github.com/abdullah2993/expression-parser/actions/workflows/build.yaml)
An expression evaluator written in typescript with the goal to support `SQL` like `WHERE` clauses.
## Installation
```
npm install --save @abdullah2993/expression-parser
```## Supported Operations and Functions
### Arithmetics
- `+`
- `-`
- `*`
- `/`### Comparison
- `=`
- `<>`
- `>`
- `>=`
- `<=`### Logical
- `and`
- `or`### SQL
- `IS NULL`
- `IS NOT NULL`
- `BETWEEN [NUMBER] AND [NUMBER]`
- `CASE WHEN expression THEN expression [WHEN expression] [ELSE expression] END`### Functions
Currently only function that is evaluated is the `LENGTH(variable)` function but supports function calls at the parser level so it is fairly easy to add more `SQL` functions.
## Examples
```js
/** Basic Math **/
evaluate('1+2'));
// 3
evaluate('10 + 2 * 6'));
// 22
evaluate('100 * 2 + 12'));
// 212
evaluate('100 * ( 2 + 12 )'));
// 1400
evaluate('100 * ( 2 + 12 ) / 14'));
// 100/** Basic Math With Variable Substitution**/
const context = {
a: 1, b: 2, c: 10, d: 6, e: 100, f: 12, g: 14,
};evaluateObject('a+b', context));
// 3
evaluateObject('c + b * d', context));
// 22
evaluateObject('e * b + f', context));
// 212
evaluateObject('e * ( b + f )', context));
// 1400
evaluateObject('e * ( b + f ) / g', context));
// 100/** Other Operations **/
const val: any = { a: null };
evaluateObject('a is not null and length(a) between 4 and 10', val);
// false
const val = { a: '123' };
evaluateObject('a is not null and length(a) between 4 and 10', val);
// false
const val = { a: '1234' };
evaluateObject('a is not null and length(a) between 4 and 10', val);
// true
const val = { a: '1234567890' };
evaluateObject('a is not null and length(a) between 4 and 10', val);
// true
const val = { a: '12345678901' };
evaluateObject('a is not null and length(a) between 4 and 10', val);
// false
const val: any = { a: 1, b: 1 };
evaluateObject('a is not null and b is not null', val);
// true
evaluateObject('a is not null and b is null', val);
// false
const val = { a: 1, b: null };
evaluateObject('a is not null and b is null', val);
// true
const val = { a: 1, b: 1 };
evaluateObject('a=b', val));
// true
evaluateObject('a>b', val));
// false
evaluateObject('ab', val);
// false
evaluateObject('a 1 then true else false end', val);
// false
const val = { a: 2, b: 3 };
evaluateObject('case when a > 1 then true else false end', val);
// true
val = { a: 2, b: 3 };
evaluateObject('case when a = 1 then 1 when a = 2 then 1 else false end', val);
// 1
evaluateObject('case when a = 1 then 1 when a = 2 then 2 else 3 end', val);
// 2
evaluateObject('case when a = 1 then 1 when a = 3 then 3 else 2 end', val);
// 2
const rule = `case
when light = 'Green' then 'Go'
when light = 'Yellow' then 'Should Stop'
when light = 'Red' then 'Stop'
else 'Invalid State' end`;
val = { light: 'Yellow' };
evaluateObject(rule, val))
// 'Should Stop'
val = { light: 'Green' };
evaluateObject(rule, val))
// 'Go'
val = { light: 'Red' };
evaluateObject(rule, val))
// 'Stop'
val = { light: 'Blue' };
evaluateObject(rule, val))
// 'Invalid State'```
## Sample AST
```json
//Expression: a is not null and length(a) between 4 and 10
{
"operator": "and",
"left": {
"operator": "<>",
"left": {
"name": "a",
"type": "IdentifierExpression"
},
"right": {
"value": null,
"type": "ValueExpression"
},
"type": "BinaryExpression"
},
"right": {
"operator": "and",
"left": {
"operator": ">=",
"left": {
"name": "length",
"args": [
{
"name": "a",
"type": "IdentifierExpression"
}
],
"type": "FunctionCallExpression"
},
"right": {
"value": 4,
"type": "ValueExpression"
},
"type": "BinaryExpression"
},
"right": {
"operator": "<=",
"left": {
"name": "length",
"args": [
{
"name": "a",
"type": "IdentifierExpression"
}
],
"type": "FunctionCallExpression"
},
"right": {
"value": 10,
"type": "ValueExpression"
},
"type": "BinaryExpression"
},
"type": "BinaryExpression"
},
"type": "BinaryExpression"
}
```## Test Coverage
```
13 specs, 0 failures
Finished in 0.069 seconds
Randomized with seed 62175 (jasmine --random=true --seed=62175)
--------------|---------|----------|---------|---------|-----------------------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-----------------------------------
All files | 93.24 | 83.33 | 92.73 | 93.19 |
ast.ts | 89.66 | 100 | 90 | 90 | 16-18
evaluator.ts | 85 | 69.23 | 100 | 84.21 | 14,18,27,47-49,64
lexer.ts | 99.04 | 98 | 100 | 99.03 | 86
parser.ts | 89.89 | 70 | 89.47 | 89.41 | 83,91,103,121,133,137,144,181,184
token.ts | 97.06 | 100 | 75 | 96.97 | 44
--------------|---------|----------|---------|---------|-----------------------------------
```