fix(search): also support exact phrase matching such as ='test phrase'

This commit is contained in:
perf3ct 2025-10-21 10:12:14 -07:00
parent 4fa4112840
commit fb0d971e48
No known key found for this signature in database
GPG Key ID: 569C4EEC436F5232
2 changed files with 15 additions and 7 deletions

View File

@ -118,7 +118,7 @@ class NoteContentFulltextExp extends Expression {
} }
/** /**
* Checks if content contains the exact word (with word boundaries) * Checks if content contains the exact word (with word boundaries) or exact phrase
* This is case-insensitive since content and token are already normalized * This is case-insensitive since content and token are already normalized
*/ */
private containsExactWord(token: string, content: string): boolean { private containsExactWord(token: string, content: string): boolean {
@ -126,7 +126,13 @@ class NoteContentFulltextExp extends Expression {
const normalizedToken = normalizeSearchText(token); const normalizedToken = normalizeSearchText(token);
const normalizedContent = normalizeSearchText(content); const normalizedContent = normalizeSearchText(content);
// Split content into words and check for exact match // If token contains spaces, it's a multi-word phrase from quotes
// Check for substring match (consecutive phrase)
if (normalizedToken.includes(' ')) {
return normalizedContent.includes(normalizedToken);
}
// For single words, split content into words and check for exact match
const words = normalizedContent.split(/\s+/); const words = normalizedContent.split(/\s+/);
return words.some(word => word === normalizedToken); return words.some(word => word === normalizedToken);
} }

View File

@ -15,18 +15,19 @@ type Comparator<T> = (comparedValue: T) => (val: string) => boolean;
const stringComparators: Record<string, Comparator<string>> = { const stringComparators: Record<string, Comparator<string>> = {
"=": (comparedValue) => (val) => { "=": (comparedValue) => (val) => {
// For the = operator, check if the value contains the exact word or phrase // For the = operator, check if the value contains the exact word or phrase
// This is case-insensitive since both values are already lowercased // This is case-insensitive
if (!val) return false; if (!val) return false;
const normalizedVal = normalizeSearchText(val); const normalizedVal = normalizeSearchText(val);
const normalizedCompared = normalizeSearchText(comparedValue); const normalizedCompared = normalizeSearchText(comparedValue);
// If comparedValue has multiple words, check for exact phrase // If comparedValue has spaces, it's a multi-word phrase
// Check for substring match (consecutive phrase)
if (normalizedCompared.includes(" ")) { if (normalizedCompared.includes(" ")) {
return normalizedVal.includes(normalizedCompared); return normalizedVal.includes(normalizedCompared);
} }
// For single word, split into words and check for exact match // For single word, split into words and check for exact word match
const words = normalizedVal.split(/\s+/); const words = normalizedVal.split(/\s+/);
return words.some(word => word === normalizedCompared); return words.some(word => word === normalizedCompared);
}, },
@ -37,12 +38,13 @@ const stringComparators: Record<string, Comparator<string>> = {
const normalizedVal = normalizeSearchText(val); const normalizedVal = normalizeSearchText(val);
const normalizedCompared = normalizeSearchText(comparedValue); const normalizedCompared = normalizeSearchText(comparedValue);
// If comparedValue has multiple words, check for exact phrase // If comparedValue has spaces, it's a multi-word phrase
// Check for substring match (consecutive phrase) and negate
if (normalizedCompared.includes(" ")) { if (normalizedCompared.includes(" ")) {
return !normalizedVal.includes(normalizedCompared); return !normalizedVal.includes(normalizedCompared);
} }
// For single word, split into words and check for exact match // For single word, split into words and check for exact word match, then negate
const words = normalizedVal.split(/\s+/); const words = normalizedVal.split(/\s+/);
return !words.some(word => word === normalizedCompared); return !words.some(word => word === normalizedCompared);
}, },