| 7 | use nodedb_types::Value; |
| 8 | |
| 9 | pub(super) fn try_eval(name: &str, args: &[Value]) -> Option<Value> { |
| 10 | let v = match name { |
| 11 | "upper" => str_arg(args, 0).map_or(Value::Null, |s| Value::String(s.to_uppercase())), |
| 12 | "lower" => str_arg(args, 0).map_or(Value::Null, |s| Value::String(s.to_lowercase())), |
| 13 | "trim" => str_arg(args, 0).map_or(Value::Null, |s| Value::String(s.trim().to_string())), |
| 14 | "ltrim" => { |
| 15 | str_arg(args, 0).map_or(Value::Null, |s| Value::String(s.trim_start().to_string())) |
| 16 | } |
| 17 | "rtrim" => { |
| 18 | str_arg(args, 0).map_or(Value::Null, |s| Value::String(s.trim_end().to_string())) |
| 19 | } |
| 20 | "length" | "char_length" | "character_length" => { |
| 21 | str_arg(args, 0).map_or(Value::Null, |s| Value::Integer(s.len() as i64)) |
| 22 | } |
| 23 | "substr" | "substring" => { |
| 24 | let Some(s) = str_arg(args, 0) else { |
| 25 | return Some(Value::Null); |
| 26 | }; |
| 27 | let start = num_arg(args, 1).unwrap_or(1.0) as usize; |
| 28 | let len = num_arg(args, 2).map(|n| n as usize); |
| 29 | let start_idx = start.saturating_sub(1); // SQL is 1-based. |
| 30 | let result: String = match len { |
| 31 | Some(l) => s.chars().skip(start_idx).take(l).collect(), |
| 32 | None => s.chars().skip(start_idx).collect(), |
| 33 | }; |
| 34 | Value::String(result) |
| 35 | } |
| 36 | "concat" => { |
| 37 | let parts: Vec<String> = args.iter().map(value_to_display_string).collect(); |
| 38 | Value::String(parts.join("")) |
| 39 | } |
| 40 | "replace" => { |
| 41 | let Some(s) = str_arg(args, 0) else { |
| 42 | return Some(Value::Null); |
| 43 | }; |
| 44 | let from = str_arg(args, 1).unwrap_or_default(); |
| 45 | let to = str_arg(args, 2).unwrap_or_default(); |
| 46 | Value::String(s.replace(&from, &to)) |
| 47 | } |
| 48 | "reverse" => { |
| 49 | str_arg(args, 0).map_or(Value::Null, |s| Value::String(s.chars().rev().collect())) |
| 50 | } |
| 51 | _ => return None, |
| 52 | }; |
| 53 | Some(v) |
| 54 | } |