use crate::commands::core::{CommandResult, QueryParams};
use crate::transducer::Transducer;
use libdictenstein::Dictionary;
pub fn execute_query<D: Dictionary + Clone>(
dict: &D,
params: &QueryParams,
) -> Vec<(String, usize)> {
let transducer = Transducer::new(dict.clone(), params.algorithm);
let mut results: Vec<(String, usize)> = if params.prefix {
transducer
.query_ordered(¶ms.term, params.max_distance)
.prefix()
.map(|c| (c.term, c.distance))
.collect()
} else {
transducer
.query_ordered(¶ms.term, params.max_distance)
.map(|c| (c.term, c.distance))
.collect()
};
if let Some(limit) = params.limit {
results.truncate(limit);
}
results
}
pub fn format_results(results: &[(String, usize)], show_distances: bool) -> String {
if results.is_empty() {
return "No matches found".to_string();
}
if show_distances {
results
.iter()
.map(|(term, distance)| format!("{} (distance: {})", term, distance))
.collect::<Vec<_>>()
.join("\n")
} else {
results
.iter()
.map(|(term, _)| term.clone())
.collect::<Vec<_>>()
.join("\n")
}
}
pub fn query_and_format<D: Dictionary + Clone>(dict: &D, params: &QueryParams) -> CommandResult {
let results = execute_query(dict, params);
let output = format_results(&results, params.show_distances);
CommandResult::success(output)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::transducer::Algorithm;
use libdictenstein::double_array_trie::DoubleArrayTrie;
#[test]
fn test_execute_query_exact() {
let dict = DoubleArrayTrie::from_terms(vec!["test", "testing", "tested"]);
let params = QueryParams {
term: "test".to_string(),
max_distance: 0,
algorithm: Algorithm::Standard,
prefix: false,
show_distances: false,
limit: None,
};
let results = execute_query(&dict, ¶ms);
assert_eq!(results.len(), 1);
assert_eq!(results[0].0, "test");
assert_eq!(results[0].1, 0);
}
#[test]
fn test_execute_query_fuzzy() {
let dict = DoubleArrayTrie::from_terms(vec!["test", "best", "rest"]);
let params = QueryParams {
term: "test".to_string(),
max_distance: 1,
algorithm: Algorithm::Standard,
prefix: false,
show_distances: false,
limit: None,
};
let results = execute_query(&dict, ¶ms);
assert!(results.len() >= 3);
assert!(results.iter().any(|(t, _)| t == "test"));
assert!(results.iter().any(|(t, _)| t == "best"));
assert!(results.iter().any(|(t, _)| t == "rest"));
}
#[test]
fn test_execute_query_with_limit() {
let dict = DoubleArrayTrie::from_terms(vec!["test", "best", "rest", "nest"]);
let params = QueryParams {
term: "test".to_string(),
max_distance: 1,
algorithm: Algorithm::Standard,
prefix: false,
show_distances: false,
limit: Some(2),
};
let results = execute_query(&dict, ¶ms);
assert_eq!(results.len(), 2);
}
#[test]
fn test_format_results_no_distances() {
let results = vec![
("apple".to_string(), 0),
("apply".to_string(), 1),
("ample".to_string(), 2),
];
let output = format_results(&results, false);
assert_eq!(output, "apple\napply\nample");
}
#[test]
fn test_format_results_with_distances() {
let results = vec![("apple".to_string(), 0), ("apply".to_string(), 1)];
let output = format_results(&results, true);
assert!(output.contains("apple (distance: 0)"));
assert!(output.contains("apply (distance: 1)"));
}
#[test]
fn test_format_results_empty() {
let results = vec![];
let output = format_results(&results, false);
assert_eq!(output, "No matches found");
}
#[test]
fn test_query_and_format() {
let dict = DoubleArrayTrie::from_terms(vec!["test"]);
let params = QueryParams {
term: "test".to_string(),
max_distance: 0,
algorithm: Algorithm::Standard,
prefix: false,
show_distances: false,
limit: None,
};
let result = query_and_format(&dict, ¶ms);
assert_eq!(result.output, "test");
assert!(!result.modified);
}
}