use serde_json::Value; /// Search and filtering utilities for entity data #[allow(dead_code)] pub struct SearchFilter; #[allow(dead_code)] impl SearchFilter { /// Filter a collection of JSON values based on a search query across specified fields pub fn filter_data(data: &[Value], search_query: &str, search_fields: &[&str]) -> Vec { if search_query.is_empty() { return data.to_vec(); } let search_lower = search_query.to_lowercase(); data.iter() .filter(|item| { search_fields.iter().any(|field| { item.get(field) .and_then(|v| v.as_str()) .map(|s| s.to_lowercase().contains(&search_lower)) .unwrap_or(false) }) }) .cloned() .collect() } /// Filter any generic collection with a custom predicate pub fn filter_generic(data: &[T], predicate: impl Fn(&T) -> bool) -> Vec where T: Clone, { data.iter() .filter(|item| predicate(item)) .cloned() .collect() } /// Search assets specifically (common fields: name, asset_tag, manufacturer, model) pub fn filter_assets(assets: &[Value], search_query: &str) -> Vec { Self::filter_data( assets, search_query, &[ "name", "asset_tag", "manufacturer", "model", "serial_number", ], ) } /// Search borrowers (common fields: first_name, last_name, email, username) pub fn filter_borrowers(borrowers: &[Value], search_query: &str) -> Vec { Self::filter_data( borrowers, search_query, &["first_name", "last_name", "email", "username"], ) } /// Search categories (common fields: category_name, category_code) pub fn filter_categories(categories: &[Value], search_query: &str) -> Vec { Self::filter_data( categories, search_query, &["category_name", "category_code"], ) } /// Search zones (common fields: zone_name, zone_code) pub fn filter_zones(zones: &[Value], search_query: &str) -> Vec { Self::filter_data(zones, search_query, &["zone_name", "zone_code"]) } /// Search suppliers (common fields: name) pub fn filter_suppliers(suppliers: &[Value], search_query: &str) -> Vec { Self::filter_data(suppliers, search_query, &["name"]) } } /// Sorting utilities #[allow(dead_code)] pub struct SortUtils; #[allow(dead_code)] impl SortUtils { /// Sort JSON values by a specific field pub fn sort_json_by_field(data: &mut [Value], field: &str, ascending: bool) { data.sort_by(|a, b| { let val_a = a.get(field); let val_b = b.get(field); let cmp = match (val_a, val_b) { (Some(a), Some(b)) => { // Try to compare as strings first match (a.as_str(), b.as_str()) { (Some(s_a), Some(s_b)) => s_a.cmp(s_b), _ => { // Try to compare as numbers match (a.as_i64(), b.as_i64()) { (Some(n_a), Some(n_b)) => n_a.cmp(&n_b), _ => { // Try to compare as floats match (a.as_f64(), b.as_f64()) { (Some(f_a), Some(f_b)) => f_a .partial_cmp(&f_b) .unwrap_or(std::cmp::Ordering::Equal), _ => std::cmp::Ordering::Equal, } } } } } } (Some(_), None) => std::cmp::Ordering::Less, (None, Some(_)) => std::cmp::Ordering::Greater, (None, None) => std::cmp::Ordering::Equal, }; if ascending { cmp } else { cmp.reverse() } }); } /// Generic sort function for any collection pub fn sort_generic(data: &mut [T], compare_fn: impl Fn(&T, &T) -> std::cmp::Ordering) { data.sort_by(compare_fn); } }