search.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. use serde_json::Value;
  2. /// Search and filtering utilities for entity data
  3. #[allow(dead_code)]
  4. pub struct SearchFilter;
  5. #[allow(dead_code)]
  6. impl SearchFilter {
  7. /// Filter a collection of JSON values based on a search query across specified fields
  8. pub fn filter_data(data: &[Value], search_query: &str, search_fields: &[&str]) -> Vec<Value> {
  9. if search_query.is_empty() {
  10. return data.to_vec();
  11. }
  12. let search_lower = search_query.to_lowercase();
  13. data.iter()
  14. .filter(|item| {
  15. search_fields.iter().any(|field| {
  16. item.get(field)
  17. .and_then(|v| v.as_str())
  18. .map(|s| s.to_lowercase().contains(&search_lower))
  19. .unwrap_or(false)
  20. })
  21. })
  22. .cloned()
  23. .collect()
  24. }
  25. /// Filter any generic collection with a custom predicate
  26. pub fn filter_generic<T>(data: &[T], predicate: impl Fn(&T) -> bool) -> Vec<T>
  27. where
  28. T: Clone,
  29. {
  30. data.iter()
  31. .filter(|item| predicate(item))
  32. .cloned()
  33. .collect()
  34. }
  35. /// Search assets specifically (common fields: name, asset_tag, manufacturer, model)
  36. pub fn filter_assets(assets: &[Value], search_query: &str) -> Vec<Value> {
  37. Self::filter_data(
  38. assets,
  39. search_query,
  40. &[
  41. "name",
  42. "asset_tag",
  43. "manufacturer",
  44. "model",
  45. "serial_number",
  46. ],
  47. )
  48. }
  49. /// Search borrowers (common fields: first_name, last_name, email, username)
  50. pub fn filter_borrowers(borrowers: &[Value], search_query: &str) -> Vec<Value> {
  51. Self::filter_data(
  52. borrowers,
  53. search_query,
  54. &["first_name", "last_name", "email", "username"],
  55. )
  56. }
  57. /// Search categories (common fields: category_name, category_code)
  58. pub fn filter_categories(categories: &[Value], search_query: &str) -> Vec<Value> {
  59. Self::filter_data(
  60. categories,
  61. search_query,
  62. &["category_name", "category_code"],
  63. )
  64. }
  65. /// Search zones (common fields: zone_name, zone_code)
  66. pub fn filter_zones(zones: &[Value], search_query: &str) -> Vec<Value> {
  67. Self::filter_data(zones, search_query, &["zone_name", "zone_code"])
  68. }
  69. /// Search suppliers (common fields: name)
  70. pub fn filter_suppliers(suppliers: &[Value], search_query: &str) -> Vec<Value> {
  71. Self::filter_data(suppliers, search_query, &["name"])
  72. }
  73. }
  74. /// Sorting utilities
  75. #[allow(dead_code)]
  76. pub struct SortUtils;
  77. #[allow(dead_code)]
  78. impl SortUtils {
  79. /// Sort JSON values by a specific field
  80. pub fn sort_json_by_field(data: &mut [Value], field: &str, ascending: bool) {
  81. data.sort_by(|a, b| {
  82. let val_a = a.get(field);
  83. let val_b = b.get(field);
  84. let cmp = match (val_a, val_b) {
  85. (Some(a), Some(b)) => {
  86. // Try to compare as strings first
  87. match (a.as_str(), b.as_str()) {
  88. (Some(s_a), Some(s_b)) => s_a.cmp(s_b),
  89. _ => {
  90. // Try to compare as numbers
  91. match (a.as_i64(), b.as_i64()) {
  92. (Some(n_a), Some(n_b)) => n_a.cmp(&n_b),
  93. _ => {
  94. // Try to compare as floats
  95. match (a.as_f64(), b.as_f64()) {
  96. (Some(f_a), Some(f_b)) => f_a
  97. .partial_cmp(&f_b)
  98. .unwrap_or(std::cmp::Ordering::Equal),
  99. _ => std::cmp::Ordering::Equal,
  100. }
  101. }
  102. }
  103. }
  104. }
  105. }
  106. (Some(_), None) => std::cmp::Ordering::Less,
  107. (None, Some(_)) => std::cmp::Ordering::Greater,
  108. (None, None) => std::cmp::Ordering::Equal,
  109. };
  110. if ascending {
  111. cmp
  112. } else {
  113. cmp.reverse()
  114. }
  115. });
  116. }
  117. /// Generic sort function for any collection
  118. pub fn sort_generic<T>(data: &mut [T], compare_fn: impl Fn(&T, &T) -> std::cmp::Ordering) {
  119. data.sort_by(compare_fn);
  120. }
  121. }