From 81dc907afc0360305aba4822817040bcb803e858 Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 16 Mar 2019 20:52:21 +0100 Subject: [PATCH] ordering of search results --- src/services/build_search_query.js | 42 ++++++++++++++++++++++++++---- src/services/parse_filters.js | 2 +- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/services/build_search_query.js b/src/services/build_search_query.js index 6ee1d4f38..69c299368 100644 --- a/src/services/build_search_query.js +++ b/src/services/build_search_query.js @@ -1,3 +1,5 @@ +const utils = require('./utils'); + const VIRTUAL_ATTRIBUTES = ["dateCreated", "dateCreated", "dateModified", "utcDateCreated", "utcDateModified", "isProtected", "title", "content", "type", "mime", "text"]; module.exports = function(filters) { @@ -21,10 +23,9 @@ module.exports = function(filters) { accessor = `${alias}.value`; } else if (property === 'content') { - const alias = "note_content"; + const alias = "note_contents"; if (!(alias in joins)) { - // FIXME: this will fail if there's more instances of content joins[alias] = `JOIN note_contents ON note_contents.noteId = notes.noteId`; } @@ -34,7 +35,6 @@ module.exports = function(filters) { const alias = "note_fulltext"; if (!(alias in joins)) { - // FIXME: this will fail if there's more instances of content joins[alias] = `JOIN note_fulltext ON note_fulltext.noteId = notes.noteId`; } @@ -47,10 +47,27 @@ module.exports = function(filters) { return accessor; } + let orderBy = []; + + const orderByFilter = filters.find(filter => filter.name.toLowerCase() === 'orderby'); + + if (orderByFilter) { + orderBy = orderByFilter.value.split(",").map(prop => { + const direction = prop.includes("-") ? "DESC" : "ASC"; + const cleanedProp = prop.trim().replace("-", ""); + + return getAccessor(cleanedProp) + " " + direction; + }); + } + let where = '1'; const params = []; for (const filter of filters) { + if (filter.name.toLowerCase() === 'orderby') { + continue; // orderby is not real filter + } + where += " " + filter.relation + " "; const accessor = getAccessor(filter.name); @@ -64,8 +81,17 @@ module.exports = function(filters) { else if (filter.operator === '=' || filter.operator === '!=') { if (filter.name === 'text') { const safeSearchText = utils.sanitizeSql(filter.value); + let condition = accessor + ' ' + `MATCH '${safeSearchText}'`; - where += accessor + ' ' + (filter.operator === '!=' ? 'NOT ' : '') + `MATCH '${safeSearchText}'`; + if (filter.operator.includes("!")) { + // not supported! + } + else if (orderBy.length === 0) { + // if there's a positive full text search and there's no defined order then order by rank + orderBy.push("rank"); + } + + where += condition; } else { where += `${accessor} ${filter.operator} ?`; @@ -110,11 +136,17 @@ module.exports = function(filters) { } } + if (orderBy.length === 0) { + // if no ordering is given then order at least by note title + orderBy.push("notes.title"); + } + const query = `SELECT DISTINCT notes.noteId FROM notes ${Object.values(joins).join('\r\n')} WHERE notes.isDeleted = 0 - AND (${where})`; + AND (${where}) + ORDER BY ` + orderBy.join(", "); console.log(query); console.log(params); diff --git a/src/services/parse_filters.js b/src/services/parse_filters.js index 91871350f..9c8fe85c5 100644 --- a/src/services/parse_filters.js +++ b/src/services/parse_filters.js @@ -1,6 +1,6 @@ const dayjs = require("dayjs"); -const filterRegex = /(\b(AND|OR)\s+)?@(!?)([\w_]+|"[^"]+")((=|!=|<|<=|>|>=|!?\*=|!?=\*|!?\*=\*)([\w_-]+|"[^"]+"))?/ig; +const filterRegex = /(\b(AND|OR)\s+)?@(!?)([\w_]+|"[^"]+")\s*((=|!=|<|<=|>|>=|!?\*=|!?=\*|!?\*=\*)\s*([\w_-]+|"[^"]+"))?/ig; const smartValueRegex = /^(NOW|TODAY|WEEK|MONTH|YEAR) *([+\-] *\d+)?$/i; function calculateSmartValue(v) {