Skip to main content

akar_function/scalar/
utility.rs

1use crate::registry::*;
2use crate::scalar::comparison::compare_values;
3use akar_common::types::Value;
4
5// ==================== Utility ====================
6
7pub(crate) fn evaluate_utility(op: UtilityOp, args: &[Value]) -> Result<Value, String> {
8    match op {
9        UtilityOp::Coalesce | UtilityOp::IfNull => {
10            for arg in args {
11                if !matches!(arg, Value::Null) {
12                    return Ok(arg.clone());
13                }
14            }
15            Ok(Value::Null)
16        }
17        UtilityOp::TypeOf => {
18            if args.is_empty() {
19                return Ok(Value::String("NULL".into()));
20            }
21            Ok(Value::String(format!("{:?}", args[0].logical_type())))
22        }
23        UtilityOp::NullIf => {
24            if args.len() < 2 {
25                return Err("NULLIF requires 2 arguments".into());
26            }
27            if args[0] == args[1] {
28                Ok(Value::Null)
29            } else {
30                Ok(args[0].clone())
31            }
32        }
33        UtilityOp::Size => {
34            if args.is_empty() {
35                return Err("SIZE requires 1 argument".into());
36            }
37            match &args[0] {
38                Value::List(v) => Ok(Value::Int64(v.len() as i64)),
39                Value::String(s) => Ok(Value::Int64(s.len() as i64)),
40                Value::Map(v) => Ok(Value::Int64(v.len() as i64)),
41                Value::Null => Ok(Value::Null),
42                _ => Err(format!("SIZE does not support type {:?}", args[0].logical_type())),
43            }
44        }
45        UtilityOp::Error => {
46            if args.is_empty() {
47                return Err("ERROR requires 1 argument".into());
48            }
49            match &args[0] {
50                Value::String(s) => Err(s.clone()),
51                Value::Null => Err("user-triggered error".into()),
52                other => Err(format!("{:?}", other)),
53            }
54        }
55        UtilityOp::PgIsReady => Ok(Value::Bool(true)),
56        UtilityOp::Greatest => {
57            if args.is_empty() {
58                return Err("GREATEST requires at least one argument".into());
59            }
60            let mut result = Value::Null;
61            for arg in args {
62                if matches!(arg, Value::Null) {
63                    continue;
64                }
65                if matches!(result, Value::Null) {
66                    result = arg.clone();
67                } else if compare_values(arg, &result)?.is_gt() {
68                    result = arg.clone();
69                }
70            }
71            Ok(result)
72        }
73        UtilityOp::Least => {
74            if args.is_empty() {
75                return Err("LEAST requires at least one argument".into());
76            }
77            let mut result = Value::Null;
78            for arg in args {
79                if matches!(arg, Value::Null) {
80                    continue;
81                }
82                if matches!(result, Value::Null) {
83                    result = arg.clone();
84                } else if compare_values(arg, &result)?.is_lt() {
85                    result = arg.clone();
86                }
87            }
88            Ok(result)
89        }
90        UtilityOp::ConstantOrNull => {
91            if args.len() < 2 {
92                return Err("CONSTANT_OR_NULL requires 2 arguments".into());
93            }
94            if matches!(args[0], Value::Null) || matches!(args[1], Value::Null) {
95                Ok(Value::Null)
96            } else {
97                Ok(args[0].clone())
98            }
99        }
100    }
101}