2020-05-19 00:00:35 +02:00
|
|
|
const AndExp = require('./expressions/and');
|
|
|
|
const OrExp = require('./expressions/or');
|
|
|
|
const NotExp = require('./expressions/not');
|
2020-05-20 00:03:33 +02:00
|
|
|
const AttributeExistsExp = require('./expressions/attribute_exists');
|
|
|
|
const FieldComparisonExp = require('./expressions/field_comparison');
|
2020-05-19 00:00:35 +02:00
|
|
|
const NoteCacheFulltextExp = require('./expressions/note_cache_fulltext');
|
|
|
|
const NoteContentFulltextExp = require('./expressions/note_content_fulltext');
|
|
|
|
|
|
|
|
function getFulltext(tokens, includingNoteContent) {
|
|
|
|
if (includingNoteContent) {
|
|
|
|
return [
|
|
|
|
new OrExp([
|
|
|
|
new NoteCacheFulltextExp(tokens),
|
|
|
|
new NoteContentFulltextExp(tokens)
|
|
|
|
])
|
|
|
|
]
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return [
|
|
|
|
new NoteCacheFulltextExp(tokens)
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function isOperator(str) {
|
|
|
|
return str.matches(/^[=<>*]+$/);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getExpressions(tokens) {
|
|
|
|
const expressions = [];
|
|
|
|
let op = null;
|
|
|
|
|
|
|
|
for (let i = 0; i < tokens.length; i++) {
|
|
|
|
const token = tokens[i];
|
|
|
|
|
|
|
|
if (token === '#' || token === '@') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Array.isArray(token)) {
|
|
|
|
expressions.push(getExpressions(token));
|
|
|
|
}
|
|
|
|
else if (token.startsWith('#') || token.startsWith('@')) {
|
|
|
|
const type = token.startsWith('#') ? 'label' : 'relation';
|
|
|
|
|
|
|
|
if (i < tokens.length - 2 && isOperator(tokens[i + 1])) {
|
2020-05-20 00:03:33 +02:00
|
|
|
expressions.push(new FieldComparisonExp(type, token.substr(1), tokens[i + 1], tokens[i + 2]));
|
2020-05-19 00:00:35 +02:00
|
|
|
|
|
|
|
i += 2;
|
|
|
|
}
|
|
|
|
else {
|
2020-05-20 00:03:33 +02:00
|
|
|
expressions.push(new AttributeExistsExp(type, token.substr(1)));
|
2020-05-19 00:00:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (['and', 'or'].includes(token.toLowerCase())) {
|
|
|
|
if (!op) {
|
|
|
|
op = token.toLowerCase();
|
|
|
|
}
|
|
|
|
else if (op !== token.toLowerCase()) {
|
|
|
|
throw new Error('Mixed usage of AND/OR - always use parenthesis to group AND/OR expressions.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (isOperator(token)) {
|
|
|
|
throw new Error(`Misplaced or incomplete expression "${token}"`);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
throw new Error(`Unrecognized expression "${token}"`);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!op && expressions.length > 1) {
|
|
|
|
op = 'and';
|
|
|
|
}
|
|
|
|
}
|
2020-05-20 00:03:33 +02:00
|
|
|
|
|
|
|
return expressions;
|
2020-05-19 00:00:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function parse(fulltextTokens, expressionTokens, includingNoteContent) {
|
|
|
|
return AndExp.of([
|
|
|
|
...getFulltext(fulltextTokens, includingNoteContent),
|
|
|
|
...getExpressions(expressionTokens)
|
|
|
|
]);
|
|
|
|
}
|
2020-05-20 00:03:33 +02:00
|
|
|
|
|
|
|
module.exports = parse;
|