diff --git a/spec/search/parser.spec.js b/spec/search/parser.spec.js index 3de146120..fa0ee5c2a 100644 --- a/spec/search/parser.spec.js +++ b/spec/search/parser.spec.js @@ -1,4 +1,4 @@ -const ParsingContext = require("../../src/services/search/parsing_context.js"); +const SearchContext = require("../../src/services/search/search_context.js"); const parse = require('../../src/services/search/services/parse.js'); function tokens(toks, cur = 0) { @@ -24,7 +24,7 @@ describe("Parser", () => { const rootExp = parse({ fulltextTokens: tokens(["hello", "hi"]), expressionTokens: [], - parsingContext: new ParsingContext({includeNoteContent: false}) + searchContext: new SearchContext({includeNoteContent: false}) }); expect(rootExp.constructor.name).toEqual("AndExp"); @@ -36,7 +36,7 @@ describe("Parser", () => { const rootExp = parse({ fulltextTokens: tokens(["hello", "hi"]), expressionTokens: [], - parsingContext: new ParsingContext({includeNoteContent: true}) + searchContext: new SearchContext({includeNoteContent: true}) }); expect(rootExp.constructor.name).toEqual("AndExp"); @@ -59,7 +59,7 @@ describe("Parser", () => { const rootExp = parse({ fulltextTokens: [], expressionTokens: tokens(["#mylabel", "=", "text"]), - parsingContext: new ParsingContext() + searchContext: new SearchContext() }); expect(rootExp.constructor.name).toEqual("LabelComparisonExp"); @@ -72,7 +72,7 @@ describe("Parser", () => { let rootExp = parse({ fulltextTokens: [], expressionTokens: tokens(["#!mylabel"]), - parsingContext: new ParsingContext() + searchContext: new SearchContext() }); expect(rootExp.constructor.name).toEqual("NotExp"); @@ -83,7 +83,7 @@ describe("Parser", () => { rootExp = parse({ fulltextTokens: [], expressionTokens: tokens(["~!myrelation"]), - parsingContext: new ParsingContext() + searchContext: new SearchContext() }); expect(rootExp.constructor.name).toEqual("NotExp"); @@ -96,7 +96,7 @@ describe("Parser", () => { const rootExp = parse({ fulltextTokens: [], expressionTokens: tokens(["#first", "=", "text", "and", "#second", "=", "text"]), - parsingContext: new ParsingContext(true) + searchContext: new SearchContext(true) }); expect(rootExp.constructor.name).toEqual("AndExp"); @@ -113,7 +113,7 @@ describe("Parser", () => { const rootExp = parse({ fulltextTokens: [], expressionTokens: tokens(["#first", "=", "text", "#second", "=", "text"]), - parsingContext: new ParsingContext() + searchContext: new SearchContext() }); expect(rootExp.constructor.name).toEqual("AndExp"); @@ -130,7 +130,7 @@ describe("Parser", () => { const rootExp = parse({ fulltextTokens: [], expressionTokens: tokens(["#first", "=", "text", "or", "#second", "=", "text"]), - parsingContext: new ParsingContext() + searchContext: new SearchContext() }); expect(rootExp.constructor.name).toEqual("OrExp"); @@ -147,7 +147,7 @@ describe("Parser", () => { const rootExp = parse({ fulltextTokens: tokens(["hello"]), expressionTokens: tokens(["#mylabel", "=", "text"]), - parsingContext: new ParsingContext() + searchContext: new SearchContext() }); expect(rootExp.constructor.name).toEqual("AndExp"); @@ -165,7 +165,7 @@ describe("Parser", () => { const rootExp = parse({ fulltextTokens: [], expressionTokens: tokens(["#first", "=", "text", "or", ["#second", "=", "text", "and", "#third", "=", "text"]]), - parsingContext: new ParsingContext() + searchContext: new SearchContext() }); expect(rootExp.constructor.name).toEqual("OrExp"); @@ -187,39 +187,39 @@ describe("Parser", () => { describe("Invalid expressions", () => { it("incomplete comparison", () => { - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); parse({ fulltextTokens: [], expressionTokens: tokens(["#first", "="]), - parsingContext + searchContext }); - expect(parsingContext.error).toEqual('Misplaced or incomplete expression "="') + expect(searchContext.error).toEqual('Misplaced or incomplete expression "="') }); it("comparison between labels is impossible", () => { - let parsingContext = new ParsingContext(); - parsingContext.originalQuery = "#first = #second"; + let searchContext = new SearchContext(); + searchContext.originalQuery = "#first = #second"; parse({ fulltextTokens: [], expressionTokens: tokens(["#first", "=", "#second"]), - parsingContext + searchContext }); - expect(parsingContext.error).toEqual(`Error near token "#second" in "#first = #second", it's possible to compare with constant only.`); + expect(searchContext.error).toEqual(`Error near token "#second" in "#first = #second", it's possible to compare with constant only.`); - parsingContext = new ParsingContext(); - parsingContext.originalQuery = "#first = note.relations.second"; + searchContext = new SearchContext(); + searchContext.originalQuery = "#first = note.relations.second"; parse({ fulltextTokens: [], expressionTokens: tokens(["#first", "=", "note", ".", "relations", "second"]), - parsingContext + searchContext }); - expect(parsingContext.error).toEqual(`Error near token "note" in "#first = note.relations.second", it's possible to compare with constant only.`); + expect(searchContext.error).toEqual(`Error near token "note" in "#first = note.relations.second", it's possible to compare with constant only.`); const rootExp = parse({ fulltextTokens: [], @@ -228,7 +228,7 @@ describe("Invalid expressions", () => { { token: "=", inQuotes: false }, { token: "#second", inQuotes: true }, ], - parsingContext: new ParsingContext() + searchContext: new SearchContext() }); expect(rootExp.constructor.name).toEqual("LabelComparisonExp"); diff --git a/spec/search/search.spec.js b/spec/search/search.spec.js index e5b051716..e04c29bdc 100644 --- a/spec/search/search.spec.js +++ b/spec/search/search.spec.js @@ -1,7 +1,7 @@ const searchService = require('../../src/services/search/services/search.js'); const Note = require('../../src/services/note_cache/entities/note.js'); const Branch = require('../../src/services/note_cache/entities/branch.js'); -const ParsingContext = require('../../src/services/search/parsing_context.js'); +const SearchContext = require('../../src/services/search/search_context.js'); const dateUtils = require('../../src/services/date_utils.js'); const noteCache = require('../../src/services/note_cache/note_cache.js'); const {NoteBuilder, findNoteByTitle, note} = require('./note_cache_mocking.js'); @@ -22,8 +22,8 @@ describe("Search", () => { .child(note("Austria")) ); - const parsingContext = new ParsingContext(); - const searchResults = searchService.findNotesWithQuery('europe austria', parsingContext); + const searchContext = new SearchContext(); + const searchResults = searchService.findNotesWithQuery('europe austria', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); @@ -39,13 +39,13 @@ describe("Search", () => { .child(vienna .label('inhabitants', '1888776')); - const parsingContext = new ParsingContext(); - let searchResults = searchService.findNotesWithQuery('capital', parsingContext); + const searchContext = new SearchContext(); + let searchResults = searchService.findNotesWithQuery('capital', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); - searchResults = searchService.findNotesWithQuery('inhabitants', parsingContext); + searchResults = searchService.findNotesWithQuery('inhabitants', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Vienna")).toBeTruthy(); @@ -56,18 +56,18 @@ describe("Search", () => { .child(note("Effective Java", 'book', '')) .child(note("Hello World.java", 'code', 'text/x-java')); - const parsingContext = new ParsingContext(); - let searchResults = searchService.findNotesWithQuery('book', parsingContext); + const searchContext = new SearchContext(); + let searchResults = searchService.findNotesWithQuery('book', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Effective Java")).toBeTruthy(); - searchResults = searchService.findNotesWithQuery('text', parsingContext); // should match mime + searchResults = searchService.findNotesWithQuery('text', searchContext); // should match mime expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Hello World.java")).toBeTruthy(); - searchResults = searchService.findNotesWithQuery('java', parsingContext); + searchResults = searchService.findNotesWithQuery('java', searchContext); expect(searchResults.length).toEqual(2); }); @@ -78,8 +78,8 @@ describe("Search", () => { .child(note("Austria")) ); - const parsingContext = new ParsingContext(); - const searchResults = searchService.findNotesWithQuery('europe', parsingContext); + const searchContext = new SearchContext(); + const searchResults = searchService.findNotesWithQuery('europe', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy(); @@ -92,9 +92,9 @@ describe("Search", () => { .label('capital', 'Vienna')) ); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - const searchResults = searchService.findNotesWithQuery('Vienna', parsingContext); + const searchResults = searchService.findNotesWithQuery('Vienna', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); }); @@ -108,9 +108,9 @@ describe("Search", () => { .label('capital', 'Prague')) ); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('#capital=Vienna', parsingContext); + let searchResults = searchService.findNotesWithQuery('#capital=Vienna', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); }); @@ -124,9 +124,9 @@ describe("Search", () => { .label('capital', 'Prague')) ); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('# note.labels.capital=Prague', parsingContext); + let searchResults = searchService.findNotesWithQuery('# note.labels.capital=Prague', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); }); @@ -141,9 +141,9 @@ describe("Search", () => { .label('population', '10650000')) ); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - const searchResults = searchService.findNotesWithQuery('#country #population >= 10000000', parsingContext); + const searchResults = searchService.findNotesWithQuery('#country #population >= 10000000', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); }); @@ -162,13 +162,13 @@ describe("Search", () => { .label('established', '1920-06-04')) ); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('#established <= "1955-01-01"', parsingContext); + let searchResults = searchService.findNotesWithQuery('#established <= "1955-01-01"', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Hungary")).toBeTruthy(); - searchResults = searchService.findNotesWithQuery('#established > "1955-01-01"', parsingContext); + searchResults = searchService.findNotesWithQuery('#established > "1955-01-01"', searchContext); expect(searchResults.length).toEqual(2); expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); @@ -185,10 +185,10 @@ describe("Search", () => { .label('dateTime', dateUtils.localNowDateTime()) ); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); function test(query, expectedResultCount) { - const searchResults = searchService.findNotesWithQuery(query, parsingContext); + const searchResults = searchService.findNotesWithQuery(query, searchContext); expect(searchResults.length).toEqual(expectedResultCount); if (expectedResultCount === 1) { @@ -238,9 +238,9 @@ describe("Search", () => { .label('languageFamily', 'finnougric')) ); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - const searchResults = searchService.findNotesWithQuery('#languageFamily = slavic OR #languageFamily = germanic', parsingContext); + const searchResults = searchService.findNotesWithQuery('#languageFamily = slavic OR #languageFamily = germanic', searchContext); expect(searchResults.length).toEqual(2); expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); @@ -255,20 +255,20 @@ describe("Search", () => { .child(note("Czech Republic") .label('languageFamily', 'slavic'))); - let parsingContext = new ParsingContext({fuzzyAttributeSearch: false}); + let searchContext = new SearchContext({fuzzyAttributeSearch: false}); - let searchResults = searchService.findNotesWithQuery('#language', parsingContext); + let searchResults = searchService.findNotesWithQuery('#language', searchContext); expect(searchResults.length).toEqual(0); - searchResults = searchService.findNotesWithQuery('#languageFamily=ger', parsingContext); + searchResults = searchService.findNotesWithQuery('#languageFamily=ger', searchContext); expect(searchResults.length).toEqual(0); - parsingContext = new ParsingContext({fuzzyAttributeSearch: true}); + searchContext = new SearchContext({fuzzyAttributeSearch: true}); - searchResults = searchService.findNotesWithQuery('#language', parsingContext); + searchResults = searchService.findNotesWithQuery('#language', searchContext); expect(searchResults.length).toEqual(2); - searchResults = searchService.findNotesWithQuery('#languageFamily=ger', parsingContext); + searchResults = searchService.findNotesWithQuery('#languageFamily=ger', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); }); @@ -279,9 +279,9 @@ describe("Search", () => { .child(note("Austria")) .child(note("Czech Republic"))); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - const searchResults = searchService.findNotesWithQuery('# note.title =* czech', parsingContext); + const searchResults = searchService.findNotesWithQuery('# note.title =* czech', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); }); @@ -296,18 +296,18 @@ describe("Search", () => { .child(note("Asia") .child(note('Taiwan'))); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe', parsingContext); + let searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe', searchContext); expect(searchResults.length).toEqual(2); expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); - searchResults = searchService.findNotesWithQuery('# note.parents.title = Asia', parsingContext); + searchResults = searchService.findNotesWithQuery('# note.parents.title = Asia', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Taiwan")).toBeTruthy(); - searchResults = searchService.findNotesWithQuery('# note.parents.parents.title = Europe', parsingContext); + searchResults = searchService.findNotesWithQuery('# note.parents.parents.title = Europe', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Prague")).toBeTruthy(); }); @@ -324,13 +324,13 @@ describe("Search", () => { .child(note('Taipei').label('city'))) ); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('#city AND note.ancestors.title = Europe', parsingContext); + let searchResults = searchService.findNotesWithQuery('#city AND note.ancestors.title = Europe', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Prague")).toBeTruthy(); - searchResults = searchService.findNotesWithQuery('#city AND note.ancestors.title = Asia', parsingContext); + searchResults = searchService.findNotesWithQuery('#city AND note.ancestors.title = Asia', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Taipei")).toBeTruthy(); }); @@ -345,18 +345,18 @@ describe("Search", () => { .child(note("Oceania") .child(note('Australia'))); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('# note.children.title =* Aust', parsingContext); + let searchResults = searchService.findNotesWithQuery('# note.children.title =* Aust', searchContext); expect(searchResults.length).toEqual(2); expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy(); expect(findNoteByTitle(searchResults, "Oceania")).toBeTruthy(); - searchResults = searchService.findNotesWithQuery('# note.children.title =* Aust AND note.children.title *= republic', parsingContext); + searchResults = searchService.findNotesWithQuery('# note.children.title =* Aust AND note.children.title *= republic', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy(); - searchResults = searchService.findNotesWithQuery('# note.children.children.title = Prague', parsingContext); + searchResults = searchService.findNotesWithQuery('# note.children.children.title = Prague', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy(); }); @@ -375,13 +375,13 @@ describe("Search", () => { .relation('neighbor', portugal.note)) ); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('# ~neighbor.title = Austria', parsingContext); + let searchResults = searchService.findNotesWithQuery('# ~neighbor.title = Austria', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); - searchResults = searchService.findNotesWithQuery('# ~neighbor.title = Portugal', parsingContext); + searchResults = searchService.findNotesWithQuery('# ~neighbor.title = Portugal', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Spain")).toBeTruthy(); }); @@ -400,9 +400,9 @@ describe("Search", () => { .relation('neighbor', portugal.note)) ); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - const searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.title = Austria', parsingContext); + const searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.title = Austria', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); }); @@ -426,13 +426,13 @@ describe("Search", () => { .child(ukraine) ); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.relations.neighbor.title = Italy', parsingContext); + let searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.relations.neighbor.title = Italy', searchContext); expect(searchResults.length).toEqual(1); expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); - searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.relations.neighbor.title = Ukraine', parsingContext); + searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.relations.neighbor.title = Ukraine', searchContext); expect(searchResults.length).toEqual(2); expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); @@ -463,10 +463,10 @@ describe("Search", () => { austria.note.utcDateModified = '2020-05-14 11:11:42.001Z'; austria.note.contentLength = 1001; - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); function test(propertyName, value, expectedResultCount) { - const searchResults = searchService.findNotesWithQuery(`# note.${propertyName} = ${value}`, parsingContext); + const searchResults = searchService.findNotesWithQuery(`# note.${propertyName} = ${value}`, searchContext); expect(searchResults.length).toEqual(expectedResultCount); } @@ -520,38 +520,38 @@ describe("Search", () => { .child(austria) .child(italy)); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.title', parsingContext); + let searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.title', searchContext); expect(searchResults.length).toEqual(4); expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Austria"); expect(noteCache.notes[searchResults[1].noteId].title).toEqual("Italy"); expect(noteCache.notes[searchResults[2].noteId].title).toEqual("Slovakia"); expect(noteCache.notes[searchResults[3].noteId].title).toEqual("Ukraine"); - searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital', parsingContext); + searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital', searchContext); expect(searchResults.length).toEqual(4); expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Slovakia"); expect(noteCache.notes[searchResults[1].noteId].title).toEqual("Ukraine"); expect(noteCache.notes[searchResults[2].noteId].title).toEqual("Italy"); expect(noteCache.notes[searchResults[3].noteId].title).toEqual("Austria"); - searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital DESC', parsingContext); + searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital DESC', searchContext); expect(searchResults.length).toEqual(4); expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Austria"); expect(noteCache.notes[searchResults[1].noteId].title).toEqual("Italy"); expect(noteCache.notes[searchResults[2].noteId].title).toEqual("Ukraine"); expect(noteCache.notes[searchResults[3].noteId].title).toEqual("Slovakia"); - searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital DESC limit 2', parsingContext); + searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital DESC limit 2', searchContext); expect(searchResults.length).toEqual(2); expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Austria"); expect(noteCache.notes[searchResults[1].noteId].title).toEqual("Italy"); - searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 0', parsingContext); + searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 0', searchContext); expect(searchResults.length).toEqual(0); - searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 1000', parsingContext); + searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 1000', searchContext); expect(searchResults.length).toEqual(4); }); @@ -564,13 +564,13 @@ describe("Search", () => { .child(slovakia) .child(italy)); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('# not(#capital) and note.noteId != root', parsingContext); + let searchResults = searchService.findNotesWithQuery('# not(#capital) and note.noteId != root', searchContext); expect(searchResults.length).toEqual(1); expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Europe"); - searchResults = searchService.findNotesWithQuery('#!capital and note.noteId != root', parsingContext); + searchResults = searchService.findNotesWithQuery('#!capital and note.noteId != root', searchContext); expect(searchResults.length).toEqual(1); expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Europe"); }); @@ -584,9 +584,9 @@ describe("Search", () => { .child(slovakia) .child(italy)); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('# note.text *=* rati and note.noteId != root', parsingContext); + let searchResults = searchService.findNotesWithQuery('# note.text *=* rati and note.noteId != root', searchContext); expect(searchResults.length).toEqual(1); expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Slovakia"); }); @@ -601,9 +601,9 @@ describe("Search", () => { .child(note('Post Y'))) .child(note ('Reddit is bad')); - const parsingContext = new ParsingContext(); + const searchContext = new SearchContext(); - let searchResults = searchService.findNotesWithQuery('reddit', parsingContext); + let searchResults = searchService.findNotesWithQuery('reddit', searchContext); expect(searchResults.length).toEqual(1); expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Reddit is bad"); }); @@ -624,9 +624,9 @@ describe("Search", () => { // .label('largestCity', 'Prague')) // ); // - // const parsingContext = new ParsingContext(); + // const searchContext = new SearchContext(); // - // const searchResults = searchService.findNotesWithQuery('#capital = #largestCity', parsingContext); + // const searchResults = searchService.findNotesWithQuery('#capital = #largestCity', searchContext); // expect(searchResults.length).toEqual(2); // expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); // expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy(); diff --git a/src/routes/api/search.js b/src/routes/api/search.js index e07832c19..7237e0053 100644 --- a/src/routes/api/search.js +++ b/src/routes/api/search.js @@ -1,19 +1,19 @@ "use strict"; const repository = require('../../services/repository'); -const ParsingContext = require('../../services/search/parsing_context'); +const SearchContext = require('../../services/search/search_context.js'); const log = require('../../services/log'); const scriptService = require('../../services/script'); const searchService = require('../../services/search/services/search'); function searchNotes(req) { - const parsingContext = new ParsingContext({ + const searchContext = new SearchContext({ includeNoteContent: req.query.includeNoteContent === 'true', excludeArchived: req.query.excludeArchived === 'true', fuzzyAttributeSearch: req.query.fuzzyAttributeSearch === 'true' }); - const {count, results} = searchService.searchTrimmedNotes(req.params.searchString, parsingContext); + const {count, results} = searchService.searchTrimmedNotes(req.params.searchString, searchContext); try { return { diff --git a/src/services/backend_script_api.js b/src/services/backend_script_api.js index 46a2cfd80..f6690d348 100644 --- a/src/services/backend_script_api.js +++ b/src/services/backend_script_api.js @@ -12,7 +12,7 @@ const dayjs = require('dayjs'); const cloningService = require('./cloning'); const appInfo = require('./app_info'); const searchService = require('./search/services/search'); -const ParsingContext = require("./search/parsing_context"); +const SearchContext = require("./search/search_context.js"); /** * This is the main backend API interface for scripts. It's published in the local "api" object. @@ -92,13 +92,13 @@ function BackendScriptApi(currentNote, apiParams) { * * @method * @param {string} query - * @param {ParsingContext} [parsingContext] + * @param {SearchContext} [searchContext] * @returns {Note[]} */ - this.searchForNotes = (query, parsingContext) => { - parsingContext = parsingContext || new ParsingContext(); + this.searchForNotes = (query, searchContext) => { + searchContext = searchContext || new SearchContext(); - const noteIds = searchService.findNotesWithQuery(query, parsingContext) + const noteIds = searchService.findNotesWithQuery(query, searchContext) .map(sr => sr.noteId); return repository.getNotes(noteIds); diff --git a/src/services/search/parsing_context.js b/src/services/search/search_context.js similarity index 90% rename from src/services/search/parsing_context.js rename to src/services/search/search_context.js index 93bf6d923..4b6a83d4a 100644 --- a/src/services/search/parsing_context.js +++ b/src/services/search/search_context.js @@ -1,6 +1,6 @@ "use strict"; -class ParsingContext { +class SearchContext { constructor(params = {}) { this.includeNoteContent = !!params.includeNoteContent; this.excludeArchived = !!params.excludeArchived; @@ -18,4 +18,4 @@ class ParsingContext { } } -module.exports = ParsingContext; +module.exports = SearchContext; diff --git a/src/services/search/services/parse.js b/src/services/search/services/parse.js index 29b9a699b..06ecc8bd4 100644 --- a/src/services/search/services/parse.js +++ b/src/services/search/services/parse.js @@ -18,16 +18,16 @@ const OrderByAndLimitExp = require('../expressions/order_by_and_limit.js'); const buildComparator = require('./build_comparator.js'); const ValueExtractor = require('../value_extractor.js'); -function getFulltext(tokens, parsingContext) { +function getFulltext(tokens, searchContext) { tokens = tokens.map(t => t.token); - parsingContext.highlightedTokens.push(...tokens); + searchContext.highlightedTokens.push(...tokens); if (tokens.length === 0) { return null; } - if (parsingContext.includeNoteContent) { + if (searchContext.includeNoteContent) { return new OrExp([ new NoteCacheFulltextExp(tokens), new NoteContentProtectedFulltextExp('*=*', tokens), @@ -43,7 +43,7 @@ function isOperator(str) { return str.match(/^[=<>*]+$/); } -function getExpression(tokens, parsingContext, level = 0) { +function getExpression(tokens, searchContext, level = 0) { if (tokens.length === 0) { return null; } @@ -56,11 +56,11 @@ function getExpression(tokens, parsingContext, level = 0) { function context(i) { let {startIndex, endIndex} = tokens[i]; startIndex = Math.max(0, startIndex - 20); - endIndex = Math.min(parsingContext.originalQuery.length, endIndex + 20); + endIndex = Math.min(searchContext.originalQuery.length, endIndex + 20); return '"' + (startIndex !== 0 ? "..." : "") - + parsingContext.originalQuery.substr(startIndex, endIndex - startIndex) - + (endIndex !== parsingContext.originalQuery.length ? "..." : "") + '"'; + + searchContext.originalQuery.substr(startIndex, endIndex - startIndex) + + (endIndex !== searchContext.originalQuery.length ? "..." : "") + '"'; } function resolveConstantOperand() { @@ -68,7 +68,7 @@ function getExpression(tokens, parsingContext, level = 0) { if (!operand.inQuotes && (operand.token.startsWith('#') || operand.token.startsWith('~') || operand.token === 'note')) { - parsingContext.addError(`Error near token "${operand.token}" in ${context(i)}, it's possible to compare with constant only.`); + searchContext.addError(`Error near token "${operand.token}" in ${context(i)}, it's possible to compare with constant only.`); return null; } @@ -114,7 +114,7 @@ function getExpression(tokens, parsingContext, level = 0) { function parseNoteProperty() { if (tokens[i].token !== '.') { - parsingContext.addError('Expected "." to separate field path'); + searchContext.addError('Expected "." to separate field path'); return; } @@ -126,7 +126,7 @@ function getExpression(tokens, parsingContext, level = 0) { const operator = tokens[i].token; if (!isOperator(operator)) { - parsingContext.addError(`After content expected operator, but got "${tokens[i].token}" in ${context(i)}`); + searchContext.addError(`After content expected operator, but got "${tokens[i].token}" in ${context(i)}`); return; } @@ -158,7 +158,7 @@ function getExpression(tokens, parsingContext, level = 0) { if (tokens[i].token === 'labels') { if (tokens[i + 1].token !== '.') { - parsingContext.addError(`Expected "." to separate field path, got "${tokens[i + 1].token}" in ${context(i)}`); + searchContext.addError(`Expected "." to separate field path, got "${tokens[i + 1].token}" in ${context(i)}`); return; } @@ -169,7 +169,7 @@ function getExpression(tokens, parsingContext, level = 0) { if (tokens[i].token === 'relations') { if (tokens[i + 1].token !== '.') { - parsingContext.addError(`Expected "." to separate field path, got "${tokens[i + 1].token}" in ${context(i)}`); + searchContext.addError(`Expected "." to separate field path, got "${tokens[i + 1].token}" in ${context(i)}`); return; } @@ -180,13 +180,13 @@ function getExpression(tokens, parsingContext, level = 0) { if (tokens[i].token === 'text') { if (tokens[i + 1].token !== '*=*') { - parsingContext.addError(`Virtual attribute "note.text" supports only *=* operator, instead given "${tokens[i + 1].token}" in ${context(i)}`); + searchContext.addError(`Virtual attribute "note.text" supports only *=* operator, instead given "${tokens[i + 1].token}" in ${context(i)}`); return; } i += 2; - return getFulltext([tokens[i]], parsingContext); + return getFulltext([tokens[i]], searchContext); } if (PropertyComparisonExp.isProperty(tokens[i].token)) { @@ -196,7 +196,7 @@ function getExpression(tokens, parsingContext, level = 0) { const comparator = buildComparator(operator, comparedValue); if (!comparator) { - parsingContext.addError(`Can't find operator '${operator}' in ${context(i)}`); + searchContext.addError(`Can't find operator '${operator}' in ${context(i)}`); return; } @@ -205,7 +205,7 @@ function getExpression(tokens, parsingContext, level = 0) { return new PropertyComparisonExp(propertyName, comparator); } - parsingContext.addError(`Unrecognized note property "${tokens[i].token}" in ${context(i)}`); + searchContext.addError(`Unrecognized note property "${tokens[i].token}" in ${context(i)}`); } function parseAttribute(name) { @@ -225,7 +225,7 @@ function getExpression(tokens, parsingContext, level = 0) { } function parseLabel(labelName) { - parsingContext.highlightedTokens.push(labelName); + searchContext.highlightedTokens.push(labelName); if (i < tokens.length - 2 && isOperator(tokens[i + 1].token)) { let operator = tokens[i + 1].token; @@ -238,33 +238,33 @@ function getExpression(tokens, parsingContext, level = 0) { return; } - parsingContext.highlightedTokens.push(comparedValue); + searchContext.highlightedTokens.push(comparedValue); - if (parsingContext.fuzzyAttributeSearch && operator === '=') { + if (searchContext.fuzzyAttributeSearch && operator === '=') { operator = '*=*'; } const comparator = buildComparator(operator, comparedValue); if (!comparator) { - parsingContext.addError(`Can't find operator '${operator}' in ${context(i - 1)}`); + searchContext.addError(`Can't find operator '${operator}' in ${context(i - 1)}`); } else { return new LabelComparisonExp('label', labelName, comparator); } } else { - return new AttributeExistsExp('label', labelName, parsingContext.fuzzyAttributeSearch); + return new AttributeExistsExp('label', labelName, searchContext.fuzzyAttributeSearch); } } function parseRelation(relationName) { - parsingContext.highlightedTokens.push(relationName); + searchContext.highlightedTokens.push(relationName); if (i < tokens.length - 2 && tokens[i + 1].token === '.') { i += 1; return new RelationWhereExp(relationName, parseNoteProperty()); } else { - return new AttributeExistsExp('relation', relationName, parsingContext.fuzzyAttributeSearch); + return new AttributeExistsExp('relation', relationName, searchContext.fuzzyAttributeSearch); } } @@ -293,7 +293,7 @@ function getExpression(tokens, parsingContext, level = 0) { const valueExtractor = new ValueExtractor(propertyPath); if (valueExtractor.validate()) { - parsingContext.addError(valueExtractor.validate()); + searchContext.addError(valueExtractor.validate()); } orderDefinitions.push({ @@ -321,7 +321,7 @@ function getExpression(tokens, parsingContext, level = 0) { for (i = 0; i < tokens.length; i++) { if (Array.isArray(tokens[i])) { - expressions.push(getExpression(tokens[i], parsingContext, level++)); + expressions.push(getExpression(tokens[i], searchContext, level++)); continue; } @@ -336,7 +336,7 @@ function getExpression(tokens, parsingContext, level = 0) { } else if (['orderby', 'limit'].includes(token)) { if (level !== 0) { - parsingContext.addError('orderBy can appear only on the top expression level'); + searchContext.addError('orderBy can appear only on the top expression level'); continue; } @@ -354,11 +354,11 @@ function getExpression(tokens, parsingContext, level = 0) { i += 1; if (!Array.isArray(tokens[i])) { - parsingContext.addError(`not keyword should be followed by sub-expression in parenthesis, got ${tokens[i].token} instead`); + searchContext.addError(`not keyword should be followed by sub-expression in parenthesis, got ${tokens[i].token} instead`); continue; } - expressions.push(new NotExp(getExpression(tokens[i], parsingContext, level++))); + expressions.push(new NotExp(getExpression(tokens[i], searchContext, level++))); } else if (token === 'note') { i++; @@ -372,14 +372,14 @@ function getExpression(tokens, parsingContext, level = 0) { op = token; } else if (op !== token) { - parsingContext.addError('Mixed usage of AND/OR - always use parenthesis to group AND/OR expressions.'); + searchContext.addError('Mixed usage of AND/OR - always use parenthesis to group AND/OR expressions.'); } } else if (isOperator(token)) { - parsingContext.addError(`Misplaced or incomplete expression "${token}"`); + searchContext.addError(`Misplaced or incomplete expression "${token}"`); } else { - parsingContext.addError(`Unrecognized expression "${token}"`); + searchContext.addError(`Unrecognized expression "${token}"`); } if (!op && expressions.length > 1) { @@ -390,11 +390,11 @@ function getExpression(tokens, parsingContext, level = 0) { return getAggregateExpression(); } -function parse({fulltextTokens, expressionTokens, parsingContext}) { +function parse({fulltextTokens, expressionTokens, searchContext}) { return AndExp.of([ - parsingContext.excludeArchived ? new PropertyComparisonExp("isarchived", buildComparator("=", "false")) : null, - getFulltext(fulltextTokens, parsingContext), - getExpression(expressionTokens, parsingContext) + searchContext.excludeArchived ? new PropertyComparisonExp("isarchived", buildComparator("=", "false")) : null, + getFulltext(fulltextTokens, searchContext), + getExpression(expressionTokens, searchContext) ]); } diff --git a/src/services/search/services/search.js b/src/services/search/services/search.js index 1a2263703..7254db96c 100644 --- a/src/services/search/services/search.js +++ b/src/services/search/services/search.js @@ -5,7 +5,7 @@ const handleParens = require('./handle_parens.js'); const parse = require('./parse.js'); const NoteSet = require("../note_set.js"); const SearchResult = require("../search_result.js"); -const ParsingContext = require("../parsing_context.js"); +const SearchContext = require("../search_context.js"); const noteCache = require('../../note_cache/note_cache.js'); const noteCacheService = require('../../note_cache/note_cache_service.js'); const hoistedNoteService = require('../../hoisted_note.js'); @@ -50,14 +50,14 @@ function findNotesWithExpression(expression) { return searchResults; } -function parseQueryToExpression(query, parsingContext) { +function parseQueryToExpression(query, searchContext) { const {fulltextTokens, expressionTokens} = lex(query); const structuredExpressionTokens = handleParens(expressionTokens); const expression = parse({ fulltextTokens, expressionTokens: structuredExpressionTokens, - parsingContext, + searchContext, originalQuery: query }); @@ -66,16 +66,16 @@ function parseQueryToExpression(query, parsingContext) { /** * @param {string} query - * @param {ParsingContext} parsingContext + * @param {SearchContext} searchContext * @return {SearchResult[]} */ -function findNotesWithQuery(query, parsingContext) { +function findNotesWithQuery(query, searchContext) { if (!query.trim().length) { return []; } return utils.stopWatch(`Search with query "${query}"`, () => { - const expression = parseQueryToExpression(query, parsingContext); + const expression = parseQueryToExpression(query, searchContext); if (!expression) { return []; @@ -85,8 +85,8 @@ function findNotesWithQuery(query, parsingContext) { }, 20); } -function searchTrimmedNotes(query, parsingContext) { - const allSearchResults = findNotesWithQuery(query, parsingContext); +function searchTrimmedNotes(query, searchContext) { + const allSearchResults = findNotesWithQuery(query, searchContext); const trimmedSearchResults = allSearchResults.slice(0, 200); return { @@ -96,15 +96,15 @@ function searchTrimmedNotes(query, parsingContext) { } function searchNotesForAutocomplete(query) { - const parsingContext = new ParsingContext({ + const searchContext = new SearchContext({ includeNoteContent: false, excludeArchived: true, fuzzyAttributeSearch: true }); - const {results} = searchTrimmedNotes(query, parsingContext); + const {results} = searchTrimmedNotes(query, searchContext); - highlightSearchResults(results, parsingContext.highlightedTokens); + highlightSearchResults(results, searchContext.highlightedTokens); return results.map(result => { return {