refactoring of router search code into service

This commit is contained in:
zadam 2019-03-16 22:19:01 +01:00
parent 81dc907afc
commit 62650a4545
6 changed files with 64 additions and 24 deletions

View File

@ -1,20 +1,13 @@
"use strict"; "use strict";
const sql = require('../../services/sql');
const utils = require('../../services/utils');
const noteService = require('../../services/notes'); const noteService = require('../../services/notes');
const noteCacheService = require('../../services/note_cache'); const noteCacheService = require('../../services/note_cache');
const parseFilters = require('../../services/parse_filters'); const searchService = require('../../services/search');
const buildSearchQuery = require('../../services/build_search_query');
async function searchNotes(req) { async function searchNotes(req) {
const filters = parseFilters(req.params.searchString); const noteIds = await searchService.searchForNoteIds(req.params.searchString);
const {query, params} = buildSearchQuery(filters); return noteIds.map(noteCacheService.getNotePath).filter(res => !!res);
const labelFiltersNoteIds = await sql.getColumn(query, params);
return labelFiltersNoteIds.map(noteCacheService.getNotePath).filter(res => !!res);
} }
async function saveSearchToNote(req) { async function saveSearchToNote(req) {

View File

@ -55,7 +55,7 @@ function getDesktopFileContent() {
} }
function escapePath(path) { function escapePath(path) {
return path.replace(" ", "\\ "); return path.replace(/ /g, "\\ ");
} }
function getExePath() { function getExePath() {

View File

@ -2,7 +2,7 @@ const utils = require('./utils');
const VIRTUAL_ATTRIBUTES = ["dateCreated", "dateCreated", "dateModified", "utcDateCreated", "utcDateModified", "isProtected", "title", "content", "type", "mime", "text"]; const VIRTUAL_ATTRIBUTES = ["dateCreated", "dateCreated", "dateModified", "utcDateCreated", "utcDateModified", "isProtected", "title", "content", "type", "mime", "text"];
module.exports = function(filters) { module.exports = function(filters, selectedColumns = 'notes.*') {
// alias => join // alias => join
const joins = { const joins = {
"notes": null "notes": null
@ -54,7 +54,7 @@ module.exports = function(filters) {
if (orderByFilter) { if (orderByFilter) {
orderBy = orderByFilter.value.split(",").map(prop => { orderBy = orderByFilter.value.split(",").map(prop => {
const direction = prop.includes("-") ? "DESC" : "ASC"; const direction = prop.includes("-") ? "DESC" : "ASC";
const cleanedProp = prop.trim().replace("-", ""); const cleanedProp = prop.trim().replace(/-/g, "");
return getAccessor(cleanedProp) + " " + direction; return getAccessor(cleanedProp) + " " + direction;
}); });
@ -101,17 +101,17 @@ module.exports = function(filters) {
else if (filter.operator === '*=' || filter.operator === '!*=') { else if (filter.operator === '*=' || filter.operator === '!*=') {
where += `${accessor}` where += `${accessor}`
+ (filter.operator.includes('!') ? ' NOT' : '') + (filter.operator.includes('!') ? ' NOT' : '')
+ ` LIKE '%` + filter.value + "'"; // FIXME: escaping + ` LIKE ` + utils.prepareSqlForLike('%', filter.value, '');
} }
else if (filter.operator === '=*' || filter.operator === '!=*') { else if (filter.operator === '=*' || filter.operator === '!=*') {
where += `${accessor}` where += `${accessor}`
+ (filter.operator.includes('!') ? ' NOT' : '') + (filter.operator.includes('!') ? ' NOT' : '')
+ ` LIKE '` + filter.value + "%'"; // FIXME: escaping + ` LIKE '` + utils.prepareSqlForLike('', filter.value, '%');
} }
else if (filter.operator === '*=*' || filter.operator === '!*=*') { else if (filter.operator === '*=*' || filter.operator === '!*=*') {
where += `${accessor}` where += `${accessor}`
+ (filter.operator.includes('!') ? ' NOT' : '') + (filter.operator.includes('!') ? ' NOT' : '')
+ ` LIKE '%` + filter.value + "%'"; // FIXME: escaping + ` LIKE ` + utils.prepareSqlForLike('%', filter.value, '%');
} }
else if ([">", ">=", "<", "<="].includes(filter.operator)) { else if ([">", ">=", "<", "<="].includes(filter.operator)) {
let floatParam; let floatParam;
@ -141,12 +141,13 @@ module.exports = function(filters) {
orderBy.push("notes.title"); orderBy.push("notes.title");
} }
const query = `SELECT DISTINCT notes.noteId FROM notes const query = `SELECT ${selectedColumns} FROM notes
${Object.values(joins).join('\r\n')} ${Object.values(joins).join('\r\n')}
WHERE WHERE
notes.isDeleted = 0 notes.isDeleted = 0
AND (${where}) AND (${where})
ORDER BY ` + orderBy.join(", "); GROUP BY notes.noteId
ORDER BY ${orderBy.join(", ")}`;
console.log(query); console.log(query);
console.log(params); console.log(params);

View File

@ -10,7 +10,7 @@ function calculateSmartValue(v) {
} }
const keyword = match[1].toUpperCase(); const keyword = match[1].toUpperCase();
const num = match[2] ? parseInt(match[2].replace(" ", "")) : 0; // can contain spaces between sign and digits const num = match[2] ? parseInt(match[2].replace(/ /g, "")) : 0; // can contain spaces between sign and digits
let format, date; let format, date;
@ -23,8 +23,8 @@ function calculateSmartValue(v) {
format = "YYYY-MM-DD"; format = "YYYY-MM-DD";
} }
else if (keyword === 'WEEK') { else if (keyword === 'WEEK') {
// FIXME // FIXME: this will always use sunday as start of the week
//date = dayjs().add(num, 'day'); date = dayjs().startOf('week').add(7 * num, 'day');
format = "YYYY-MM-DD"; format = "YYYY-MM-DD";
} }
else if (keyword === 'MONTH') { else if (keyword === 'MONTH') {
@ -43,6 +43,18 @@ function calculateSmartValue(v) {
} }
module.exports = function (searchText) { module.exports = function (searchText) {
// if the string doesn't start with attribute then we consider it as just standard full text search
if (!searchText.trim().startsWith("@")) {
return [
{
relation: 'and',
name: 'text',
operator: '=',
value: searchText
}
]
}
const filters = []; const filters = [];
function trimQuotes(str) { return str.startsWith('"') ? str.substr(1, str.length - 2) : str; } function trimQuotes(str) { return str.startsWith('"') ? str.substr(1, str.length - 2) : str; }
@ -67,7 +79,5 @@ module.exports = function (searchText) {
}); });
} }
console.log(filters);
return filters; return filters;
}; };

25
src/services/search.js Normal file
View File

@ -0,0 +1,25 @@
const repository = require('./repository');
const sql = require('./sql');
const parseFilters = require('./parse_filters');
const buildSearchQuery = require('./build_search_query');
async function searchForNotes(searchString) {
const filters = parseFilters(searchString);
const {query, params} = buildSearchQuery(filters);
return await repository.getEntities(query, params);
}
async function searchForNoteIds(searchString) {
const filters = parseFilters(searchString);
const {query, params} = buildSearchQuery(filters, 'notes.noteId');
return await sql.getColumn(query, params);
}
module.exports = {
searchForNotes,
searchForNoteIds
};

View File

@ -50,7 +50,17 @@ function isEmptyOrWhitespace(str) {
function sanitizeSql(str) { function sanitizeSql(str) {
// should be improved or usage eliminated // should be improved or usage eliminated
return str.replace(/'/g, "\\'"); return str.replace(/'/g, "''");
}
function prepareSqlForLike(prefix, str, suffix) {
const value = str
.replace(/\\/g, "\\\\")
.replace(/'/g, "''")
.replace(/_/g, "\\_")
.replace(/%/g, "\\%");
return `'${prefix}${value}${suffix}' ESCAPE '\\'`;
} }
async function stopWatch(what, func) { async function stopWatch(what, func) {
@ -156,6 +166,7 @@ module.exports = {
hash, hash,
isEmptyOrWhitespace, isEmptyOrWhitespace,
sanitizeSql, sanitizeSql,
prepareSqlForLike,
stopWatch, stopWatch,
escapeHtml, escapeHtml,
unescapeHtml, unescapeHtml,