diff --git a/packages/filterparser/src/datetimeParser.ts b/packages/filterparser/src/datetimeParser.ts index 20dd7987..22d0dd68 100644 --- a/packages/filterparser/src/datetimeParser.ts +++ b/packages/filterparser/src/datetimeParser.ts @@ -190,6 +190,16 @@ const unaryCondition = conditionType => () => { }; }; +const sqlTemplate = templateSql => { + return { + conditionType: 'rawTemplate', + templateSql, + expr: { + exprType: 'placeholder', + }, + }; +}; + const createParser = () => { const langDef = { comma: () => word(','), @@ -198,6 +208,11 @@ const createParser = () => { notNull: r => r.not.then(r.null).map(unaryCondition('isNotNull')), null: () => word('NULL').map(unaryCondition('isNull')), + sql: () => + token(P.regexp(/\{(.*?)\}/, 1)) + .map(sqlTemplate) + .desc('sql literal'), + yearNum: () => P.regexp(/\d\d\d\d/).map(yearCondition()), yearMonthNum: () => P.regexp(/\d\d\d\d-\d\d?/).map(yearMonthCondition()), yearMonthDayNum: () => P.regexp(/\d\d\d\d-\d\d?-\d\d?/).map(yearMonthDayCondition()), @@ -282,7 +297,8 @@ const createParser = () => { r.le, r.lt, r.ge, - r.gt + r.gt, + r.sql ).trim(whitespace), factor: r => r.element.sepBy(whitespace).map(compoudCondition('$and')), list: r => r.factor.sepBy(r.comma).map(compoudCondition('$or')), diff --git a/packages/filterparser/src/parseFilter.ts b/packages/filterparser/src/parseFilter.ts index a7740779..35cb8fa4 100644 --- a/packages/filterparser/src/parseFilter.ts +++ b/packages/filterparser/src/parseFilter.ts @@ -68,6 +68,16 @@ const negateCondition = condition => { }; }; +const sqlTemplate = templateSql => { + return { + conditionType: 'rawTemplate', + templateSql, + expr: { + exprType: 'placeholder', + }, + }; +}; + const createParser = (filterType: FilterType) => { const langDef = { string1: () => @@ -97,6 +107,11 @@ const createParser = (filterType: FilterType) => { noQuotedString: () => P.regexp(/[^\s^,^'^"]+/).desc('string unquoted'), + sql: () => + token(P.regexp(/\{(.*?)\}/, 1)) + .map(sqlTemplate) + .desc('sql literal'), + value: r => P.alt(...allowedValues.map(x => r[x])), valueTestEq: r => r.value.map(binaryCondition('=')), valueTestStr: r => r.value.map(likeCondition('like', '%#VALUE#%')), @@ -139,7 +154,7 @@ const createParser = (filterType: FilterType) => { allowedValues.push('string1Num', 'string2Num', 'number'); } - const allowedElements = ['null', 'notNull', 'eq', 'ne', 'ne2']; + const allowedElements = ['null', 'notNull', 'eq', 'ne', 'ne2', 'sql']; if (filterType == 'number' || filterType == 'datetime' || filterType == 'eval') { allowedElements.push('le', 'ge', 'lt', 'gt'); } diff --git a/packages/sqltree/src/dumpSqlCondition.ts b/packages/sqltree/src/dumpSqlCondition.ts index df4d2e96..ea2abc44 100644 --- a/packages/sqltree/src/dumpSqlCondition.ts +++ b/packages/sqltree/src/dumpSqlCondition.ts @@ -72,5 +72,15 @@ export function dumpSqlCondition(dmp: SqlDumper, condition: Condition) { dumpSqlExpression(dmp, condition.expr); dmp.put(' ^in (%,v)', condition.values); break; + case 'rawTemplate': + let was = false; + for (const item of condition.templateSql.split('$$')) { + if (was) { + dumpSqlExpression(dmp, condition.expr); + } + dmp.putRaw(item); + was = true; + } + break; } } diff --git a/packages/sqltree/src/types.ts b/packages/sqltree/src/types.ts index 18f77423..07e9e4b0 100644 --- a/packages/sqltree/src/types.ts +++ b/packages/sqltree/src/types.ts @@ -105,6 +105,12 @@ export interface InCondition { values: any[]; } +export interface RawTemplateCondition { + conditionType: 'rawTemplate'; + templateSql: string; + expr: Expression; +} + export type Condition = | BinaryCondition | NotCondition @@ -114,7 +120,8 @@ export type Condition = | ExistsCondition | NotExistsCondition | BetweenCondition - | InCondition; + | InCondition + | RawTemplateCondition; export interface Source { name?: NamedObjectInfo;