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
37pub(crate) fn minimum_arguments(name: &str) -> Option<usize> {
39 let fixed = fixed_parameters(name)?;
40 Some(match local_name(name).as_str() {
41 "json_build_object" | "json_build_array" | "jsonb_build_object" | "jsonb_build_array" => 0,
42 "format" => 1,
43 _ => fixed + 1,
44 })
45}
46
47#[must_use]
49pub fn is_variadic_any(name: &str) -> bool {
50 fixed_parameters(name).is_some()
51}
52
53pub(crate) fn not_an_array() -> SQLError {
54 SQLError::Routine {
55 sqlstate: "42804".into(),
56 message: "VARIADIC argument must be an array".into(),
57 }
58}
59
60fn flatten(values: &[Value], output: &mut Vec<(Option<String>, Value)>) {
61 for value in values {
62 match value {
63 Value::List(values) => flatten(values, output),
64 value => output.push((None, value.clone())),
65 }
66 }
67}
68
69pub fn expand_variadic_any(
71 name: &str,
72 mut arguments: Vec<(Option<String>, Value)>,
73) -> Result<VariadicAnyArguments> {
74 let Some(fixed) = fixed_parameters(name) else {
75 return Ok(VariadicAnyArguments::Arguments(arguments));
76 };
77 if arguments.len() != fixed + 1 {
78 return Ok(VariadicAnyArguments::Arguments(arguments));
79 }
80 let Some((_, variadic)) = arguments.pop() else {
81 return Ok(VariadicAnyArguments::Arguments(arguments));
82 };
83 match variadic {
84 Value::Null if local_name(name) == "format" => {
86 Ok(VariadicAnyArguments::Arguments(arguments))
87 }
88 Value::Null => Ok(VariadicAnyArguments::NullResult),
89 Value::Array(array) => {
90 flatten(array.elements(), &mut arguments);
91 Ok(VariadicAnyArguments::Arguments(arguments))
92 }
93 Value::List(values) => {
94 flatten(&values, &mut arguments);
95 Ok(VariadicAnyArguments::Arguments(arguments))
96 }
97 _ => Err(not_an_array()),
98 }
99}