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";
const sql = require('../../services/sql');
const utils = require('../../services/utils');
const noteService = require('../../services/notes');
const noteCacheService = require('../../services/note_cache');
const parseFilters = require('../../services/parse_filters');
const buildSearchQuery = require('../../services/build_search_query');
const searchService = require('../../services/search');
async function searchNotes(req) {
const filters = parseFilters(req.params.searchString);
const noteIds = await searchService.searchForNoteIds(req.params.searchString);
const {query, params} = buildSearchQuery(filters);
const labelFiltersNoteIds = await sql.getColumn(query, params);
return labelFiltersNoteIds.map(noteCacheService.getNotePath).filter(res => !!res);
return noteIds.map(noteCacheService.getNotePath).filter(res => !!res);
}
async function saveSearchToNote(req) {

View file

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

View file

@ -10,7 +10,7 @@ function calculateSmartValue(v) {
}
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;
@ -23,8 +23,8 @@ function calculateSmartValue(v) {
format = "YYYY-MM-DD";
}
else if (keyword === 'WEEK') {
// FIXME
//date = dayjs().add(num, 'day');
// FIXME: this will always use sunday as start of the week
date = dayjs().startOf('week').add(7 * num, 'day');
format = "YYYY-MM-DD";
}
else if (keyword === 'MONTH') {
@ -43,6 +43,18 @@ function calculateSmartValue(v) {
}
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 = [];
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;
};

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) {
// 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) {
@ -156,6 +166,7 @@ module.exports = {
hash,
isEmptyOrWhitespace,
sanitizeSql,
prepareSqlForLike,
stopWatch,
escapeHtml,
unescapeHtml,