use serde_json::Value; use uuid::Uuid; pub fn build_quickwit_query(input: &str) -> Option { let tokens: Vec = input .split_whitespace() .filter(|token| !token.is_empty()) .map(|token| { let normalized = token.to_lowercase(); escape_quickwit_token(&normalized) }) .collect(); if tokens.is_empty() { return None; } let parts: Vec = tokens .into_iter() .map(|token| format!("(title:{token} OR text:{token})")) .collect(); Some(parts.join(" AND ")) } pub fn escape_quickwit_token(token: &str) -> String { let mut escaped = String::with_capacity(token.len()); for ch in token.chars() { match ch { '+' | '-' | '&' | '|' | '!' | '(' | ')' | '{' | '}' | '[' | ']' | '^' | '"' | '~' | '*' | '?' | ':' | '\\' | '/' => { escaped.push('\\'); escaped.push(ch); } _ => escaped.push(ch), } } escaped } pub fn extract_document_id(hit: &Value) -> Option { for key in ["_source", "source", "fields", "stored_fields"] { if let Some(value) = hit.get(key) { if let Some(uuid) = extract_uuid_from_value(value) { return Some(uuid); } } } if let Some(value) = hit.get("document_id") { if let Some(uuid) = extract_uuid_from_value(value) { return Some(uuid); } } None } pub fn extract_uuid_from_value(value: &Value) -> Option { if let Some(obj) = value.as_object() { if let Some(inner) = obj.get("document_id") { return parse_uuid_value(inner); } } if let Some(arr) = value.as_array() { for item in arr { if let Some(uuid) = extract_uuid_from_value(item) { return Some(uuid); } } } parse_uuid_value(value) } pub fn parse_uuid_value(value: &Value) -> Option { if let Some(s) = value.as_str() { return Uuid::parse_str(s).ok(); } if let Some(arr) = value.as_array() { for item in arr { if let Some(uuid) = parse_uuid_value(item) { return Some(uuid); } } } None }