filter parser

This commit is contained in:
Jan Prochazka 2020-03-12 13:15:13 +01:00
parent 064121376f
commit 2de6033dc9
3 changed files with 81 additions and 8 deletions

View File

@ -52,6 +52,29 @@ const compoudCondition = conditionType => conditions => {
}; };
}; };
const unaryCondition = conditionType => () => {
return {
conditionType,
expr: {
exprType: 'placeholder',
},
};
};
const binaryFixedValueCondition = value => () => {
return {
conditionType: 'binary',
operator: '=',
left: {
exprType: 'placeholder',
},
right: {
exprType: 'value',
value,
},
};
};
const parser = P.createLanguage({ const parser = P.createLanguage({
string1: () => string1: () =>
token(P.regexp(/"((?:\\.|.)*?)"/, 1)) token(P.regexp(/"((?:\\.|.)*?)"/, 1))
@ -72,16 +95,33 @@ const parser = P.createLanguage({
.desc('number'), .desc('number'),
noQuotedString: () => noQuotedString: () =>
P.regexp(/[^\s]+/) P.regexp(/[^\s^,^'^"]+/)
.desc('string unquoted') .desc('string unquoted')
.map(binaryCondition('=')), .map(binaryCondition('=')),
comma: () => word(','), comma: () => word(','),
not: () => word('NOT'), not: () => word('NOT'),
notNull: r => r.not.then(r.null).map(() => 'NOT_NULL'), notNull: r => r.not.then(r.null).map(unaryCondition('isNotNull')),
null: () => word('NULL'), null: () => word('NULL').map(unaryCondition('isNull')),
empty: () => word('EMPTY').map(unaryCondition('isEmpty')),
notEmpty: r => r.not.then(r.empty).map(unaryCondition('isNotEmpty')),
true: () => word('TRUE').map(binaryFixedValueCondition(1)),
false: () => word('FALSE').map(binaryFixedValueCondition(0)),
element: r => P.alt(r.string1, r.string2, r.null, r.notNull, r.number, r.noQuotedString).trim(whitespace), element: r =>
P.alt(
r.string1,
r.string2,
r.null,
r.notNull,
r.number,
r.empty,
r.notEmpty,
r.true,
r.false,
// must be last
r.noQuotedString
).trim(whitespace),
factor: r => r.element.sepBy(whitespace).map(compoudCondition('and')), factor: r => r.element.sepBy(whitespace).map(compoudCondition('and')),
list: r => r.factor.sepBy(r.comma).map(compoudCondition('or')), list: r => r.factor.sepBy(r.comma).map(compoudCondition('or')),
}); });

View File

@ -5,11 +5,34 @@ import { dumpSqlExpression } from './dumpSqlExpression';
export function dumpSqlCondition(dmp: SqlDumper, condition: Condition) { export function dumpSqlCondition(dmp: SqlDumper, condition: Condition) {
switch (condition.conditionType) { switch (condition.conditionType) {
case 'binary': case 'binary':
dmp.put('(');
dumpSqlExpression(dmp, condition.left); dumpSqlExpression(dmp, condition.left);
dmp.put(' %s ', condition.operator); dmp.put(' %s ', condition.operator);
dumpSqlExpression(dmp, condition.right); dumpSqlExpression(dmp, condition.right);
dmp.put(')');
break; break;
case 'isNull':
dumpSqlExpression(dmp, condition.expr);
dmp.put(' ^is ^null');
break;
case 'isNotNull':
dumpSqlExpression(dmp, condition.expr);
dmp.put(' ^is ^not ^null');
break;
case 'isEmpty':
dmp.put('^trim(');
dumpSqlExpression(dmp, condition.expr);
dmp.put(") = ''");
break;
case 'isNotEmpty':
dmp.put('^trim(');
dumpSqlExpression(dmp, condition.expr);
dmp.put(") <> ''");
break;
case 'and':
case 'or':
dmp.putCollection(` ^${condition.conditionType} `, condition.conditions, cond => {
dmp.putRaw('(');
dumpSqlCondition(dmp, cond);
dmp.putRaw(')');
});
} }
} }

View File

@ -34,11 +34,21 @@ export interface BinaryCondition {
right: Expression; right: Expression;
} }
export interface NotCondition extends UnaryCondition { export interface NotCondition {
conditionType: 'not'; conditionType: 'not';
condition: Condition;
} }
export type Condition = BinaryCondition | NotCondition; export interface TestCondition extends UnaryCondition {
conditionType: 'isNull' | 'isNotNull' | 'isEmpty' | 'isNotEmpty';
}
export interface CompoudCondition {
conditionType: 'and' | 'or';
conditions: Condition[];
}
export type Condition = BinaryCondition | NotCondition | TestCondition | CompoudCondition;
export interface Source { export interface Source {
name?: NamedObjectInfo; name?: NamedObjectInfo;