mirror of
https://github.com/zadam/trilium.git
synced 2025-02-24 23:13:43 +08:00
refactoring of router search code into service
This commit is contained in:
parent
81dc907afc
commit
62650a4545
6 changed files with 64 additions and 24 deletions
|
@ -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) {
|
||||
|
|
|
@ -55,7 +55,7 @@ function getDesktopFileContent() {
|
|||
}
|
||||
|
||||
function escapePath(path) {
|
||||
return path.replace(" ", "\\ ");
|
||||
return path.replace(/ /g, "\\ ");
|
||||
}
|
||||
|
||||
function getExePath() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
25
src/services/search.js
Normal 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
|
||||
};
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue