tellaro_query_language/mutators/
string_mutators.rs1use super::{get_param, Mutator, MutatorParams};
6use crate::error::{Result, TqlError};
7use serde_json::Value as JsonValue;
8
9pub struct LowercaseMutator {
11 _params: MutatorParams,
12}
13
14impl LowercaseMutator {
15 pub fn new(params: MutatorParams) -> Self {
16 Self { _params: params }
17 }
18}
19
20impl Mutator for LowercaseMutator {
21 fn apply(
22 &self,
23 _field_name: &str,
24 _record: &JsonValue,
25 value: &JsonValue,
26 ) -> Result<JsonValue> {
27 match value {
28 JsonValue::String(s) => Ok(JsonValue::String(s.to_lowercase())),
29 JsonValue::Array(arr) => {
30 let transformed: Vec<JsonValue> = arr
31 .iter()
32 .map(|item| {
33 if let JsonValue::String(s) = item {
34 JsonValue::String(s.to_lowercase())
35 } else {
36 item.clone()
37 }
38 })
39 .collect();
40 Ok(JsonValue::Array(transformed))
41 }
42 _ => Ok(value.clone()),
43 }
44 }
45
46 fn name(&self) -> &str {
47 "lowercase"
48 }
49}
50
51pub struct UppercaseMutator {
53 _params: MutatorParams,
54}
55
56impl UppercaseMutator {
57 pub fn new(params: MutatorParams) -> Self {
58 Self { _params: params }
59 }
60}
61
62impl Mutator for UppercaseMutator {
63 fn apply(
64 &self,
65 _field_name: &str,
66 _record: &JsonValue,
67 value: &JsonValue,
68 ) -> Result<JsonValue> {
69 match value {
70 JsonValue::String(s) => Ok(JsonValue::String(s.to_uppercase())),
71 JsonValue::Array(arr) => {
72 let transformed: Vec<JsonValue> = arr
73 .iter()
74 .map(|item| {
75 if let JsonValue::String(s) = item {
76 JsonValue::String(s.to_uppercase())
77 } else {
78 item.clone()
79 }
80 })
81 .collect();
82 Ok(JsonValue::Array(transformed))
83 }
84 _ => Ok(value.clone()),
85 }
86 }
87
88 fn name(&self) -> &str {
89 "uppercase"
90 }
91}
92
93pub struct TrimMutator {
95 _params: MutatorParams,
96}
97
98impl TrimMutator {
99 pub fn new(params: MutatorParams) -> Self {
100 Self { _params: params }
101 }
102}
103
104impl Mutator for TrimMutator {
105 fn apply(
106 &self,
107 _field_name: &str,
108 _record: &JsonValue,
109 value: &JsonValue,
110 ) -> Result<JsonValue> {
111 match value {
112 JsonValue::String(s) => Ok(JsonValue::String(s.trim().to_string())),
113 JsonValue::Array(arr) => {
114 let transformed: Vec<JsonValue> = arr
115 .iter()
116 .map(|item| {
117 if let JsonValue::String(s) = item {
118 JsonValue::String(s.trim().to_string())
119 } else {
120 item.clone()
121 }
122 })
123 .collect();
124 Ok(JsonValue::Array(transformed))
125 }
126 _ => Ok(value.clone()),
127 }
128 }
129
130 fn name(&self) -> &str {
131 "trim"
132 }
133}
134
135pub struct SplitMutator {
137 params: MutatorParams,
138}
139
140impl SplitMutator {
141 pub fn new(params: MutatorParams) -> Self {
142 Self { params }
143 }
144
145 fn get_delimiter(&self) -> String {
146 get_param(&self.params, "delimiter", 0)
147 .and_then(|v| v.as_str())
148 .unwrap_or(" ")
149 .to_string()
150 }
151}
152
153impl Mutator for SplitMutator {
154 fn apply(
155 &self,
156 _field_name: &str,
157 _record: &JsonValue,
158 value: &JsonValue,
159 ) -> Result<JsonValue> {
160 let delimiter = self.get_delimiter();
161
162 match value {
163 JsonValue::String(s) => {
164 let parts: Vec<JsonValue> = s
165 .split(&delimiter)
166 .map(|part| JsonValue::String(part.to_string()))
167 .collect();
168 Ok(JsonValue::Array(parts))
169 }
170 JsonValue::Array(arr) => {
171 let transformed: Vec<JsonValue> = arr
173 .iter()
174 .flat_map(|item| {
175 if let JsonValue::String(s) = item {
176 s.split(&delimiter)
177 .map(|part| JsonValue::String(part.to_string()))
178 .collect::<Vec<JsonValue>>()
179 } else {
180 vec![item.clone()]
181 }
182 })
183 .collect();
184 Ok(JsonValue::Array(transformed))
185 }
186 _ => Ok(value.clone()),
187 }
188 }
189
190 fn name(&self) -> &str {
191 "split"
192 }
193}
194
195pub struct LengthMutator {
197 _params: MutatorParams,
198}
199
200impl LengthMutator {
201 pub fn new(params: MutatorParams) -> Self {
202 Self { _params: params }
203 }
204}
205
206impl Mutator for LengthMutator {
207 fn apply(
208 &self,
209 _field_name: &str,
210 _record: &JsonValue,
211 value: &JsonValue,
212 ) -> Result<JsonValue> {
213 match value {
214 JsonValue::String(s) => Ok(JsonValue::Number(serde_json::Number::from(
215 s.chars().count(),
216 ))),
217 JsonValue::Array(arr) => Ok(JsonValue::Number(serde_json::Number::from(arr.len()))),
218 _ => Ok(JsonValue::Number(serde_json::Number::from(0))),
219 }
220 }
221
222 fn name(&self) -> &str {
223 "length"
224 }
225}
226
227pub struct ReplaceMutator {
229 params: MutatorParams,
230}
231
232impl ReplaceMutator {
233 pub fn new(params: MutatorParams) -> Self {
234 Self { params }
235 }
236
237 fn get_find(&self) -> Result<String> {
238 get_param(&self.params, "find", 0)
239 .and_then(|v| v.as_str())
240 .map(|s| s.to_string())
241 .ok_or_else(|| {
242 TqlError::MutatorError("Replace mutator requires 'find' parameter".to_string())
243 })
244 }
245
246 fn get_replace(&self) -> String {
247 get_param(&self.params, "replace", 1)
248 .and_then(|v| v.as_str())
249 .unwrap_or("")
250 .to_string()
251 }
252}
253
254impl Mutator for ReplaceMutator {
255 fn apply(
256 &self,
257 _field_name: &str,
258 _record: &JsonValue,
259 value: &JsonValue,
260 ) -> Result<JsonValue> {
261 let find = self.get_find()?;
262 let replace = self.get_replace();
263
264 match value {
265 JsonValue::String(s) => Ok(JsonValue::String(s.replace(&find, &replace))),
266 JsonValue::Array(arr) => {
267 let transformed: Result<Vec<JsonValue>> = arr
268 .iter()
269 .map(|item| {
270 if let JsonValue::String(s) = item {
271 Ok(JsonValue::String(s.replace(&find, &replace)))
272 } else {
273 Ok(item.clone())
274 }
275 })
276 .collect();
277 Ok(JsonValue::Array(transformed?))
278 }
279 _ => Ok(value.clone()),
280 }
281 }
282
283 fn name(&self) -> &str {
284 "replace"
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291 use serde_json::json;
292 use std::collections::HashMap;
293
294 #[test]
295 fn test_lowercase_mutator() {
296 let mutator = LowercaseMutator::new(HashMap::new());
297 let record = json!({});
298
299 let value = json!("HELLO WORLD");
301 let result = mutator.apply("field", &record, &value).unwrap();
302 assert_eq!(result, json!("hello world"));
303
304 let value = json!(["HELLO", "WORLD"]);
306 let result = mutator.apply("field", &record, &value).unwrap();
307 assert_eq!(result, json!(["hello", "world"]));
308
309 let value = json!(42);
311 let result = mutator.apply("field", &record, &value).unwrap();
312 assert_eq!(result, json!(42));
313 }
314
315 #[test]
316 fn test_uppercase_mutator() {
317 let mutator = UppercaseMutator::new(HashMap::new());
318 let record = json!({});
319
320 let value = json!("hello world");
321 let result = mutator.apply("field", &record, &value).unwrap();
322 assert_eq!(result, json!("HELLO WORLD"));
323 }
324
325 #[test]
326 fn test_trim_mutator() {
327 let mutator = TrimMutator::new(HashMap::new());
328 let record = json!({});
329
330 let value = json!(" hello world ");
331 let result = mutator.apply("field", &record, &value).unwrap();
332 assert_eq!(result, json!("hello world"));
333
334 let value = json!([" hello ", " world "]);
336 let result = mutator.apply("field", &record, &value).unwrap();
337 assert_eq!(result, json!(["hello", "world"]));
338 }
339
340 #[test]
341 fn test_split_mutator() {
342 let mut params = HashMap::new();
343 params.insert("delimiter".to_string(), json!(","));
344 let mutator = SplitMutator::new(params);
345 let record = json!({});
346
347 let value = json!("a,b,c");
348 let result = mutator.apply("field", &record, &value).unwrap();
349 assert_eq!(result, json!(["a", "b", "c"]));
350 }
351
352 #[test]
353 fn test_split_default_delimiter() {
354 let mutator = SplitMutator::new(HashMap::new());
355 let record = json!({});
356
357 let value = json!("hello world");
358 let result = mutator.apply("field", &record, &value).unwrap();
359 assert_eq!(result, json!(["hello", "world"]));
360 }
361
362 #[test]
363 fn test_length_mutator() {
364 let mutator = LengthMutator::new(HashMap::new());
365 let record = json!({});
366
367 let value = json!("hello");
369 let result = mutator.apply("field", &record, &value).unwrap();
370 assert_eq!(result, json!(5));
371
372 let value = json!(["a", "b", "c"]);
374 let result = mutator.apply("field", &record, &value).unwrap();
375 assert_eq!(result, json!(3));
376 }
377
378 #[test]
379 fn test_replace_mutator() {
380 let mut params = HashMap::new();
381 params.insert("find".to_string(), json!("world"));
382 params.insert("replace".to_string(), json!("universe"));
383 let mutator = ReplaceMutator::new(params);
384 let record = json!({});
385
386 let value = json!("hello world");
387 let result = mutator.apply("field", &record, &value).unwrap();
388 assert_eq!(result, json!("hello universe"));
389
390 let value = json!(["hello world", "world peace"]);
392 let result = mutator.apply("field", &record, &value).unwrap();
393 assert_eq!(result, json!(["hello universe", "universe peace"]));
394 }
395
396 #[test]
397 fn test_replace_missing_find_parameter() {
398 let mutator = ReplaceMutator::new(HashMap::new());
399 let record = json!({});
400 let value = json!("hello");
401
402 let result = mutator.apply("field", &record, &value);
403 assert!(result.is_err());
404 assert!(result
405 .unwrap_err()
406 .to_string()
407 .contains("Replace mutator requires 'find' parameter"));
408 }
409}