From 75d8627f1cf6f4ab8d34dfbadf92536d523da546 Mon Sep 17 00:00:00 2001 From: zadam Date: Thu, 21 May 2020 11:46:01 +0200 Subject: [PATCH] refactoring to ParserContext --- spec/parser.spec.js | 17 +++++++++-------- src/services/search/parser.js | 25 +++++++++++++------------ src/services/search/parsing_context.js | 18 ++++++++++++++++++ src/services/search/search.js | 14 ++++++++------ 4 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 src/services/search/parsing_context.js diff --git a/spec/parser.spec.js b/spec/parser.spec.js index 05fabea01..466d90363 100644 --- a/spec/parser.spec.js +++ b/spec/parser.spec.js @@ -1,3 +1,4 @@ +const ParsingContext = require("../src/services/search/parsing_context"); const parser = require('../src/services/search/parser'); describe("Parser", () => { @@ -5,7 +6,7 @@ describe("Parser", () => { const rootExp = parser({ fulltextTokens: ["hello", "hi"], expressionTokens: [], - includingNoteContent: false + parsingContext: new ParsingContext(false) }); expect(rootExp.constructor.name).toEqual("NoteCacheFulltextExp"); @@ -16,7 +17,7 @@ describe("Parser", () => { const rootExp = parser({ fulltextTokens: ["hello", "hi"], expressionTokens: [], - includingNoteContent: true + parsingContext: new ParsingContext(true) }); expect(rootExp.constructor.name).toEqual("OrExp"); @@ -33,7 +34,7 @@ describe("Parser", () => { const rootExp = parser({ fulltextTokens: [], expressionTokens: ["#mylabel", "=", "text"], - includingNoteContent: true + parsingContext: new ParsingContext(true) }); expect(rootExp.constructor.name).toEqual("FieldComparisonExp"); @@ -46,7 +47,7 @@ describe("Parser", () => { const rootExp = parser({ fulltextTokens: [], expressionTokens: ["#first", "=", "text", "AND", "#second", "=", "text"], - includingNoteContent: true + parsingContext: new ParsingContext(true) }); expect(rootExp.constructor.name).toEqual("AndExp"); @@ -63,7 +64,7 @@ describe("Parser", () => { const rootExp = parser({ fulltextTokens: [], expressionTokens: ["#first", "=", "text", "#second", "=", "text"], - includingNoteContent: true + parsingContext: new ParsingContext(true) }); expect(rootExp.constructor.name).toEqual("AndExp"); @@ -80,7 +81,7 @@ describe("Parser", () => { const rootExp = parser({ fulltextTokens: [], expressionTokens: ["#first", "=", "text", "OR", "#second", "=", "text"], - includingNoteContent: true + parsingContext: new ParsingContext(true) }); expect(rootExp.constructor.name).toEqual("OrExp"); @@ -97,7 +98,7 @@ describe("Parser", () => { const rootExp = parser({ fulltextTokens: ["hello"], expressionTokens: ["#mylabel", "=", "text"], - includingNoteContent: false + parsingContext: new ParsingContext(false) }); expect(rootExp.constructor.name).toEqual("AndExp"); @@ -114,7 +115,7 @@ describe("Parser", () => { const rootExp = parser({ fulltextTokens: [], expressionTokens: ["#first", "=", "text", "OR", ["#second", "=", "text", "AND", "#third", "=", "text"]], - includingNoteContent: false + parsingContext: new ParsingContext(false) }); expect(rootExp.constructor.name).toEqual("OrExp"); diff --git a/src/services/search/parser.js b/src/services/search/parser.js index d63d14374..e92d07129 100644 --- a/src/services/search/parser.js +++ b/src/services/search/parser.js @@ -1,3 +1,6 @@ +"use strict"; + +const ParsingContext = require('./parsing_context'); const AndExp = require('./expressions/and'); const OrExp = require('./expressions/or'); const NotExp = require('./expressions/not'); @@ -7,13 +10,13 @@ const NoteCacheFulltextExp = require('./expressions/note_cache_fulltext'); const NoteContentFulltextExp = require('./expressions/note_content_fulltext'); const comparatorBuilder = require('./comparator_builder'); -function getFulltext(tokens, includingNoteContent, highlightedTokens) { - highlightedTokens.push(...tokens); +function getFulltext(tokens, parsingContext) { + parsingContext.highlightedTokens.push(...tokens); if (tokens.length === 0) { return null; } - else if (includingNoteContent) { + else if (parsingContext.includeNoteContent) { return new OrExp([ new NoteCacheFulltextExp(tokens), new NoteContentFulltextExp(tokens) @@ -28,7 +31,7 @@ function isOperator(str) { return str.match(/^[=<>*]+$/); } -function getExpression(tokens, highlightedTokens) { +function getExpression(tokens, parsingContext) { if (tokens.length === 0) { return null; } @@ -44,18 +47,18 @@ function getExpression(tokens, highlightedTokens) { } if (Array.isArray(token)) { - expressions.push(getExpression(token, highlightedTokens)); + expressions.push(getExpression(token, parsingContext)); } else if (token.startsWith('#') || token.startsWith('@')) { const type = token.startsWith('#') ? 'label' : 'relation'; - highlightedTokens.push(token.substr(1)); + parsingContext.highlightedTokens.push(token.substr(1)); if (i < tokens.length - 2 && isOperator(tokens[i + 1])) { const operator = tokens[i + 1]; const comparedValue = tokens[i + 2]; - highlightedTokens.push(comparedValue); + parsingContext.highlightedTokens.push(comparedValue); const comparator = comparatorBuilder(operator, comparedValue); @@ -99,12 +102,10 @@ function getExpression(tokens, highlightedTokens) { } } -function parse({fulltextTokens, expressionTokens, includingNoteContent, highlightedTokens}) { - highlightedTokens = highlightedTokens || []; - +function parse({fulltextTokens, expressionTokens, parsingContext}) { return AndExp.of([ - getFulltext(fulltextTokens, includingNoteContent, highlightedTokens), - getExpression(expressionTokens, highlightedTokens) + getFulltext(fulltextTokens, parsingContext), + getExpression(expressionTokens, parsingContext) ]); } diff --git a/src/services/search/parsing_context.js b/src/services/search/parsing_context.js new file mode 100644 index 000000000..f76ff3b3d --- /dev/null +++ b/src/services/search/parsing_context.js @@ -0,0 +1,18 @@ +"use strict"; + +class ParsingContext { + constructor(includeNoteContent) { + this.includeNoteContent = includeNoteContent; + this.highlightedTokens = []; + this.error = null; + } + + addError(error) { + // we record only the first error, subsequent ones are usually consequence of the first + if (!this.error) { + this.error = error; + } + } +} + +module.exports = ParsingContext; diff --git a/src/services/search/search.js b/src/services/search/search.js index a4d86802f..1eb6faf77 100644 --- a/src/services/search/search.js +++ b/src/services/search/search.js @@ -42,15 +42,14 @@ async function findNotesWithExpression(expression) { return searchResults; } -function parseQueryToExpression(query, highlightedTokens) { +function parseQueryToExpression(query, parsingContext) { const {fulltextTokens, expressionTokens} = lexer(query); const structuredExpressionTokens = parens(expressionTokens); const expression = parser({ fulltextTokens, expressionTokens: structuredExpressionTokens, - includingNoteContent: false, - highlightedTokens + parsingContext }); return expression; @@ -61,9 +60,12 @@ async function searchNotesForAutocomplete(query) { return []; } - const highlightedTokens = []; + const parsingContext = { + includeNoteContent: false, + highlightedTokens: [] + }; - const expression = parseQueryToExpression(query, highlightedTokens); + const expression = parseQueryToExpression(query, parsingContext); if (!expression) { return []; @@ -73,7 +75,7 @@ async function searchNotesForAutocomplete(query) { searchResults = searchResults.slice(0, 200); - highlightSearchResults(searchResults, highlightedTokens); + highlightSearchResults(searchResults, parsingContext.highlightedTokens); return searchResults.map(result => { return {