1use serde_json::Value;
2use crate::Error;
3
4pub fn apply_stats_operation(data: &[Value], operation: &str, field: Option<&str>) -> Result<Value, Error> {
6 match operation {
7 "unique" => apply_unique(data, field),
8 "sort" => apply_sort(data, field),
9 "median" => apply_median(data, field),
10 "stddev" => apply_stddev(data, field),
11 "length" => Ok(Value::Number(serde_json::Number::from(data.len()))),
12 _ => Err(Error::StringOperation(format!("Unknown stats operation: {}", operation))),
13 }
14}
15
16fn apply_unique(data: &[Value], field: Option<&str>) -> Result<Value, Error> {
18 use std::collections::HashSet;
19
20 let mut unique_values = HashSet::new();
21 let mut result = Vec::new();
22
23 for item in data {
24 let value_to_check = if let Some(field_name) = field {
25 item.get(field_name).unwrap_or(&Value::Null).clone()
27 } else {
28 item.clone()
30 };
31
32 let key = serde_json::to_string(&value_to_check).unwrap_or_default();
34
35 if unique_values.insert(key) {
36 result.push(value_to_check);
37 }
38 }
39
40 Ok(Value::Array(result))
41}
42
43fn apply_sort(data: &[Value], field: Option<&str>) -> Result<Value, Error> {
45 let mut sorted_data = data.to_vec();
46
47 sorted_data.sort_by(|a, b| {
48 let val_a = if let Some(field_name) = field {
49 a.get(field_name).unwrap_or(&Value::Null)
50 } else {
51 a
52 };
53
54 let val_b = if let Some(field_name) = field {
55 b.get(field_name).unwrap_or(&Value::Null)
56 } else {
57 b
58 };
59
60 compare_json_values(val_a, val_b)
61 });
62
63 Ok(Value::Array(sorted_data))
64}
65
66fn apply_median(data: &[Value], field: Option<&str>) -> Result<Value, Error> {
68 let mut numbers = extract_numbers(data, field)?;
69
70 if numbers.is_empty() {
71 return Ok(Value::Null);
72 }
73
74 numbers.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
75
76 let len = numbers.len();
77 let median = if len % 2 == 0 {
78 (numbers[len / 2 - 1] + numbers[len / 2]) / 2.0
80 } else {
81 numbers[len / 2]
83 };
84
85 Ok(Value::Number(serde_json::Number::from_f64(median).unwrap()))
86}
87
88fn apply_stddev(data: &[Value], field: Option<&str>) -> Result<Value, Error> {
90 let numbers = extract_numbers(data, field)?;
91
92 if numbers.len() < 2 {
93 return Ok(Value::Null);
94 }
95
96 let mean = numbers.iter().sum::<f64>() / numbers.len() as f64;
97 let variance = numbers.iter()
98 .map(|x| (x - mean).powi(2))
99 .sum::<f64>() / (numbers.len() - 1) as f64; let stddev = variance.sqrt();
102
103 Ok(Value::Number(serde_json::Number::from_f64(stddev).unwrap()))
104}
105
106fn extract_numbers(data: &[Value], field: Option<&str>) -> Result<Vec<f64>, Error> {
108 let mut numbers = Vec::new();
109
110 for item in data {
111 let value = if let Some(field_name) = field {
112 item.get(field_name).unwrap_or(&Value::Null)
113 } else {
114 item
115 };
116
117 if let Some(num) = value.as_f64() {
118 numbers.push(num);
119 }
120 }
121
122 Ok(numbers)
123}
124
125fn compare_json_values(a: &Value, b: &Value) -> std::cmp::Ordering {
127 use std::cmp::Ordering;
128
129 match (a, b) {
130 (Value::Number(n1), Value::Number(n2)) => {
131 n1.as_f64().unwrap_or(0.0).partial_cmp(&n2.as_f64().unwrap_or(0.0)).unwrap_or(Ordering::Equal)
132 },
133 (Value::String(s1), Value::String(s2)) => s1.cmp(s2),
134 (Value::Bool(b1), Value::Bool(b2)) => b1.cmp(b2),
135 (Value::Null, Value::Null) => Ordering::Equal,
136 (Value::Null, _) => Ordering::Less,
137 (_, Value::Null) => Ordering::Greater,
138 _ => get_type_priority(a).cmp(&get_type_priority(b)),
140 }
141}
142
143fn get_type_priority(value: &Value) -> u8 {
145 match value {
146 Value::Null => 0,
147 Value::Bool(_) => 1,
148 Value::Number(_) => 2,
149 Value::String(_) => 3,
150 Value::Array(_) => 4,
151 Value::Object(_) => 5,
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158
159 #[test]
160 fn test_unique_operation() {
161 let data = vec![
162 Value::String("apple".to_string()),
163 Value::String("banana".to_string()),
164 Value::String("apple".to_string()),
165 Value::String("cherry".to_string()),
166 ];
167
168 let result = apply_unique(&data, None).unwrap();
169 if let Value::Array(arr) = result {
170 assert_eq!(arr.len(), 3); } else {
172 panic!("Expected array result");
173 }
174 }
175
176 #[test]
177 fn test_sort_numbers() {
178 let data = vec![
179 Value::Number(3.into()),
180 Value::Number(1.into()),
181 Value::Number(4.into()),
182 Value::Number(2.into()),
183 ];
184
185 let result = apply_sort(&data, None).unwrap();
186 if let Value::Array(arr) = result {
187 assert_eq!(arr[0], Value::Number(1.into()));
188 assert_eq!(arr[1], Value::Number(2.into()));
189 assert_eq!(arr[2], Value::Number(3.into()));
190 assert_eq!(arr[3], Value::Number(4.into()));
191 } else {
192 panic!("Expected array result");
193 }
194 }
195
196 #[test]
197 fn test_median_even() {
198 let data = vec![
199 Value::Number(1.into()),
200 Value::Number(2.into()),
201 Value::Number(4.into()),
202 Value::Number(5.into()),
203 ];
204
205 let result = apply_median(&data, None).unwrap();
206 assert_eq!(result, Value::Number(serde_json::Number::from_f64(3.0).unwrap()));
207 }
208
209 #[test]
210 fn test_stddev() {
211 let data = vec![
212 Value::Number(1.into()),
213 Value::Number(2.into()),
214 Value::Number(3.into()),
215 Value::Number(4.into()),
216 Value::Number(5.into()),
217 ];
218
219 let result = apply_stddev(&data, None).unwrap();
220 if let Value::Number(n) = result {
222 let stddev = n.as_f64().unwrap();
223 assert!((stddev - 1.58).abs() < 0.1);
224 } else {
225 panic!("Expected number result");
226 }
227 }
228
229 #[test]
230 fn test_unique_with_field() {
231 let data = vec![
232 serde_json::json!({"name": "Alice", "age": 30}),
233 serde_json::json!({"name": "Bob", "age": 25}),
234 serde_json::json!({"name": "Alice", "age": 35}),
235 ];
236
237 let result = apply_unique(&data, Some("name")).unwrap();
238 if let Value::Array(arr) = result {
239 assert_eq!(arr.len(), 2); } else {
241 panic!("Expected array result");
242 }
243 }
244}