mirror of
https://github.com/zadam/trilium.git
synced 2025-10-19 22:58:52 +02:00
feat(search): also implement defensive checks for undefined notes
This commit is contained in:
parent
583ab8dc92
commit
5b669ca287
@ -57,7 +57,11 @@ class NoteFlatTextExp extends Expression {
|
||||
const foundAttrTokens: string[] = [];
|
||||
|
||||
for (const token of remainingTokens) {
|
||||
if (note.type.includes(token) || note.mime.includes(token)) {
|
||||
// Add defensive checks for undefined properties
|
||||
const typeMatches = note.type && note.type.includes(token);
|
||||
const mimeMatches = note.mime && note.mime.includes(token);
|
||||
|
||||
if (typeMatches || mimeMatches) {
|
||||
foundAttrTokens.push(token);
|
||||
}
|
||||
}
|
||||
@ -105,7 +109,11 @@ class NoteFlatTextExp extends Expression {
|
||||
const foundAttrTokens: string[] = [];
|
||||
|
||||
for (const token of this.tokens) {
|
||||
if (note.type.includes(token) || note.mime.includes(token)) {
|
||||
// Add defensive checks for undefined properties
|
||||
const typeMatches = note.type && note.type.includes(token);
|
||||
const mimeMatches = note.mime && note.mime.includes(token);
|
||||
|
||||
if (typeMatches || mimeMatches) {
|
||||
foundAttrTokens.push(token);
|
||||
}
|
||||
|
||||
|
@ -25,25 +25,25 @@ describe("Progressive Search Strategy", () => {
|
||||
it("should complete search with exact matches when sufficient results found", () => {
|
||||
// Create notes with exact matches
|
||||
rootNote
|
||||
.child(note("Test Document One"))
|
||||
.child(note("Test Report Two"))
|
||||
.child(note("Test Analysis Three"))
|
||||
.child(note("Test Summary Four"))
|
||||
.child(note("Test Review Five"))
|
||||
.child(note("Typo Test Documnt")); // This has a typo
|
||||
.child(note("Document Analysis One"))
|
||||
.child(note("Document Report Two"))
|
||||
.child(note("Document Review Three"))
|
||||
.child(note("Document Summary Four"))
|
||||
.child(note("Document Overview Five"))
|
||||
.child(note("Documnt Analysis Six")); // This has a typo that should require fuzzy matching
|
||||
|
||||
const searchContext = new SearchContext();
|
||||
const searchResults = searchService.findResultsWithQuery("test", searchContext);
|
||||
const searchResults = searchService.findResultsWithQuery("document", searchContext);
|
||||
|
||||
// Should find 5+ exact matches and not process the typo
|
||||
expect(searchResults.length).toBeGreaterThanOrEqual(5);
|
||||
// Should find 5 exact matches and not need fuzzy matching
|
||||
expect(searchResults.length).toEqual(5);
|
||||
|
||||
// Verify all results have high scores (exact matches)
|
||||
const highQualityResults = searchResults.filter(result => result.score >= 10);
|
||||
expect(highQualityResults.length).toBeGreaterThanOrEqual(5);
|
||||
expect(highQualityResults.length).toEqual(5);
|
||||
|
||||
// The typo document should not be in results since we have enough exact matches
|
||||
expect(findNoteByTitle(searchResults, "Typo Test Documnt")).toBeFalsy();
|
||||
expect(findNoteByTitle(searchResults, "Documnt Analysis Six")).toBeFalsy();
|
||||
});
|
||||
|
||||
it("should use exact match scoring only in Phase 1", () => {
|
||||
|
@ -583,16 +583,15 @@ describe("Search", () => {
|
||||
.child(note("Analysis Report")) // Exact match
|
||||
.child(note("Data Analysis")) // Exact match
|
||||
.child(note("Test Analysis")) // Exact match
|
||||
.child(note("Statistical Analysis")) // Exact match
|
||||
.child(note("Business Analysis")) // Exact match
|
||||
.child(note("Advanced Anaylsis")) // Fuzzy match (typo)
|
||||
.child(note("Quick Anlaysis")); // Fuzzy match (typo)
|
||||
|
||||
const searchContext = new SearchContext();
|
||||
const searchResults = searchService.findResultsWithQuery("analysis", searchContext);
|
||||
|
||||
// Should find all matches but exact ones should come first
|
||||
expect(searchResults.length).toEqual(7);
|
||||
// With only 3 exact matches (below threshold), fuzzy should be triggered
|
||||
// Should find all 5 matches but exact ones should come first
|
||||
expect(searchResults.length).toEqual(5);
|
||||
|
||||
// Get note titles in result order
|
||||
const resultTitles = searchResults.map(r => becca.notes[r.noteId].title);
|
||||
@ -607,7 +606,7 @@ describe("Search", () => {
|
||||
(title.includes("Anaylsis") || title.includes("Anlaysis")) ? index : -1
|
||||
).filter(index => index !== -1);
|
||||
|
||||
expect(exactMatchIndices.length).toEqual(5);
|
||||
expect(exactMatchIndices.length).toEqual(3);
|
||||
expect(fuzzyMatchIndices.length).toEqual(2);
|
||||
|
||||
// CRITICAL: All exact matches must appear before all fuzzy matches
|
||||
|
@ -237,6 +237,19 @@ function findResultsWithExpression(expression: Expression, searchContext: Search
|
||||
loadNeededInfoFromDatabase();
|
||||
}
|
||||
|
||||
// If there's an explicit orderBy clause, skip progressive search
|
||||
// as it would interfere with the ordering
|
||||
if (searchContext.orderBy) {
|
||||
// For ordered queries, don't use progressive search but respect
|
||||
// the original fuzzy matching setting
|
||||
return performSearch(expression, searchContext, searchContext.enableFuzzyMatching);
|
||||
}
|
||||
|
||||
// If fuzzy matching is explicitly disabled, skip progressive search
|
||||
if (!searchContext.enableFuzzyMatching) {
|
||||
return performSearch(expression, searchContext, false);
|
||||
}
|
||||
|
||||
// Phase 1: Try exact matches first (without fuzzy matching)
|
||||
const exactResults = performSearch(expression, searchContext, false);
|
||||
|
||||
@ -251,7 +264,7 @@ function findResultsWithExpression(expression: Expression, searchContext: Search
|
||||
return exactResults;
|
||||
}
|
||||
|
||||
// Phase 2: Add fuzzy matching as fallback
|
||||
// Phase 2: Add fuzzy matching as fallback when exact matches are insufficient
|
||||
const fuzzyResults = performSearch(expression, searchContext, true);
|
||||
|
||||
// Merge results, ensuring exact matches always rank higher than fuzzy matches
|
||||
@ -402,6 +415,16 @@ function findResultsWithQuery(query: string, searchContext: SearchContext): Sear
|
||||
return [];
|
||||
}
|
||||
|
||||
// If the query starts with '#', it's a pure expression query.
|
||||
// Don't use progressive search for these as they may have complex
|
||||
// ordering or other logic that shouldn't be interfered with.
|
||||
const isPureExpressionQuery = query.trim().startsWith('#');
|
||||
|
||||
if (isPureExpressionQuery) {
|
||||
// For pure expression queries, use standard search without progressive phases
|
||||
return performSearch(expression, searchContext, searchContext.enableFuzzyMatching);
|
||||
}
|
||||
|
||||
return findResultsWithExpression(expression, searchContext);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user