uqa_sql/expr/
array_transform.rs1use super::{validate_named_argument_order, Result, Value};
10
11pub fn argument_positions(
13 name: &str,
14 argument_names: &[Option<&str>],
15) -> Result<Option<Vec<usize>>> {
16 validate_named_argument_order(argument_names.iter().copied())?;
17 let lower = name.to_ascii_lowercase();
18 let function = lower.strip_prefix("pg_catalog.").unwrap_or(&lower);
19 let parameter_names: &[Option<&str>] = match (function, argument_names.len()) {
20 ("array_reverse", 1) | ("array_sort", 1) => &[None],
21 ("array_sort", 2) => &[Some("array"), Some("descending")],
22 ("array_sort", 3) => &[Some("array"), Some("descending"), Some("nulls_first")],
23 _ => return Ok(None),
24 };
25 let mut occupied = vec![false; parameter_names.len()];
26 let mut positions = Vec::with_capacity(argument_names.len());
27 let mut positional = 0;
28 for argument_name in argument_names {
29 let position = if let Some(argument_name) = argument_name {
30 parameter_names
31 .iter()
32 .position(|candidate| *candidate == Some(*argument_name))
33 } else {
34 let position = positional;
35 positional += 1;
36 Some(position)
37 };
38 let Some(position) = position.filter(|position| *position < occupied.len()) else {
39 return Ok(None);
40 };
41 if occupied[position] {
42 return Ok(None);
43 }
44 occupied[position] = true;
45 positions.push(position);
46 }
47 Ok(occupied.into_iter().all(|slot| slot).then_some(positions))
48}
49
50pub(super) fn reorder_named_values(
51 function: &str,
52 call_args: &[(Option<String>, Value)],
53) -> Option<Vec<Value>> {
54 let argument_names = call_args
55 .iter()
56 .map(|(name, _)| name.as_deref())
57 .collect::<Vec<_>>();
58 let positions = argument_positions(function, &argument_names)
59 .ok()
60 .flatten()?;
61 let mut values = vec![None; call_args.len()];
62 for ((_, value), position) in call_args.iter().zip(positions) {
63 values[position] = Some(value.clone());
64 }
65 values.into_iter().collect()
66}