Files
Trilium/apps/server/src/routes/api/search.ts

135 lines
3.8 KiB
TypeScript
Raw Normal View History

"use strict";
import type { Request } from "express";
2024-04-06 22:48:20 +03:00
import becca from "../../becca/becca.js";
import SearchContext from "../../services/search/search_context.js";
import searchService, { EMPTY_RESULT, type SearchNoteResult } from "../../services/search/services/search.js";
import bulkActionService from "../../services/bulk_actions.js";
import cls from "../../services/cls.js";
import attributeFormatter from "../../services/attribute_formatter.js";
import ValidationError from "../../errors/validation_error.js";
import type SearchResult from "../../services/search/search_result.js";
2024-04-06 22:48:20 +03:00
2024-07-18 22:58:12 +03:00
function searchFromNote(req: Request): SearchNoteResult {
const note = becca.getNoteOrThrow(req.params.noteId);
2023-06-05 09:23:42 +02:00
if (!note) {
// this can be triggered from recent changes, and it's harmless to return an empty list rather than fail
2024-07-18 22:58:12 +03:00
return EMPTY_RESULT;
}
2025-01-09 18:07:02 +02:00
if (note.type !== "search") {
throw new ValidationError(`Note '${req.params.noteId}' is not a search note.`);
}
return searchService.searchFromNote(note);
}
2024-04-06 22:48:20 +03:00
function searchAndExecute(req: Request) {
const note = becca.getNoteOrThrow(req.params.noteId);
2023-06-05 09:23:42 +02:00
if (!note) {
// this can be triggered from recent changes, and it's harmless to return an empty list rather than fail
return [];
}
2025-01-09 18:07:02 +02:00
if (note.type !== "search") {
throw new ValidationError(`Note '${req.params.noteId}' is not a search note.`);
}
2025-01-09 18:07:02 +02:00
const { searchResultNoteIds } = searchService.searchFromNote(note);
2022-06-05 23:36:46 +02:00
bulkActionService.executeActions(note, searchResultNoteIds);
}
2024-04-06 22:48:20 +03:00
function quickSearch(req: Request) {
2025-01-09 18:07:02 +02:00
const { searchString } = req.params;
2021-01-31 22:45:45 +01:00
const searchContext = new SearchContext({
fastSearch: false,
includeArchivedNotes: false,
fuzzyAttributeSearch: false
});
2025-01-09 18:07:02 +02:00
const resultNoteIds = searchService.findResultsWithQuery(searchString, searchContext).map((sr) => sr.noteId);
2022-12-17 11:58:30 +01:00
return {
searchResultNoteIds: resultNoteIds,
error: searchContext.getError()
};
2021-01-31 22:45:45 +01:00
}
2024-04-06 22:48:20 +03:00
function search(req: Request) {
2025-01-09 18:07:02 +02:00
const { searchString } = req.params;
const searchContext = new SearchContext({
fastSearch: false,
includeArchivedNotes: true,
fuzzyAttributeSearch: false,
ignoreHoistedNote: true
});
2025-01-09 18:07:02 +02:00
return searchService.findResultsWithQuery(searchString, searchContext).map((sr) => sr.noteId);
}
2024-04-06 22:48:20 +03:00
function getRelatedNotes(req: Request) {
2020-06-25 23:56:06 +02:00
const attr = req.body;
2020-09-13 22:23:03 +02:00
const searchSettings = {
fastSearch: true,
includeArchivedNotes: false,
2020-09-13 22:23:03 +02:00
fuzzyAttributeSearch: false
};
2024-04-06 22:48:20 +03:00
const matchingNameAndValue = searchService.findResultsWithQuery(attributeFormatter.formatAttrForSearch(attr, true), new SearchContext(searchSettings));
const matchingName = searchService.findResultsWithQuery(attributeFormatter.formatAttrForSearch(attr, false), new SearchContext(searchSettings));
2020-06-25 23:56:06 +02:00
2024-04-06 22:48:20 +03:00
const results: SearchResult[] = [];
2020-06-25 23:56:06 +02:00
const allResults = matchingNameAndValue.concat(matchingName);
const allResultNoteIds = new Set();
for (const record of allResults) {
allResultNoteIds.add(record.noteId);
}
for (const record of allResults) {
2020-06-25 23:56:06 +02:00
if (results.length >= 20) {
break;
}
2025-01-09 18:07:02 +02:00
if (results.find((res) => res.noteId === record.noteId)) {
2020-06-25 23:56:06 +02:00
continue;
}
results.push(record);
}
return {
count: allResultNoteIds.size,
2020-06-25 23:56:06 +02:00
results
};
}
2022-05-31 22:45:57 +02:00
function searchTemplates() {
2025-01-09 18:07:02 +02:00
const query = cls.getHoistedNoteId() === "root" ? "#template" : "#template OR #workspaceTemplate";
return searchService
.searchNotes(query, {
includeArchivedNotes: true,
ignoreHoistedNote: false
})
.map((note) => note.noteId);
2022-05-31 22:45:57 +02:00
}
export default {
2020-06-25 23:56:06 +02:00
searchFromNote,
searchAndExecute,
2021-01-31 22:45:45 +01:00
getRelatedNotes,
quickSearch,
2022-05-31 22:45:57 +02:00
search,
searchTemplates
2020-05-16 23:12:29 +02:00
};