diff --git a/apps/server/src/services/search/services/build_comparator.ts b/apps/server/src/services/search/services/build_comparator.ts index 752ad8ff4..3aebe1adb 100644 --- a/apps/server/src/services/search/services/build_comparator.ts +++ b/apps/server/src/services/search/services/build_comparator.ts @@ -1,3 +1,5 @@ +import { normalizeSearchText, fuzzyMatchWord, FUZZY_SEARCH_CONFIG } from "../utils/text_utils.js"; + const cachedRegexes: Record = {}; function getRegex(str: string) { @@ -20,7 +22,41 @@ const stringComparators: Record> = { "*=": (comparedValue) => (val) => !!val && val.endsWith(comparedValue), "=*": (comparedValue) => (val) => !!val && val.startsWith(comparedValue), "*=*": (comparedValue) => (val) => !!val && val.includes(comparedValue), - "%=": (comparedValue) => (val) => !!val && !!getRegex(comparedValue).test(val) + "%=": (comparedValue) => (val) => !!val && !!getRegex(comparedValue).test(val), + "~=": (comparedValue) => (val) => { + if (!val || !comparedValue) return false; + + // Validate minimum length for fuzzy search to prevent false positives + if (comparedValue.length < FUZZY_SEARCH_CONFIG.MIN_FUZZY_TOKEN_LENGTH) { + return val.includes(comparedValue); + } + + const normalizedVal = normalizeSearchText(val); + const normalizedCompared = normalizeSearchText(comparedValue); + + // First try exact substring match + if (normalizedVal.includes(normalizedCompared)) { + return true; + } + + // Then try fuzzy word matching + const words = normalizedVal.split(/\s+/); + return words.some(word => fuzzyMatchWord(normalizedCompared, word)); + }, + "~*": (comparedValue) => (val) => { + if (!val || !comparedValue) return false; + + // Validate minimum length for fuzzy search + if (comparedValue.length < FUZZY_SEARCH_CONFIG.MIN_FUZZY_TOKEN_LENGTH) { + return val.includes(comparedValue); + } + + const normalizedVal = normalizeSearchText(val); + const normalizedCompared = normalizeSearchText(comparedValue); + + // For ~* operator, use fuzzy matching across the entire content + return fuzzyMatchWord(normalizedCompared, normalizedVal); + } }; const numericComparators: Record> = {