use crate::error::{BrainError, Result};
pub fn escape_fts5_query(raw: &str) -> Result<String> {
let tokens: Vec<&str> = raw.split_whitespace().filter(|t| !t.is_empty()).collect();
if tokens.is_empty() {
return Err(BrainError::FtsQuery(
"query must contain at least one non-whitespace token".into(),
));
}
let escaped = tokens
.into_iter()
.map(|t| {
let q = t.replace('"', "\"\"");
format!("\"{q}\"")
})
.collect::<Vec<_>>()
.join(" ");
Ok(escaped)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn escapes_and_quotes_tokens() {
let q = escape_fts5_query(r#"raft "consensus""#).unwrap();
assert_eq!(q, r#""raft" """consensus""""#);
}
#[test]
fn rejects_empty() {
assert!(escape_fts5_query(" ").is_err());
}
#[test]
fn operators_become_literals() {
let q = escape_fts5_query("foo AND bar").unwrap();
assert_eq!(q, r#""foo" "AND" "bar""#);
}
}