trilium/src/services/search.js

74 lines
2.3 KiB
JavaScript

const repository = require('./repository');
const sql = require('./sql');
const log = require('./log');
const parseFilters = require('./parse_filters');
const buildSearchQuery = require('./build_search_query');
const noteCacheService = require('./note_cache');
async function searchForNotes(searchString) {
const noteIds = await searchForNoteIds(searchString);
return await repository.getNotes(noteIds);
}
async function searchForNoteIds(searchString) {
const filters = parseFilters(searchString);
const {query, params} = buildSearchQuery(filters, 'notes.noteId');
try {
let noteIds = await sql.getColumn(query, params);
noteIds = noteIds.filter(noteCacheService.isAvailable);
const isArchivedFilter = filters.find(filter => filter.name.toLowerCase() === 'isarchived');
if (isArchivedFilter) {
if (isArchivedFilter.operator === 'exists') {
noteIds = noteIds.filter(noteCacheService.isArchived);
}
else if (isArchivedFilter.operator === 'not-exists') {
noteIds = noteIds.filter(noteId => !noteCacheService.isArchived(noteId));
}
else {
throw new Error(`Unrecognized isArchived operator ${isArchivedFilter.operator}`);
}
}
const isInFilters = filters.filter(filter => filter.name.toLowerCase() === 'in');
for (const isInFilter of isInFilters) {
if (isInFilter.operator === '=') {
noteIds = noteIds.filter(noteId => noteCacheService.isInAncestor(noteId, isInFilter.value));
}
else if (isInFilter.operator === '!=') {
noteIds = noteIds.filter(noteId => !noteCacheService.isInAncestor(noteId, isInFilter.value));
}
else {
throw new Error(`Unrecognized isIn operator ${isInFilter.operator}`);
}
}
const limitFilter = filters.find(filter => filter.name.toLowerCase() === 'limit');
if (limitFilter) {
const limit = parseInt(limitFilter.value);
return noteIds.splice(0, limit);
}
else {
return noteIds;
}
}
catch (e) {
log.error("Search failed for " + query);
throw e;
}
}
module.exports = {
searchForNotes,
searchForNoteIds
};