1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
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<Value> {
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<T>(data: &[T], predicate: impl Fn(&T) -> bool) -> Vec<T>
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<Value> {
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<Value> {
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<Value> {
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<Value> {
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<Value> {
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<T>(data: &mut [T], compare_fn: impl Fn(&T, &T) -> std::cmp::Ordering) {
data.sort_by(compare_fn);
}
}
|