|
|
@@ -1,92 +1,98 @@ |
|
|
|
export const DIRECTIVE_MAP = { |
|
|
|
'=': 'equals', |
|
|
|
'!=': 'not-equals', |
|
|
|
'<': 'greater-than', |
|
|
|
'>': 'less-than', |
|
|
|
'<=': 'greater-than-equal', |
|
|
|
'>=': 'less-than-equal', |
|
|
|
'>=': 'greater-than-equal', |
|
|
|
'<=': 'less-than-equal', |
|
|
|
'>': 'greater-than', |
|
|
|
'<': 'less-than', |
|
|
|
}; |
|
|
|
|
|
|
|
export const DATA_SOURCE_QUERY_OPERATORS = Object.keys(DIRECTIVE_MAP) as (keyof typeof DIRECTIVE_MAP)[]; |
|
|
|
|
|
|
|
export type DataSourceQueryOperator = typeof DATA_SOURCE_QUERY_OPERATORS[number]; |
|
|
|
|
|
|
|
export interface DataSourceQuery { |
|
|
|
export interface DataSourceOperatorQuery { |
|
|
|
lhs: string; |
|
|
|
operator: DataSourceQueryOperator; |
|
|
|
rhs: string; |
|
|
|
} |
|
|
|
|
|
|
|
export interface DataSourceFunctionQuery { |
|
|
|
name: string; |
|
|
|
args: string[]; |
|
|
|
} |
|
|
|
|
|
|
|
export type DataSourceQuery = DataSourceOperatorQuery | DataSourceFunctionQuery; |
|
|
|
|
|
|
|
interface ConvertToDataSourceQueryCollectionOptions { |
|
|
|
} |
|
|
|
|
|
|
|
const parseDirectives = (valueRaw: string) => { |
|
|
|
let operator = '='; |
|
|
|
|
|
|
|
let hasDirective: boolean; |
|
|
|
let valueTest = valueRaw.toLowerCase(); |
|
|
|
let valuePredicate = valueRaw; |
|
|
|
const fragments = valueTest.split('.'); |
|
|
|
const directiveShorthands = Object.values(DIRECTIVE_MAP).map((s) => { |
|
|
|
// TODO how to parse? |
|
|
|
}) |
|
|
|
do { |
|
|
|
hasDirective = false; |
|
|
|
|
|
|
|
if (valueTest.startsWith('.neq.')) { |
|
|
|
operator = '!='; |
|
|
|
|
|
|
|
valueTest = valueTest.slice('.neq.'.length); |
|
|
|
valuePredicate = valuePredicate.slice('.neq.'.length); |
|
|
|
hasDirective = true; |
|
|
|
} else if (valueTest.startsWith('.gt.eq.')) { |
|
|
|
operator = '>='; |
|
|
|
|
|
|
|
valueTest = valueTest.slice('.gt.eq.'.length); |
|
|
|
valuePredicate = valuePredicate.slice('.gt.eq.'.length); |
|
|
|
hasDirective = true; |
|
|
|
} else if (valueTest.startsWith('.gte.')) { |
|
|
|
operator = '>='; |
|
|
|
|
|
|
|
valueTest = valueTest.slice('.gte.'.length); |
|
|
|
valuePredicate = valuePredicate.slice('.gte.'.length); |
|
|
|
hasDirective = true; |
|
|
|
} else if (valueTest.startsWith('.lt.eq.')) { |
|
|
|
operator = '<='; |
|
|
|
|
|
|
|
valueTest = valueTest.slice('.lt.eq.'.length); |
|
|
|
valuePredicate = valuePredicate.slice('.lt.eq.'.length); |
|
|
|
hasDirective = true; |
|
|
|
} else if (valueTest.startsWith('.lte.')) { |
|
|
|
operator = '<='; |
|
|
|
|
|
|
|
valueTest = valueTest.slice('.lte.'.length); |
|
|
|
valuePredicate = valuePredicate.slice('.lte.'.length); |
|
|
|
hasDirective = true; |
|
|
|
} else if (valueTest.startsWith('.gt.')) { |
|
|
|
operator = '>'; |
|
|
|
|
|
|
|
valueTest = valueTest.slice('.gt.'.length); |
|
|
|
valuePredicate = valuePredicate.slice('.gt.'.length); |
|
|
|
hasDirective = true; |
|
|
|
} else if (valueTest.startsWith('.lt.')) { |
|
|
|
operator = '<'; |
|
|
|
|
|
|
|
valueTest = valueTest.slice('.lt.'.length); |
|
|
|
valuePredicate = valuePredicate.slice('.lt.'.length); |
|
|
|
hasDirective = true; |
|
|
|
} else if (valueTest.startsWith('.eq.')) { |
|
|
|
operator = '='; |
|
|
|
|
|
|
|
valueTest = valueTest.slice('.eq.'.length); |
|
|
|
valuePredicate = valuePredicate.slice('.eq.'.length); |
|
|
|
hasDirective = true; |
|
|
|
} |
|
|
|
} while (hasDirective); |
|
|
|
const fragments = valueRaw.split('.'); |
|
|
|
|
|
|
|
if (!( |
|
|
|
fragments.length > 1 && fragments[0].length === 0 |
|
|
|
)) { |
|
|
|
return { |
|
|
|
operator: '=', |
|
|
|
rhs: valueRaw, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
const theOperator = fragments.slice(1, -1).reduce( |
|
|
|
(theState, f) => { |
|
|
|
const whichDirective = Object.entries(DIRECTIVE_MAP).find( |
|
|
|
([, match]) => { |
|
|
|
const remainingChars = match.split('').reduce( |
|
|
|
(rem, matchChar) => { |
|
|
|
if (matchChar === rem.charAt(0)) { |
|
|
|
return rem.slice(1); |
|
|
|
} |
|
|
|
|
|
|
|
return rem; |
|
|
|
}, |
|
|
|
f.toLowerCase() |
|
|
|
); |
|
|
|
|
|
|
|
return remainingChars.length <= 0; |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
const selectedOperator = whichDirective?.[0] ?? theState.operator; |
|
|
|
|
|
|
|
if (selectedOperator === '=') { |
|
|
|
if (theState.operator === '>') { |
|
|
|
return { |
|
|
|
...theState, |
|
|
|
operator: '>=', |
|
|
|
currentToken: `${theState.currentToken}${f}`, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
if (theState.operator === '<') { |
|
|
|
return { |
|
|
|
...theState, |
|
|
|
operator: '<=', |
|
|
|
currentToken: `${theState.currentToken}${f}`, |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return { |
|
|
|
...theState, |
|
|
|
operator: selectedOperator, |
|
|
|
currentToken: `${theState.currentToken}${f}`, |
|
|
|
}; |
|
|
|
}, |
|
|
|
{ |
|
|
|
operator: undefined as (string | undefined), |
|
|
|
currentToken: '', |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
return { |
|
|
|
operator, |
|
|
|
rhs: valuePredicate, |
|
|
|
operator: theOperator.operator ?? '=', |
|
|
|
rhs: fragments.at(-1), |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|