uqa_sql/expr/
variadic_any.rs1use uqa_core::Value;
10
11use super::{Result, SQLError};
12
13pub enum VariadicAnyArguments {
15 Arguments(Vec<(Option<String>, Value)>),
16 NullResult,
18}
19
20fn local_name(name: &str) -> String {
21 let lower = name.to_ascii_lowercase();
22 lower
23 .strip_prefix("pg_catalog.")
24 .map_or_else(|| lower.clone(), str::to_owned)
25}
26
27fn fixed_parameters(name: &str) -> Option<usize> {
29 Some(match local_name(name).as_str() {
30 "concat" | "json_build_object" | "json_build_array" | "jsonb_build_object"
31 | "jsonb_build_array" | "num_nulls" | "num_nonnulls" => 0,
32 "concat_ws" | "format" => 1,
33 _ => return None,
34 })
35}
36
37#[must_use]
39pub fn is_variadic_any(name: &str) -> bool {
40 fixed_parameters(name).is_some()
41}
42
43pub(crate) fn not_an_array() -> SQLError {
44 SQLError::Routine {
45 sqlstate: "42804".into(),
46 message: "VARIADIC argument must be an array".into(),
47 }
48}
49
50fn flatten(values: &[Value], output: &mut Vec<(Option<String>, Value)>) {
51 for value in values {
52 match value {
53 Value::List(values) => flatten(values, output),
54 value => output.push((None, value.clone())),
55 }
56 }
57}
58
59pub fn expand_variadic_any(
61 name: &str,
62 mut arguments: Vec<(Option<String>, Value)>,
63) -> Result<VariadicAnyArguments> {
64 let Some(fixed) = fixed_parameters(name) else {
65 return Ok(VariadicAnyArguments::Arguments(arguments));
66 };
67 if arguments.len() != fixed + 1 {
68 return Ok(VariadicAnyArguments::Arguments(arguments));
69 }
70 let Some((_, variadic)) = arguments.pop() else {
71 return Ok(VariadicAnyArguments::Arguments(arguments));
72 };
73 match variadic {
74 Value::Null if local_name(name) == "format" => {
76 Ok(VariadicAnyArguments::Arguments(arguments))
77 }
78 Value::Null => Ok(VariadicAnyArguments::NullResult),
79 Value::Array(array) => {
80 flatten(array.elements(), &mut arguments);
81 Ok(VariadicAnyArguments::Arguments(arguments))
82 }
83 Value::List(values) => {
84 flatten(&values, &mut arguments);
85 Ok(VariadicAnyArguments::Arguments(arguments))
86 }
87 _ => Err(not_an_array()),
88 }
89}