mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
implemented property based access + parent
This commit is contained in:
parent
714881ad99
commit
4ea934509e
@ -18,8 +18,8 @@ describe("Lexer fulltext", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("you can use different quotes and other special characters inside quotes", () => {
|
it("you can use different quotes and other special characters inside quotes", () => {
|
||||||
expect(lexer("'i can use \" or ` or #@=*' without problem").fulltextTokens)
|
expect(lexer("'i can use \" or ` or #~=*' without problem").fulltextTokens)
|
||||||
.toEqual(["i can use \" or ` or #@=*", "without", "problem"]);
|
.toEqual(["i can use \" or ` or #~=*", "without", "problem"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("if quote is not ended then it's just one long token", () => {
|
it("if quote is not ended then it's just one long token", () => {
|
||||||
@ -33,15 +33,15 @@ describe("Lexer fulltext", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("escaping special characters", () => {
|
it("escaping special characters", () => {
|
||||||
expect(lexer("hello \\#\\@\\'").fulltextTokens)
|
expect(lexer("hello \\#\\~\\'").fulltextTokens)
|
||||||
.toEqual(["hello", "#@'"]);
|
.toEqual(["hello", "#~'"]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Lexer expression", () => {
|
describe("Lexer expression", () => {
|
||||||
it("simple attribute existence", () => {
|
it("simple attribute existence", () => {
|
||||||
expect(lexer("#label @relation").expressionTokens)
|
expect(lexer("#label ~relation").expressionTokens)
|
||||||
.toEqual(["#label", "@relation"]);
|
.toEqual(["#label", "~relation"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("simple label operators", () => {
|
it("simple label operators", () => {
|
||||||
@ -50,12 +50,17 @@ describe("Lexer expression", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("spaces in attribute names and values", () => {
|
it("spaces in attribute names and values", () => {
|
||||||
expect(lexer(`#'long label'="hello o' world" @'long relation'`).expressionTokens)
|
expect(lexer(`#'long label'="hello o' world" ~'long relation'`).expressionTokens)
|
||||||
.toEqual(["#long label", "=", "hello o' world", "@long relation"]);
|
.toEqual(["#long label", "=", "hello o' world", "~long relation"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("complex expressions with and, or and parenthesis", () => {
|
it("complex expressions with and, or and parenthesis", () => {
|
||||||
expect(lexer(`# (#label=text OR #second=text) AND @relation`).expressionTokens)
|
expect(lexer(`# (#label=text OR #second=text) AND ~relation`).expressionTokens)
|
||||||
.toEqual(["#", "(", "#label", "=", "text", "or", "#second", "=", "text", ")", "and", "@relation"]);
|
.toEqual(["#", "(", "#label", "=", "text", "or", "#second", "=", "text", ")", "and", "~relation"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("dot separated properties", () => {
|
||||||
|
expect(lexer(`# ~author.title = 'Hugh Howey' AND note.title = 'Silo'`).expressionTokens)
|
||||||
|
.toEqual(["#", "~author", ".", "title", "=", "hugh howey", "and", "note", ".", "title", "=", "silo"]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -37,7 +37,7 @@ describe("Parser", () => {
|
|||||||
parsingContext: new ParsingContext()
|
parsingContext: new ParsingContext()
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("FieldComparisonExp");
|
expect(rootExp.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(rootExp.attributeType).toEqual("label");
|
expect(rootExp.attributeType).toEqual("label");
|
||||||
expect(rootExp.attributeName).toEqual("mylabel");
|
expect(rootExp.attributeName).toEqual("mylabel");
|
||||||
expect(rootExp.comparator).toBeTruthy();
|
expect(rootExp.comparator).toBeTruthy();
|
||||||
@ -53,10 +53,10 @@ describe("Parser", () => {
|
|||||||
expect(rootExp.constructor.name).toEqual("AndExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
const [firstSub, secondSub] = rootExp.subExpressions;
|
const [firstSub, secondSub] = rootExp.subExpressions;
|
||||||
|
|
||||||
expect(firstSub.constructor.name).toEqual("FieldComparisonExp");
|
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(firstSub.attributeName).toEqual("first");
|
expect(firstSub.attributeName).toEqual("first");
|
||||||
|
|
||||||
expect(secondSub.constructor.name).toEqual("FieldComparisonExp");
|
expect(secondSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(secondSub.attributeName).toEqual("second");
|
expect(secondSub.attributeName).toEqual("second");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -70,27 +70,27 @@ describe("Parser", () => {
|
|||||||
expect(rootExp.constructor.name).toEqual("AndExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
const [firstSub, secondSub] = rootExp.subExpressions;
|
const [firstSub, secondSub] = rootExp.subExpressions;
|
||||||
|
|
||||||
expect(firstSub.constructor.name).toEqual("FieldComparisonExp");
|
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(firstSub.attributeName).toEqual("first");
|
expect(firstSub.attributeName).toEqual("first");
|
||||||
|
|
||||||
expect(secondSub.constructor.name).toEqual("FieldComparisonExp");
|
expect(secondSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(secondSub.attributeName).toEqual("second");
|
expect(secondSub.attributeName).toEqual("second");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("simple label OR", () => {
|
it("simple label OR", () => {
|
||||||
const rootExp = parser({
|
const rootExp = parser({
|
||||||
fulltextTokens: [],
|
fulltextTokens: [],
|
||||||
expressionTokens: ["#first", "=", "text", "OR", "#second", "=", "text"],
|
expressionTokens: ["#first", "=", "text", "or", "#second", "=", "text"],
|
||||||
parsingContext: new ParsingContext()
|
parsingContext: new ParsingContext()
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("OrExp");
|
expect(rootExp.constructor.name).toEqual("OrExp");
|
||||||
const [firstSub, secondSub] = rootExp.subExpressions;
|
const [firstSub, secondSub] = rootExp.subExpressions;
|
||||||
|
|
||||||
expect(firstSub.constructor.name).toEqual("FieldComparisonExp");
|
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(firstSub.attributeName).toEqual("first");
|
expect(firstSub.attributeName).toEqual("first");
|
||||||
|
|
||||||
expect(secondSub.constructor.name).toEqual("FieldComparisonExp");
|
expect(secondSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(secondSub.attributeName).toEqual("second");
|
expect(secondSub.attributeName).toEqual("second");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -107,30 +107,30 @@ describe("Parser", () => {
|
|||||||
expect(firstSub.constructor.name).toEqual("NoteCacheFulltextExp");
|
expect(firstSub.constructor.name).toEqual("NoteCacheFulltextExp");
|
||||||
expect(firstSub.tokens).toEqual(["hello"]);
|
expect(firstSub.tokens).toEqual(["hello"]);
|
||||||
|
|
||||||
expect(secondSub.constructor.name).toEqual("FieldComparisonExp");
|
expect(secondSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(secondSub.attributeName).toEqual("mylabel");
|
expect(secondSub.attributeName).toEqual("mylabel");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("label sub-expression", () => {
|
it("label sub-expression", () => {
|
||||||
const rootExp = parser({
|
const rootExp = parser({
|
||||||
fulltextTokens: [],
|
fulltextTokens: [],
|
||||||
expressionTokens: ["#first", "=", "text", "OR", ["#second", "=", "text", "AND", "#third", "=", "text"]],
|
expressionTokens: ["#first", "=", "text", "or", ["#second", "=", "text", "and", "#third", "=", "text"]],
|
||||||
parsingContext: new ParsingContext()
|
parsingContext: new ParsingContext()
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("OrExp");
|
expect(rootExp.constructor.name).toEqual("OrExp");
|
||||||
const [firstSub, secondSub] = rootExp.subExpressions;
|
const [firstSub, secondSub] = rootExp.subExpressions;
|
||||||
|
|
||||||
expect(firstSub.constructor.name).toEqual("FieldComparisonExp");
|
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(firstSub.attributeName).toEqual("first");
|
expect(firstSub.attributeName).toEqual("first");
|
||||||
|
|
||||||
expect(secondSub.constructor.name).toEqual("AndExp");
|
expect(secondSub.constructor.name).toEqual("AndExp");
|
||||||
const [firstSubSub, secondSubSub] = secondSub.subExpressions;
|
const [firstSubSub, secondSubSub] = secondSub.subExpressions;
|
||||||
|
|
||||||
expect(firstSubSub.constructor.name).toEqual("FieldComparisonExp");
|
expect(firstSubSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(firstSubSub.attributeName).toEqual("second");
|
expect(firstSubSub.attributeName).toEqual("second");
|
||||||
|
|
||||||
expect(secondSubSub.constructor.name).toEqual("FieldComparisonExp");
|
expect(secondSubSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(secondSubSub.attributeName).toEqual("third");
|
expect(secondSubSub.attributeName).toEqual("third");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -83,6 +83,31 @@ describe("Search", () => {
|
|||||||
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("numeric label comparison fallback to string comparison", async () => {
|
||||||
|
rootNote.child(
|
||||||
|
note("Europe")
|
||||||
|
.label('country', '', true)
|
||||||
|
.child(
|
||||||
|
note("Austria")
|
||||||
|
.label('established', '1955-07-27')
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
note("Czech Republic")
|
||||||
|
.label('established', '1993-01-01')
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
note("Hungary")
|
||||||
|
.label('established', '..wrong..')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const parsingContext = new ParsingContext();
|
||||||
|
|
||||||
|
const searchResults = await searchService.findNotesWithQuery('#established < 1990', parsingContext);
|
||||||
|
expect(searchResults.length).toEqual(1);
|
||||||
|
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
it("logical or", async () => {
|
it("logical or", async () => {
|
||||||
rootNote.child(
|
rootNote.child(
|
||||||
note("Europe")
|
note("Europe")
|
||||||
@ -140,6 +165,51 @@ describe("Search", () => {
|
|||||||
expect(searchResults.length).toEqual(1);
|
expect(searchResults.length).toEqual(1);
|
||||||
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("filter by note property", async () => {
|
||||||
|
rootNote.child(
|
||||||
|
note("Europe")
|
||||||
|
.child(
|
||||||
|
note("Austria")
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
note("Czech Republic")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const parsingContext = new ParsingContext();
|
||||||
|
|
||||||
|
const searchResults = await searchService.findNotesWithQuery('# note.title =* czech', parsingContext);
|
||||||
|
expect(searchResults.length).toEqual(1);
|
||||||
|
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("filter by note's parent", async () => {
|
||||||
|
rootNote.child(
|
||||||
|
note("Europe")
|
||||||
|
.child(
|
||||||
|
note("Austria")
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
note("Czech Republic")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
note("Asia")
|
||||||
|
.child(note('Taiwan'))
|
||||||
|
);
|
||||||
|
|
||||||
|
const parsingContext = new ParsingContext();
|
||||||
|
|
||||||
|
let searchResults = await searchService.findNotesWithQuery('# note.parent.title = Europe', parsingContext);
|
||||||
|
expect(searchResults.length).toEqual(2);
|
||||||
|
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||||
|
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||||
|
|
||||||
|
searchResults = await searchService.findNotesWithQuery('# note.parent.title = Asia', parsingContext);
|
||||||
|
expect(searchResults.length).toEqual(1);
|
||||||
|
expect(findNoteByTitle(searchResults, "Taiwan")).toBeTruthy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/** @return {Note} */
|
/** @return {Note} */
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const Expression = require('./expression');
|
const Expression = require('./expression');
|
||||||
|
|
||||||
class AndExp extends Expression{
|
class AndExp extends Expression {
|
||||||
static of(subExpressions) {
|
static of(subExpressions) {
|
||||||
subExpressions = subExpressions.filter(exp => !!exp);
|
subExpressions = subExpressions.filter(exp => !!exp);
|
||||||
|
|
||||||
|
36
src/services/search/expressions/child_of.js
Normal file
36
src/services/search/expressions/child_of.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Expression = require('./expression');
|
||||||
|
const NoteSet = require('../note_set');
|
||||||
|
|
||||||
|
class ChildOfExp extends Expression {
|
||||||
|
constructor(subExpression) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.subExpression = subExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
execute(inputNoteSet, searchContext) {
|
||||||
|
const subInputNoteSet = new NoteSet();
|
||||||
|
|
||||||
|
for (const note of inputNoteSet.notes) {
|
||||||
|
subInputNoteSet.addAll(note.parents);
|
||||||
|
}
|
||||||
|
|
||||||
|
const subResNoteSet = this.subExpression.execute(subInputNoteSet, searchContext);
|
||||||
|
|
||||||
|
const resNoteSet = new NoteSet();
|
||||||
|
|
||||||
|
for (const parentNote of subResNoteSet.notes) {
|
||||||
|
for (const childNote of parentNote.children) {
|
||||||
|
if (inputNoteSet.hasNote(childNote)) {
|
||||||
|
resNoteSet.add(childNote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resNoteSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ChildOfExp;
|
@ -4,6 +4,7 @@ class Expression {
|
|||||||
/**
|
/**
|
||||||
* @param {NoteSet} noteSet
|
* @param {NoteSet} noteSet
|
||||||
* @param {object} searchContext
|
* @param {object} searchContext
|
||||||
|
* @return {NoteSet}
|
||||||
*/
|
*/
|
||||||
execute(noteSet, searchContext) {}
|
execute(noteSet, searchContext) {}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ const Expression = require('./expression');
|
|||||||
const NoteSet = require('../note_set');
|
const NoteSet = require('../note_set');
|
||||||
const noteCache = require('../../note_cache/note_cache');
|
const noteCache = require('../../note_cache/note_cache');
|
||||||
|
|
||||||
class FieldComparisonExp extends Expression {
|
class LabelComparisonExp extends Expression {
|
||||||
constructor(attributeType, attributeName, comparator) {
|
constructor(attributeType, attributeName, comparator) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -37,4 +37,4 @@ class FieldComparisonExp extends Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = FieldComparisonExp;
|
module.exports = LabelComparisonExp;
|
29
src/services/search/expressions/property_comparison.js
Normal file
29
src/services/search/expressions/property_comparison.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Expression = require('./expression');
|
||||||
|
const NoteSet = require('../note_set');
|
||||||
|
|
||||||
|
class PropertyComparisonExp extends Expression {
|
||||||
|
constructor(propertyName, comparator) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.propertyName = propertyName;
|
||||||
|
this.comparator = comparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
execute(noteSet, searchContext) {
|
||||||
|
const resNoteSet = new NoteSet();
|
||||||
|
|
||||||
|
for (const note of noteSet.notes) {
|
||||||
|
const value = note[this.propertyName].toLowerCase();
|
||||||
|
|
||||||
|
if (this.comparator(value)) {
|
||||||
|
resNoteSet.add(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resNoteSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PropertyComparisonExp;
|
@ -77,7 +77,7 @@ function lexer(str) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (!quotes) {
|
else if (!quotes) {
|
||||||
if (currentWord.length === 0 && (chr === '#' || chr === '@')) {
|
if (currentWord.length === 0 && (chr === '#' || chr === '~')) {
|
||||||
fulltextEnded = true;
|
fulltextEnded = true;
|
||||||
currentWord = chr;
|
currentWord = chr;
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ function lexer(str) {
|
|||||||
finishWord();
|
finishWord();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (fulltextEnded && ['(', ')'].includes(chr)) {
|
else if (fulltextEnded && ['(', ')', '.'].includes(chr)) {
|
||||||
finishWord();
|
finishWord();
|
||||||
currentWord += chr;
|
currentWord += chr;
|
||||||
finishWord();
|
finishWord();
|
||||||
|
@ -6,11 +6,19 @@ class NoteSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
add(note) {
|
add(note) {
|
||||||
this.notes.push(note);
|
if (!this.hasNote(note)) {
|
||||||
|
this.notes.push(note);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addAll(notes) {
|
addAll(notes) {
|
||||||
this.notes.push(...notes);
|
for (const note of notes) {
|
||||||
|
this.add(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hasNote(note) {
|
||||||
|
return this.hasNoteId(note.noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasNoteId(noteId) {
|
hasNoteId(noteId) {
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
const AndExp = require('./expressions/and');
|
const AndExp = require('./expressions/and');
|
||||||
const OrExp = require('./expressions/or');
|
const OrExp = require('./expressions/or');
|
||||||
const NotExp = require('./expressions/not');
|
const NotExp = require('./expressions/not');
|
||||||
|
const ChildOfExp = require('./expressions/child_of');
|
||||||
|
const PropertyComparisonExp = require('./expressions/property_comparison');
|
||||||
const AttributeExistsExp = require('./expressions/attribute_exists');
|
const AttributeExistsExp = require('./expressions/attribute_exists');
|
||||||
const FieldComparisonExp = require('./expressions/field_comparison');
|
const LabelComparisonExp = require('./expressions/label_comparison');
|
||||||
const NoteCacheFulltextExp = require('./expressions/note_cache_fulltext');
|
const NoteCacheFulltextExp = require('./expressions/note_cache_fulltext');
|
||||||
const NoteContentFulltextExp = require('./expressions/note_content_fulltext');
|
const NoteContentFulltextExp = require('./expressions/note_content_fulltext');
|
||||||
const comparatorBuilder = require('./comparator_builder');
|
const comparatorBuilder = require('./comparator_builder');
|
||||||
@ -38,17 +40,50 @@ function getExpression(tokens, parsingContext) {
|
|||||||
const expressions = [];
|
const expressions = [];
|
||||||
let op = null;
|
let op = null;
|
||||||
|
|
||||||
for (let i = 0; i < tokens.length; i++) {
|
let i;
|
||||||
|
|
||||||
|
function parseNoteProperty() {
|
||||||
|
if (tokens[i] !== '.') {
|
||||||
|
parsingContext.addError('Expected "." to separate field path');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (tokens[i] === 'parent') {
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
return new ChildOfExp(parseNoteProperty());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokens[i] === 'title') {
|
||||||
|
const propertyName = tokens[i];
|
||||||
|
const operator = tokens[i + 1];
|
||||||
|
const comparedValue = tokens[i + 2];
|
||||||
|
const comparator = comparatorBuilder(operator, comparedValue);
|
||||||
|
|
||||||
|
if (!comparator) {
|
||||||
|
parsingContext.addError(`Can't find operator '${operator}'`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 3;
|
||||||
|
|
||||||
|
return new PropertyComparisonExp(propertyName, comparator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < tokens.length; i++) {
|
||||||
const token = tokens[i];
|
const token = tokens[i];
|
||||||
|
|
||||||
if (token === '#' || token === '@') {
|
if (token === '#' || token === '~') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(token)) {
|
if (Array.isArray(token)) {
|
||||||
expressions.push(getExpression(token, parsingContext));
|
expressions.push(getExpression(token, parsingContext));
|
||||||
}
|
}
|
||||||
else if (token.startsWith('#') || token.startsWith('@')) {
|
else if (token.startsWith('#') || token.startsWith('~')) {
|
||||||
const type = token.startsWith('#') ? 'label' : 'relation';
|
const type = token.startsWith('#') ? 'label' : 'relation';
|
||||||
|
|
||||||
parsingContext.highlightedTokens.push(token.substr(1));
|
parsingContext.highlightedTokens.push(token.substr(1));
|
||||||
@ -70,7 +105,7 @@ function getExpression(tokens, parsingContext) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
expressions.push(new FieldComparisonExp(type, token.substr(1), comparator));
|
expressions.push(new LabelComparisonExp(type, token.substr(1), comparator));
|
||||||
|
|
||||||
i += 2;
|
i += 2;
|
||||||
}
|
}
|
||||||
@ -78,11 +113,18 @@ function getExpression(tokens, parsingContext) {
|
|||||||
expressions.push(new AttributeExistsExp(type, token.substr(1), parsingContext.fuzzyAttributeSearch));
|
expressions.push(new AttributeExistsExp(type, token.substr(1), parsingContext.fuzzyAttributeSearch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (['and', 'or'].includes(token.toLowerCase())) {
|
else if (token === 'note') {
|
||||||
|
i++;
|
||||||
|
|
||||||
|
expressions.push(parseNoteProperty(tokens));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (['and', 'or'].includes(token)) {
|
||||||
if (!op) {
|
if (!op) {
|
||||||
op = token.toLowerCase();
|
op = token;
|
||||||
}
|
}
|
||||||
else if (op !== token.toLowerCase()) {
|
else if (op !== token) {
|
||||||
parsingContext.addError('Mixed usage of AND/OR - always use parenthesis to group AND/OR expressions.');
|
parsingContext.addError('Mixed usage of AND/OR - always use parenthesis to group AND/OR expressions.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user