1use crate::executor::expression::ExpressionError;
6use linkrs_core::value::list::List;
7use linkrs_core::value::NullType;
8use linkrs_core::Value;
9use std::collections::BTreeSet;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum ContainerFunction {
14 Head,
15 Last,
16 Tail,
17 Size,
18 Range,
19 Keys,
20 ReverseList,
21 ToSet,
22 ListContains,
23 ListAppend,
24 ListPrepend,
25 ListFilter,
26 ListTransform,
27 ListConcat,
28 ListSort,
29 ListSlice,
30 ListToString,
31 ListDistinct,
32 ListUnique,
33 ListExtract,
34 ListAny,
35 ListAll,
36 ListSingle,
37 ListReduce,
38 StructPack,
39 StructExtract,
40 MapCreation,
41 MapExtract,
42 ElementAt,
43 Cardinality,
44 MapKeys,
45 MapValues,
46}
47
48impl ContainerFunction {
49 pub fn name(&self) -> &str {
51 match self {
52 Self::Head => "head",
53 Self::Last => "last",
54 Self::Tail => "tail",
55 Self::Size => "size",
56 Self::Range => "range",
57 Self::Keys => "keys",
58 Self::ReverseList => "reverse",
59 Self::ToSet => "toset",
60 Self::ListContains => "list_contains",
61 Self::ListAppend => "list_append",
62 Self::ListPrepend => "list_prepend",
63 Self::ListFilter => "list_filter",
64 Self::ListTransform => "list_transform",
65 Self::ListConcat => "list_concat",
66 Self::ListSort => "list_sort",
67 Self::ListSlice => "list_slice",
68 Self::ListToString => "list_to_string",
69 Self::ListDistinct => "list_distinct",
70 Self::ListUnique => "list_unique",
71 Self::ListExtract => "list_extract",
72 Self::ListAny => "list_any",
73 Self::ListAll => "list_all",
74 Self::ListSingle => "list_single",
75 Self::ListReduce => "list_reduce",
76 Self::StructPack => "struct_pack",
77 Self::StructExtract => "struct_extract",
78 Self::MapCreation => "map",
79 Self::MapExtract => "map_extract",
80 Self::ElementAt => "element_at",
81 Self::Cardinality => "cardinality",
82 Self::MapKeys => "map_keys",
83 Self::MapValues => "map_values",
84 }
85 }
86
87 pub fn arity(&self) -> usize {
89 match self {
90 Self::Head => 1,
91 Self::Last => 1,
92 Self::Tail => 1,
93 Self::Size => 1,
94 Self::Range => 2,
95 Self::Keys => 1,
96 Self::ReverseList => 1,
97 Self::ToSet => 1,
98 Self::ListContains => 2,
99 Self::ListAppend => 2,
100 Self::ListPrepend => 2,
101 Self::ListFilter => 2,
102 Self::ListTransform => 2,
103 Self::ListConcat => 2,
104 Self::ListSort => 1,
105 Self::ListSlice => 3,
106 Self::ListToString => 2,
107 Self::ListDistinct => 1,
108 Self::ListUnique => 1,
109 Self::ListExtract => 2,
110 Self::ListAny => 2,
111 Self::ListAll => 2,
112 Self::ListSingle => 2,
113 Self::ListReduce => 3,
114 Self::StructPack => 0,
115 Self::StructExtract => 2,
116 Self::MapCreation => 0,
117 Self::MapExtract => 2,
118 Self::ElementAt => 2,
119 Self::Cardinality => 1,
120 Self::MapKeys => 1,
121 Self::MapValues => 1,
122 }
123 }
124
125 pub fn is_variadic(&self) -> bool {
127 matches!(
128 self,
129 Self::Range | Self::ListConcat | Self::StructPack | Self::MapCreation
130 )
131 }
132
133 pub fn description(&self) -> &str {
135 match self {
136 Self::Head => "Get the first element of the list",
137 Self::Last => "Get the last element of the list",
138 Self::Tail => "Get all elements of the list except the first one",
139 Self::Size => "Get the size of a string, list, map, or set",
140 Self::Range => "Generate a list of integer ranges",
141 Self::Keys => "Get all the keys for vertices, edges, or mappings.",
142 Self::ReverseList => "inversion list",
143 Self::ToSet => "Convert the list to a set.",
144 Self::ListContains => "Check if list contains a value",
145 Self::ListAppend => "Append element to list",
146 Self::ListPrepend => "Prepend element to list",
147 Self::ListFilter => "Filter list elements by predicate",
148 Self::ListTransform => "Transform list elements by function",
149 Self::ListConcat => "Concatenate multiple lists into one",
150 Self::ListSort => "Sort list elements",
151 Self::ListSlice => "Extract a slice from a list",
152 Self::ListToString => "Convert a list to a string with delimiter",
153 Self::ListDistinct => "Remove duplicate elements from list",
154 Self::ListUnique => "Remove duplicate elements from list",
155 Self::ListExtract => "Extract element from list at specified index",
156 Self::ListAny => "Check if any element in mask list is true",
157 Self::ListAll => "Check if all elements in mask list are true",
158 Self::ListSingle => "Check if exactly one element in mask list is true",
159 Self::ListReduce => "Reduce list to a single value using accumulator",
160 Self::StructPack => "Pack values into a struct",
161 Self::StructExtract => "Extract field from struct",
162 Self::MapCreation => "Create a map from key-value pairs",
163 Self::MapExtract => "Extract value from map by key",
164 Self::ElementAt => "Get element at index from list or map",
165 Self::Cardinality => "Get number of elements in map or set",
166 Self::MapKeys => "Get all keys from a map",
167 Self::MapValues => "Get all values from a map",
168 }
169 }
170
171 pub fn execute(&self, args: &[Value]) -> Result<Value, ExpressionError> {
172 if !self.is_variadic() && args.len() != self.arity() {
173 return Err(ExpressionError::invalid_arity(
174 self.name(),
175 self.arity(),
176 args.len(),
177 ));
178 }
179 match self {
180 Self::Head => execute_head(args),
181 Self::Last => execute_last(args),
182 Self::Tail => execute_tail(args),
183 Self::Size => execute_size(args),
184 Self::Range => execute_range(args),
185 Self::Keys => execute_keys(args),
186 Self::ReverseList => execute_reverse_list(args),
187 Self::ToSet => execute_toset(args),
188 Self::ListContains => execute_list_contains(args),
189 Self::ListAppend => execute_list_append(args),
190 Self::ListPrepend => execute_list_prepend(args),
191 Self::ListFilter => execute_list_filter(args),
192 Self::ListTransform => execute_list_transform(args),
193 Self::ListConcat => execute_list_concat(args),
194 Self::ListSort => execute_list_sort(args),
195 Self::ListSlice => execute_list_slice(args),
196 Self::ListToString => execute_list_to_string(args),
197 Self::ListDistinct => execute_list_distinct(args),
198 Self::ListUnique => execute_list_distinct(args),
199 Self::ListExtract => execute_list_extract(args),
200 Self::ListAny => execute_list_any(args),
201 Self::ListAll => execute_list_all(args),
202 Self::ListSingle => execute_list_single(args),
203 Self::ListReduce => execute_list_reduce(args),
204 Self::StructPack => execute_struct_pack(args),
205 Self::StructExtract => execute_struct_extract(args),
206 Self::MapCreation => execute_map_creation(args),
207 Self::MapExtract => execute_map_extract(args),
208 Self::ElementAt => execute_element_at(args),
209 Self::Cardinality => execute_cardinality(args),
210 Self::MapKeys => execute_map_keys(args),
211 Self::MapValues => execute_map_values(args),
212 }
213 }
214}
215
216fn execute_head(args: &[Value]) -> Result<Value, ExpressionError> {
217 match &args[0] {
218 Value::List(list) => Ok(list
219 .values
220 .first()
221 .cloned()
222 .unwrap_or(Value::Null(NullType::Null))),
223 Value::Null(_) => Ok(Value::Null(NullType::Null)),
224 _ => Err(ExpressionError::type_error("head requires a list type")),
225 }
226}
227
228fn execute_last(args: &[Value]) -> Result<Value, ExpressionError> {
229 match &args[0] {
230 Value::List(list) => Ok(list
231 .values
232 .last()
233 .cloned()
234 .unwrap_or(Value::Null(NullType::Null))),
235 Value::Null(_) => Ok(Value::Null(NullType::Null)),
236 _ => Err(ExpressionError::type_error("last requires a list type")),
237 }
238}
239
240fn execute_tail(args: &[Value]) -> Result<Value, ExpressionError> {
241 match &args[0] {
242 Value::List(list) => {
243 if list.values.is_empty() {
244 Ok(Value::list(List { values: vec![] }))
245 } else {
246 Ok(Value::list(List {
247 values: list.values[1..].to_vec(),
248 }))
249 }
250 }
251 Value::Null(_) => Ok(Value::Null(NullType::Null)),
252 _ => Err(ExpressionError::type_error("tail requires a list type")),
253 }
254}
255
256fn execute_size(args: &[Value]) -> Result<Value, ExpressionError> {
257 match &args[0] {
258 Value::String(s) => Ok(Value::BigInt(s.chars().count() as i64)),
259 Value::List(list) => Ok(Value::BigInt(list.values.len() as i64)),
260 Value::Map(map) => Ok(Value::BigInt(map.len() as i64)),
261 Value::Set(set) => Ok(Value::BigInt(set.len() as i64)),
262 Value::Json(j) => {
263 if let Ok(v) = j.to_value() {
264 match v {
265 serde_json::Value::Object(m) => Ok(Value::BigInt(m.len() as i64)),
266 serde_json::Value::Array(a) => Ok(Value::BigInt(a.len() as i64)),
267 _ => Ok(Value::BigInt(1)),
268 }
269 } else {
270 Ok(Value::Null(NullType::Null))
271 }
272 }
273 Value::JsonB(j) => match j.as_value() {
274 serde_json::Value::Object(m) => Ok(Value::BigInt(m.len() as i64)),
275 serde_json::Value::Array(a) => Ok(Value::BigInt(a.len() as i64)),
276 _ => Ok(Value::BigInt(1)),
277 },
278 Value::Null(_) => Ok(Value::Null(NullType::Null)),
279 _ => Err(ExpressionError::type_error(
280 "size requires string, list, map, set, or json type",
281 )),
282 }
283}
284
285fn execute_range(args: &[Value]) -> Result<Value, ExpressionError> {
286 if args.len() < 2 || args.len() > 3 {
287 return Err(ExpressionError::type_error(
288 "range requires 2 or 3 arguments",
289 ));
290 }
291 let to_i64 = |value: &Value| -> Option<i64> {
292 match value {
293 Value::SmallInt(i) => Some(*i as i64),
294 Value::Int(i) => Some(*i as i64),
295 Value::BigInt(i) => Some(*i),
296 _ => None,
297 }
298 };
299 let start = match to_i64(&args[0]) {
300 Some(v) => v,
301 None if args[0].is_null() => return Ok(Value::Null(NullType::Null)),
302 None => {
303 return Err(ExpressionError::type_error(
304 "range requires integer arguments",
305 ))
306 }
307 };
308 let end = match to_i64(&args[1]) {
309 Some(v) => v,
310 None if args[1].is_null() => return Ok(Value::Null(NullType::Null)),
311 None => {
312 return Err(ExpressionError::type_error(
313 "The range function takes integer arguments",
314 ))
315 }
316 };
317 let step = if args.len() > 2 {
318 match to_i64(&args[2]) {
319 Some(v) => v,
320 None if args[2].is_null() => return Ok(Value::Null(NullType::Null)),
321 None => return Err(ExpressionError::type_error("range step must be an integer")),
322 }
323 } else {
324 1
325 };
326
327 if step == 0 {
328 return Err(ExpressionError::new(
329 crate::executor::expression::ExpressionErrorType::InvalidOperation,
330 "range step cannot be 0".to_string(),
331 ));
332 }
333
334 let mut result = Vec::new();
335 if step > 0 {
336 let mut i = start;
337 while i <= end {
338 result.push(Value::BigInt(i));
339 i += step;
340 }
341 } else {
342 let mut i = start;
343 while i >= end {
344 result.push(Value::BigInt(i));
345 i += step;
346 }
347 }
348
349 Ok(Value::list(List { values: result }))
350}
351
352fn execute_keys(args: &[Value]) -> Result<Value, ExpressionError> {
353 let mut keys: BTreeSet<String> = BTreeSet::new();
354
355 match &args[0] {
356 Value::Vertex(v) => {
357 for key in v.tag.properties.keys() {
358 keys.insert(key.to_string());
359 }
360 }
361 Value::Edge(e) => {
362 for key in e.props.keys() {
363 keys.insert(key.to_string());
364 }
365 }
366 Value::Map(m) => {
367 for key in m.keys() {
368 keys.insert(format!("{}", key));
371 }
372 }
373 Value::Json(j) => {
374 if let Ok(serde_json::Value::Object(m)) = j.to_value() {
375 for key in m.keys() {
376 keys.insert(key.to_string());
377 }
378 }
379 }
380 Value::JsonB(j) => {
381 if let serde_json::Value::Object(m) = j.as_value() {
382 for key in m.keys() {
383 keys.insert(key.to_string());
384 }
385 }
386 }
387 Value::Null(_) => return Ok(Value::Null(NullType::Null)),
388 _ => {
389 return Err(ExpressionError::type_error(
390 "keys requires vertex, edge, map or json type",
391 ))
392 }
393 }
394
395 let result: Vec<Value> = keys.into_iter().map(Value::string).collect();
396 Ok(Value::list(List { values: result }))
397}
398
399fn execute_reverse_list(args: &[Value]) -> Result<Value, ExpressionError> {
400 match &args[0] {
401 Value::List(list) => {
402 let mut reversed = list.values.clone();
403 reversed.reverse();
404 Ok(Value::list(List { values: reversed }))
405 }
406 Value::Null(_) => Ok(Value::Null(NullType::Null)),
407 _ => Err(ExpressionError::type_error("reverse requires a list type")),
408 }
409}
410
411fn execute_toset(args: &[Value]) -> Result<Value, ExpressionError> {
412 match &args[0] {
413 Value::List(list) => {
414 let set: std::collections::HashSet<Value> = list.values.iter().cloned().collect();
415 Ok(Value::set(set))
416 }
417 Value::Null(_) => Ok(Value::Null(NullType::Null)),
418 _ => Err(ExpressionError::type_error("toset requires a list type")),
419 }
420}
421
422fn execute_list_contains(args: &[Value]) -> Result<Value, ExpressionError> {
423 match (&args[0], &args[1]) {
424 (Value::List(list), value) => {
425 let contains = list.values.iter().any(|v| v == value);
426 Ok(Value::Bool(contains))
427 }
428 (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
429 _ => Err(ExpressionError::type_error(
430 "list_contains requires a list as first argument",
431 )),
432 }
433}
434
435fn execute_list_append(args: &[Value]) -> Result<Value, ExpressionError> {
436 match &args[0] {
437 Value::List(list) => {
438 let mut new_values = list.values.clone();
439 new_values.push(args[1].clone());
440 Ok(Value::list(List { values: new_values }))
441 }
442 Value::Null(_) => Ok(Value::Null(NullType::Null)),
443 _ => Err(ExpressionError::type_error(
444 "list_append requires a list as first argument",
445 )),
446 }
447}
448
449fn execute_list_prepend(args: &[Value]) -> Result<Value, ExpressionError> {
450 match &args[0] {
451 Value::List(list) => {
452 let mut new_values = vec![args[1].clone()];
453 new_values.extend(list.values.clone());
454 Ok(Value::list(List { values: new_values }))
455 }
456 Value::Null(_) => Ok(Value::Null(NullType::Null)),
457 _ => Err(ExpressionError::type_error(
458 "list_prepend requires a list as first argument",
459 )),
460 }
461}
462
463fn execute_list_filter(args: &[Value]) -> Result<Value, ExpressionError> {
464 match (&args[0], &args[1]) {
465 (Value::List(list), Value::List(mask)) => {
466 let min_len = list.values.len().min(mask.values.len());
467 let filtered: Vec<Value> = list.values[..min_len]
468 .iter()
469 .zip(&mask.values[..min_len])
470 .filter(|(_, m)| match m {
471 Value::Bool(b) => *b,
472 Value::Null(_) => false,
473 _ => true,
474 })
475 .map(|(v, _)| v.clone())
476 .collect();
477 Ok(Value::list(List { values: filtered }))
478 }
479 (Value::List(_), _) => Err(ExpressionError::type_error(
480 "list_filter second argument must be a boolean list",
481 )),
482 (Value::Null(_), _) => Ok(Value::Null(NullType::Null)),
483 _ => Err(ExpressionError::type_error(
484 "list_filter requires a list as first argument",
485 )),
486 }
487}
488
489fn execute_list_transform(args: &[Value]) -> Result<Value, ExpressionError> {
490 match (&args[0], &args[1]) {
491 (Value::List(list), Value::List(replacements)) => {
492 let mut result = list.values.clone();
493 for (item, replacement) in result.iter_mut().zip(replacements.values.iter()) {
494 if !replacement.is_null() {
495 *item = replacement.clone();
496 }
497 }
498 Ok(Value::list(List { values: result }))
499 }
500 (Value::List(_), _) => Err(ExpressionError::type_error(
501 "list_transform second argument must be a list",
502 )),
503 (Value::Null(_), _) => Ok(Value::Null(NullType::Null)),
504 _ => Err(ExpressionError::type_error(
505 "list_transform requires lists as arguments",
506 )),
507 }
508}
509
510fn execute_list_concat(args: &[Value]) -> Result<Value, ExpressionError> {
511 if args.len() < 2 {
512 return Err(ExpressionError::type_error(
513 "list_concat requires at least 2 arguments",
514 ));
515 }
516 let mut result = Vec::new();
517 for arg in args {
518 match arg {
519 Value::List(list) => result.extend(list.values.clone()),
520 Value::Null(_) => return Ok(Value::Null(NullType::Null)),
521 _ => {
522 return Err(ExpressionError::type_error(
523 "list_concat requires list arguments",
524 ))
525 }
526 }
527 }
528 Ok(Value::list(List { values: result }))
529}
530
531fn execute_list_sort(args: &[Value]) -> Result<Value, ExpressionError> {
532 match &args[0] {
533 Value::List(list) => {
534 let mut sorted = list.values.clone();
535 sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
536 Ok(Value::list(List { values: sorted }))
537 }
538 Value::Null(_) => Ok(Value::Null(NullType::Null)),
539 _ => Err(ExpressionError::type_error(
540 "list_sort requires a list type",
541 )),
542 }
543}
544
545fn execute_list_slice(args: &[Value]) -> Result<Value, ExpressionError> {
546 match (&args[0], &args[1], &args[2]) {
547 (Value::List(list), Value::Int(start), Value::Int(end)) => {
548 let len = list.values.len() as i32;
549 let start = if *start < 0 {
550 (len + *start).max(0)
551 } else {
552 (*start).min(len)
553 } as usize;
554 let end = if *end < 0 {
555 (len + *end).max(0)
556 } else {
557 (*end).min(len)
558 } as usize;
559 if start >= end {
560 Ok(Value::list(List { values: vec![] }))
561 } else {
562 Ok(Value::list(List {
563 values: list.values[start..end].to_vec(),
564 }))
565 }
566 }
567 (Value::Null(_), _, _) | (_, Value::Null(_), _) | (_, _, Value::Null(_)) => {
568 Ok(Value::Null(NullType::Null))
569 }
570 _ => Err(ExpressionError::type_error(
571 "list_slice requires list, integer, and integer arguments",
572 )),
573 }
574}
575
576fn execute_list_to_string(args: &[Value]) -> Result<Value, ExpressionError> {
577 match (&args[0], &args[1]) {
578 (Value::List(list), Value::String(delimiter)) => {
579 let strings: Vec<String> = list.values.iter().map(value_to_string).collect();
580 Ok(Value::string(strings.join(delimiter)))
581 }
582 (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
583 _ => Err(ExpressionError::type_error(
584 "list_to_string requires list and string arguments",
585 )),
586 }
587}
588
589fn execute_list_distinct(args: &[Value]) -> Result<Value, ExpressionError> {
590 match &args[0] {
591 Value::List(list) => {
592 let mut seen = std::collections::HashSet::new();
593 let mut result = Vec::new();
594 for item in &list.values {
595 if seen.insert(item.clone()) {
596 result.push(item.clone());
597 }
598 }
599 Ok(Value::list(List { values: result }))
600 }
601 Value::Null(_) => Ok(Value::Null(NullType::Null)),
602 _ => Err(ExpressionError::type_error(
603 "list_distinct requires a list type",
604 )),
605 }
606}
607
608fn execute_list_extract(args: &[Value]) -> Result<Value, ExpressionError> {
609 let len = match &args[0] {
610 Value::List(list) => list.values.len() as i64,
611 Value::Null(_) => return Ok(Value::Null(NullType::Null)),
612 _ => {
613 return Err(ExpressionError::type_error(
614 "list_extract requires a list as first argument",
615 ))
616 }
617 };
618 let idx = match &args[1] {
619 Value::Int(i) => {
620 let i = *i as i64;
621 if i < 0 {
622 len + i
623 } else {
624 i
625 }
626 }
627 Value::BigInt(i) => {
628 let i = *i;
629 if i < 0 {
630 len + i
631 } else {
632 i
633 }
634 }
635 Value::Null(_) => return Ok(Value::Null(NullType::Null)),
636 _ => {
637 return Err(ExpressionError::type_error(
638 "list_extract requires an integer as second argument",
639 ))
640 }
641 };
642 let list = match &args[0] {
643 Value::List(list) => list,
644 _ => unreachable!(),
645 };
646 if idx < 0 || idx >= len {
647 Ok(Value::Null(NullType::Null))
648 } else {
649 Ok(list.values[idx as usize].clone())
650 }
651}
652
653fn execute_list_any(args: &[Value]) -> Result<Value, ExpressionError> {
654 match (&args[0], &args[1]) {
655 (Value::List(list), Value::List(mask)) => {
656 let min_len = list.values.len().min(mask.values.len());
657 let any_true = mask.values[..min_len]
658 .iter()
659 .any(|m| matches!(m, Value::Bool(true)));
660 Ok(Value::Bool(any_true))
661 }
662 (Value::List(_), _) => Err(ExpressionError::type_error(
663 "list_any second argument must be a boolean list",
664 )),
665 (Value::Null(_), _) => Ok(Value::Null(NullType::Null)),
666 _ => Err(ExpressionError::type_error(
667 "list_any requires a list as first argument",
668 )),
669 }
670}
671
672fn execute_list_all(args: &[Value]) -> Result<Value, ExpressionError> {
673 match (&args[0], &args[1]) {
674 (Value::List(list), Value::List(mask)) => {
675 let min_len = list.values.len().min(mask.values.len());
676 if min_len == 0 {
677 return Ok(Value::Bool(true));
678 }
679 let all_true = mask.values[..min_len]
680 .iter()
681 .all(|m| matches!(m, Value::Bool(true)));
682 Ok(Value::Bool(all_true))
683 }
684 (Value::List(_), _) => Err(ExpressionError::type_error(
685 "list_all second argument must be a boolean list",
686 )),
687 (Value::Null(_), _) => Ok(Value::Null(NullType::Null)),
688 _ => Err(ExpressionError::type_error(
689 "list_all requires a list as first argument",
690 )),
691 }
692}
693
694fn execute_list_single(args: &[Value]) -> Result<Value, ExpressionError> {
695 match (&args[0], &args[1]) {
696 (Value::List(list), Value::List(mask)) => {
697 let min_len = list.values.len().min(mask.values.len());
698 let count = mask.values[..min_len]
699 .iter()
700 .filter(|m| matches!(m, Value::Bool(true)))
701 .count();
702 Ok(Value::Bool(count == 1))
703 }
704 (Value::List(_), _) => Err(ExpressionError::type_error(
705 "list_single second argument must be a boolean list",
706 )),
707 (Value::Null(_), _) => Ok(Value::Null(NullType::Null)),
708 _ => Err(ExpressionError::type_error(
709 "list_single requires a list as first argument",
710 )),
711 }
712}
713
714fn execute_list_reduce(args: &[Value]) -> Result<Value, ExpressionError> {
715 if matches!(&args[0], Value::Null(_)) {
720 return Ok(Value::Null(NullType::Null));
721 }
722 Err(ExpressionError::type_error(
723 "list_reduce requires (source, lambda, initial) with a lambda as second argument",
724 ))
725}
726
727fn value_to_string(v: &Value) -> String {
728 match v {
729 Value::Null(_) => String::new(),
730 Value::Bool(b) => b.to_string(),
731 Value::SmallInt(i) => i.to_string(),
732 Value::Int(i) => i.to_string(),
733 Value::BigInt(i) => i.to_string(),
734 Value::Float(f) => f.to_string(),
735 Value::Double(f) => f.to_string(),
736 Value::String(s) => s.to_string(),
737 _ => format!("{:?}", v),
738 }
739}
740
741fn execute_struct_pack(args: &[Value]) -> Result<Value, ExpressionError> {
742 if !args.len().is_multiple_of(2) {
743 return Err(ExpressionError::type_error(
744 "struct_pack requires an even number of arguments (key-value pairs)",
745 ));
746 }
747 let mut fields = std::collections::HashMap::new();
748 let mut i = 0;
749 while i < args.len() {
750 let key = match &args[i] {
751 Value::String(s) => s.to_string(),
752 Value::Null(_) => return Ok(Value::Null(NullType::Null)),
753 _ => {
754 return Err(ExpressionError::type_error(
755 "struct_pack keys must be strings",
756 ))
757 }
758 };
759 fields.insert(key, args[i + 1].clone());
760 i += 2;
761 }
762 Ok(Value::string_map(fields))
763}
764
765fn execute_struct_extract(args: &[Value]) -> Result<Value, ExpressionError> {
766 match (&args[0], &args[1]) {
767 (Value::Map(map), Value::String(key)) => {
768 let key_val = Value::string(key);
769 Ok(map
770 .get(&key_val)
771 .cloned()
772 .unwrap_or(Value::Null(NullType::Null)))
773 }
774 (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
775 _ => Err(ExpressionError::type_error(
776 "struct_extract requires a map and a string key",
777 )),
778 }
779}
780
781fn execute_map_creation(args: &[Value]) -> Result<Value, ExpressionError> {
782 if !args.len().is_multiple_of(2) {
783 return Err(ExpressionError::type_error(
784 "map requires an even number of arguments (key-value pairs)",
785 ));
786 }
787 let mut fields = std::collections::HashMap::new();
788 let mut i = 0;
789 while i < args.len() {
790 let key = match &args[i] {
791 Value::String(s) => s.to_string(),
792 Value::Null(_) => return Ok(Value::Null(NullType::Null)),
793 _ => return Err(ExpressionError::type_error("map keys must be strings")),
794 };
795 fields.insert(key, args[i + 1].clone());
796 i += 2;
797 }
798 Ok(Value::string_map(fields))
799}
800
801fn execute_map_extract(args: &[Value]) -> Result<Value, ExpressionError> {
802 match (&args[0], &args[1]) {
803 (Value::Map(map), Value::String(key)) => {
804 let key_val = Value::string(key);
805 Ok(map
806 .get(&key_val)
807 .cloned()
808 .unwrap_or(Value::Null(NullType::Null)))
809 }
810 (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
811 _ => Err(ExpressionError::type_error(
812 "map_extract requires a map and a string key",
813 )),
814 }
815}
816
817fn execute_element_at(args: &[Value]) -> Result<Value, ExpressionError> {
818 match (&args[0], &args[1]) {
819 (Value::List(list), Value::Int(idx)) => {
820 let idx = *idx;
821 let len = list.values.len() as i32;
822 let actual_idx = if idx < 0 { len + idx } else { idx };
823 if actual_idx < 0 || actual_idx >= len {
824 Ok(Value::Null(NullType::Null))
825 } else {
826 Ok(list.values[actual_idx as usize].clone())
827 }
828 }
829 (Value::List(list), Value::BigInt(idx)) => {
830 let idx = *idx;
831 let len = list.values.len() as i64;
832 let actual_idx = if idx < 0 { len + idx } else { idx };
833 if actual_idx < 0 || actual_idx >= len {
834 Ok(Value::Null(NullType::Null))
835 } else {
836 Ok(list.values[actual_idx as usize].clone())
837 }
838 }
839 (Value::Map(map), Value::String(key)) => {
840 let key_val = Value::string(key);
841 Ok(map
842 .get(&key_val)
843 .cloned()
844 .unwrap_or(Value::Null(NullType::Null)))
845 }
846 (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
847 _ => Err(ExpressionError::type_error(
848 "element_at requires a list or map as first argument",
849 )),
850 }
851}
852
853fn execute_cardinality(args: &[Value]) -> Result<Value, ExpressionError> {
854 match &args[0] {
855 Value::Map(map) => Ok(Value::BigInt(map.len() as i64)),
856 Value::Set(set) => Ok(Value::BigInt(set.len() as i64)),
857 Value::List(list) => Ok(Value::BigInt(list.values.len() as i64)),
858 Value::Null(_) => Ok(Value::Null(NullType::Null)),
859 _ => Err(ExpressionError::type_error(
860 "cardinality requires a map, set, or list type",
861 )),
862 }
863}
864
865fn execute_map_keys(args: &[Value]) -> Result<Value, ExpressionError> {
866 match &args[0] {
867 Value::Map(map) => {
868 let keys: Vec<Value> = map.keys().cloned().collect();
869 Ok(Value::list(List { values: keys }))
870 }
871 Value::Null(_) => Ok(Value::Null(NullType::Null)),
872 _ => Err(ExpressionError::type_error("map_keys requires a map type")),
873 }
874}
875
876fn execute_map_values(args: &[Value]) -> Result<Value, ExpressionError> {
877 match &args[0] {
878 Value::Map(map) => {
879 let values: Vec<Value> = map.values().cloned().collect();
880 Ok(Value::list(List { values }))
881 }
882 Value::Null(_) => Ok(Value::Null(NullType::Null)),
883 _ => Err(ExpressionError::type_error(
884 "map_values requires a map type",
885 )),
886 }
887}
888
889#[cfg(test)]
890mod tests;