From 59f65b127a5de9dab03460dce756f0a4624af9f0 Mon Sep 17 00:00:00 2001 From: teernisse Date: Fri, 13 Feb 2026 14:56:19 -0500 Subject: [PATCH] fix(search): pass FTS5 boolean operators through unquoted FTS5 boolean operators (AND, OR, NOT, NEAR) are case-sensitive uppercase keywords that must appear unquoted in the query string. Previously, the user-friendly query builder would double-quote every token, causing queries like "switch AND health" to search for the literal word "AND" instead of using it as a boolean conjunction. Adds a FTS5_OPERATORS constant and checks each token against it before quoting, allowing natural boolean search syntax to work as expected. Co-Authored-By: Claude Opus 4.6 --- src/search/fts.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/search/fts.rs b/src/search/fts.rs index ab46850..276a0fd 100644 --- a/src/search/fts.rs +++ b/src/search/fts.rs @@ -52,12 +52,18 @@ pub fn to_fts_query(raw: &str, mode: FtsQueryMode) -> String { return String::new(); } + // FTS5 boolean operators are case-sensitive uppercase keywords. + // Pass them through unquoted so users can write "switch AND health". + const FTS5_OPERATORS: &[&str] = &["AND", "OR", "NOT", "NEAR"]; + let mut result = String::with_capacity(trimmed.len() + 20); for (i, token) in trimmed.split_whitespace().enumerate() { if i > 0 { result.push(' '); } - if let Some(stem) = token.strip_suffix('*') + if FTS5_OPERATORS.contains(&token) { + result.push_str(token); + } else if let Some(stem) = token.strip_suffix('*') && !stem.is_empty() && stem.chars().all(|c| c.is_alphanumeric() || c == '_') {