Skip to main content

akar_function/scalar/
map_struct.rs

1use super::get_string;
2use crate::registry::*;
3use akar_common::types::Value;
4
5// ==================== Map & Struct ====================
6
7pub(crate) fn evaluate_map(op: MapOp, args: &[Value]) -> Result<Value, String> {
8    match op {
9        MapOp::Creation => {
10            // map_creation(args): args are alternating key, value, key, value, ...
11            if args.len() % 2 != 0 {
12                return Err("Map creation requires an even number of arguments (key-value pairs)".into());
13            }
14            let mut entries = Vec::new();
15            let mut i = 0;
16            while i < args.len() {
17                let key = match &args[i] {
18                    Value::String(s) => s.clone(),
19                    other => return Err(format!("Map key must be a string, got {:?}", other.logical_type())),
20                };
21                let val = args[i + 1].clone();
22                entries.push((key, val));
23                i += 2;
24            }
25            Ok(Value::Struct(entries))
26        }
27        MapOp::MapFromEntries => {
28            match &args[0] {
29                Value::List(items) => {
30                    let mut result_entries = Vec::new();
31                    for item in items {
32                        match item {
33                            Value::Struct(s) => {
34                                let mut k = None;
35                                let mut v = None;
36                                for (fname, fval) in s {
37                                    if fname == "key" || fname == "k" {
38                                        k = Some(fval);
39                                    } else if fname == "value" || fname == "v" {
40                                        v = Some(fval);
41                                    }
42                                }
43                                if let (Some(Value::String(k_str)), Some(val)) = (k, v) {
44                                    result_entries.push((k_str.clone(), val.clone()));
45                                } else {
46                                    // fallback: use first and second field
47                                    if s.len() >= 2 {
48                                        if let Value::String(k_str) = &s[0].1 {
49                                            result_entries.push((k_str.clone(), s[1].1.clone()));
50                                        }
51                                    }
52                                }
53                            }
54                            _ => return Err("MapFromEntries requires a list of structs".into()),
55                        }
56                    }
57                    Ok(Value::Struct(result_entries))
58                }
59                _ => Err("MapFromEntries requires a list of structs".into()),
60            }
61        }
62        MapOp::Extract => {
63            let map_val = &args[0];
64            let key = get_string(&args[1])?;
65            match map_val {
66                Value::Struct(entries) => {
67                    for (k, v) in entries {
68                        if *k == key {
69                            return Ok(v.clone());
70                        }
71                    }
72                    Err(format!("Key '{}' not found in map", key))
73                }
74                _ => Err("Expected map/struct".into()),
75            }
76        }
77        MapOp::Keys => match &args[0] {
78            Value::Struct(entries) => Ok(Value::List(
79                entries.iter().map(|(k, _)| Value::String(k.clone())).collect(),
80            )),
81            _ => Err("Expected map/struct".into()),
82        },
83        MapOp::Values => match &args[0] {
84            Value::Struct(entries) => Ok(Value::List(entries.iter().map(|(_, v)| v.clone()).collect())),
85            _ => Err("Expected map/struct".into()),
86        },
87        MapOp::Contains => match &args[0] {
88            Value::Struct(entries) => {
89                let key = get_string(&args[1])?;
90                Ok(Value::Bool(entries.iter().any(|(k, _)| *k == key)))
91            }
92            _ => Err("Expected map/struct".into()),
93        },
94    }
95}
96
97pub(crate) fn evaluate_struct(op: StructOp, args: &[Value]) -> Result<Value, String> {
98    match op {
99        StructOp::Creation => {
100            // struct_creation(args): args are alternating field_name (string), value, ...
101            if args.len() % 2 != 0 {
102                return Err("Struct creation requires an even number of arguments (field-value pairs)".into());
103            }
104            let mut entries = Vec::new();
105            let mut i = 0;
106            while i < args.len() {
107                let field_name = match &args[i] {
108                    Value::String(s) => s.clone(),
109                    other => {
110                        return Err(format!(
111                            "Struct field name must be a string, got {:?}",
112                            other.logical_type()
113                        ));
114                    }
115                };
116                let val = args[i + 1].clone();
117                entries.push((field_name, val));
118                i += 2;
119            }
120            Ok(Value::Struct(entries))
121        }
122        StructOp::Extract => {
123            let struct_val = &args[0];
124            let key = get_string(&args[1])?;
125            match struct_val {
126                Value::Struct(entries) => {
127                    for (k, v) in entries {
128                        if *k == key {
129                            return Ok(v.clone());
130                        }
131                    }
132                    Err(format!("Key '{}' not found in struct", key))
133                }
134                _ => Err("Expected struct".into()),
135            }
136        }
137    }
138}