use regex::{Regex, RegexBuilder};
use crate::error_chirho::{ErrorChirho, ResultChirho};
use crate::keys_chirho::{ListKeyChirho, StrKeyChirho};
use super::{SearchEngineChirho, SearchOptionsChirho, SearchTypeChirho};
#[derive(Debug, Clone)]
pub struct SearchEntryChirho {
pub key_chirho: String,
pub text_chirho: String,
}
pub struct RegexSearchChirho {
entries_chirho: Vec<SearchEntryChirho>,
}
impl RegexSearchChirho {
pub fn new_chirho() -> Self {
Self {
entries_chirho: Vec::new(),
}
}
pub fn add_entry_chirho(&mut self, key_chirho: String, text_chirho: String) {
self.entries_chirho.push(SearchEntryChirho {
key_chirho,
text_chirho,
});
}
pub fn entry_count_chirho(&self) -> usize {
self.entries_chirho.len()
}
pub fn clear_chirho(&mut self) {
self.entries_chirho.clear();
}
fn search_phrase_chirho(
&self,
phrase_chirho: &str,
case_insensitive_chirho: bool,
max_results_chirho: usize,
) -> ResultChirho<ListKeyChirho> {
let pattern_chirho = regex::escape(phrase_chirho);
let regex_chirho = RegexBuilder::new(&pattern_chirho)
.case_insensitive(case_insensitive_chirho)
.build()
.map_err(|e_chirho| ErrorChirho::invalid_config_chirho(
format!("Invalid regex pattern: {}", e_chirho)
))?;
self.search_with_regex_chirho(®ex_chirho, max_results_chirho)
}
fn search_regex_chirho(
&self,
pattern_chirho: &str,
case_insensitive_chirho: bool,
max_results_chirho: usize,
) -> ResultChirho<ListKeyChirho> {
let regex_chirho = RegexBuilder::new(pattern_chirho)
.case_insensitive(case_insensitive_chirho)
.build()
.map_err(|e_chirho| ErrorChirho::invalid_config_chirho(
format!("Invalid regex pattern: {}", e_chirho)
))?;
self.search_with_regex_chirho(®ex_chirho, max_results_chirho)
}
fn search_multiword_chirho(
&self,
words_chirho: &str,
case_insensitive_chirho: bool,
max_results_chirho: usize,
) -> ResultChirho<ListKeyChirho> {
let word_list_chirho: Vec<&str> = words_chirho.split_whitespace().collect();
if word_list_chirho.is_empty() {
return Ok(ListKeyChirho::new_chirho());
}
let regexes_chirho: Vec<Regex> = word_list_chirho
.iter()
.map(|w_chirho| {
RegexBuilder::new(®ex::escape(w_chirho))
.case_insensitive(case_insensitive_chirho)
.build()
})
.collect::<Result<Vec<_>, _>>()
.map_err(|e_chirho| ErrorChirho::invalid_config_chirho(
format!("Invalid regex pattern: {}", e_chirho)
))?;
let mut results_chirho = ListKeyChirho::new_chirho();
let mut count_chirho = 0;
for entry_chirho in &self.entries_chirho {
if count_chirho >= max_results_chirho {
break;
}
let all_match_chirho = regexes_chirho
.iter()
.all(|r_chirho| r_chirho.is_match(&entry_chirho.text_chirho));
if all_match_chirho {
let key_chirho = Box::new(StrKeyChirho::with_text_chirho(&entry_chirho.key_chirho));
results_chirho.add_chirho(key_chirho);
count_chirho += 1;
}
}
Ok(results_chirho)
}
fn search_with_regex_chirho(
&self,
regex_chirho: &Regex,
max_results_chirho: usize,
) -> ResultChirho<ListKeyChirho> {
let mut results_chirho = ListKeyChirho::new_chirho();
let mut count_chirho = 0;
for entry_chirho in &self.entries_chirho {
if count_chirho >= max_results_chirho {
break;
}
if regex_chirho.is_match(&entry_chirho.text_chirho) {
let key_chirho = Box::new(StrKeyChirho::with_text_chirho(&entry_chirho.key_chirho));
results_chirho.add_chirho(key_chirho);
count_chirho += 1;
}
}
Ok(results_chirho)
}
}
impl Default for RegexSearchChirho {
fn default() -> Self {
Self::new_chirho()
}
}
impl SearchEngineChirho for RegexSearchChirho {
fn search_chirho(
&self,
pattern_chirho: &str,
options_chirho: &SearchOptionsChirho,
) -> ResultChirho<ListKeyChirho> {
let max_results_chirho = options_chirho.max_results_chirho.unwrap_or(1000);
let case_insensitive_chirho = options_chirho.case_insensitive_chirho;
let search_type_chirho = options_chirho.search_type_chirho
.unwrap_or(SearchTypeChirho::PhraseChirho);
match search_type_chirho {
SearchTypeChirho::RegexChirho => {
self.search_regex_chirho(pattern_chirho, case_insensitive_chirho, max_results_chirho)
}
SearchTypeChirho::PhraseChirho => {
self.search_phrase_chirho(pattern_chirho, case_insensitive_chirho, max_results_chirho)
}
SearchTypeChirho::MultiWordChirho => {
self.search_multiword_chirho(pattern_chirho, case_insensitive_chirho, max_results_chirho)
}
SearchTypeChirho::ProximityChirho | SearchTypeChirho::FuzzyChirho => {
self.search_phrase_chirho(pattern_chirho, case_insensitive_chirho, max_results_chirho)
}
SearchTypeChirho::ExternalChirho | SearchTypeChirho::EntryAttrChirho => {
self.search_phrase_chirho(pattern_chirho, case_insensitive_chirho, max_results_chirho)
}
}
}
fn create_index_chirho(&mut self) -> ResultChirho<()> {
Ok(())
}
fn has_index_chirho(&self) -> bool {
!self.entries_chirho.is_empty()
}
fn delete_index_chirho(&mut self) -> ResultChirho<()> {
self.entries_chirho.clear();
Ok(())
}
}
#[cfg(test)]
mod tests_chirho {
use super::*;
fn create_test_search_chirho() -> RegexSearchChirho {
let mut search_chirho = RegexSearchChirho::new_chirho();
search_chirho.add_entry_chirho(
"Gen.1.1".to_string(),
"In the beginning God created the heaven and the earth".to_string(),
);
search_chirho.add_entry_chirho(
"John.3.16".to_string(),
"For God so loved the world that he gave his only begotten Son".to_string(),
);
search_chirho.add_entry_chirho(
"John.14.6".to_string(),
"I am the way the truth and the life no man cometh unto the Father but by me".to_string(),
);
search_chirho
}
#[test]
fn test_phrase_search_chirho() {
let search_chirho = create_test_search_chirho();
let options_chirho = SearchOptionsChirho {
search_type_chirho: Some(SearchTypeChirho::PhraseChirho),
max_results_chirho: Some(10),
..Default::default()
};
let results_chirho = search_chirho.search_chirho("God", &options_chirho).unwrap();
assert_eq!(results_chirho.count_chirho(), 2);
let results_chirho = search_chirho.search_chirho("the way", &options_chirho).unwrap();
assert_eq!(results_chirho.count_chirho(), 1);
}
#[test]
fn test_regex_search_chirho() {
let search_chirho = create_test_search_chirho();
let options_chirho = SearchOptionsChirho {
search_type_chirho: Some(SearchTypeChirho::RegexChirho),
max_results_chirho: Some(10),
..Default::default()
};
let results_chirho = search_chirho.search_chirho("G[ao][dv]e?", &options_chirho).unwrap();
assert_eq!(results_chirho.count_chirho(), 2);
}
#[test]
fn test_multiword_search_chirho() {
let search_chirho = create_test_search_chirho();
let options_chirho = SearchOptionsChirho {
search_type_chirho: Some(SearchTypeChirho::MultiWordChirho),
max_results_chirho: Some(10),
..Default::default()
};
let results_chirho = search_chirho.search_chirho("God loved", &options_chirho).unwrap();
assert_eq!(results_chirho.count_chirho(), 1);
let results_chirho = search_chirho.search_chirho("the", &options_chirho).unwrap();
assert_eq!(results_chirho.count_chirho(), 3);
}
#[test]
fn test_case_insensitive_chirho() {
let search_chirho = create_test_search_chirho();
let options_chirho = SearchOptionsChirho {
search_type_chirho: Some(SearchTypeChirho::PhraseChirho),
case_insensitive_chirho: true,
max_results_chirho: Some(10),
..Default::default()
};
let results_chirho = search_chirho.search_chirho("god", &options_chirho).unwrap();
assert_eq!(results_chirho.count_chirho(), 2);
}
#[test]
fn test_max_results_chirho() {
let search_chirho = create_test_search_chirho();
let options_chirho = SearchOptionsChirho {
search_type_chirho: Some(SearchTypeChirho::PhraseChirho),
max_results_chirho: Some(1),
..Default::default()
};
let results_chirho = search_chirho.search_chirho("the", &options_chirho).unwrap();
assert_eq!(results_chirho.count_chirho(), 1);
}
}