gitql_std/array/
mod.rs

1use std::collections::HashMap;
2
3use gitql_ast::types::any::AnyType;
4use gitql_ast::types::array::ArrayType;
5use gitql_ast::types::dynamic::DynamicType;
6use gitql_ast::types::integer::IntType;
7use gitql_ast::types::text::TextType;
8use gitql_core::signature::Signature;
9use gitql_core::signature::StandardFunction;
10use gitql_core::values::array::ArrayValue;
11use gitql_core::values::integer::IntValue;
12use gitql_core::values::null::NullValue;
13use gitql_core::values::text::TextValue;
14use gitql_core::values::Value;
15
16use crate::meta_types::array_element_type;
17use crate::meta_types::array_of_type;
18use crate::meta_types::first_element_type;
19use crate::meta_types::second_element_type;
20
21use rand::seq::SliceRandom;
22
23#[inline(always)]
24pub fn register_std_array_functions(map: &mut HashMap<&'static str, StandardFunction>) {
25    map.insert("array_append", array_append);
26    map.insert("array_prepend", array_prepend);
27    map.insert("array_remove", array_remove);
28    map.insert("array_cat", array_cat);
29    map.insert("array_length", array_length);
30    map.insert("array_shuffle", array_shuffle);
31    map.insert("array_position", array_position);
32    map.insert("array_positions", array_positions);
33    map.insert("array_dims", array_dims);
34    map.insert("array_replace", array_replace);
35    map.insert("trim_array", array_trim);
36    map.insert("cardinality", array_cardinality);
37}
38
39#[inline(always)]
40pub fn register_std_array_function_signatures(map: &mut HashMap<&'static str, Signature>) {
41    map.insert(
42        "array_append",
43        Signature {
44            parameters: vec![
45                Box::new(ArrayType::new(Box::new(AnyType))),
46                Box::new(DynamicType {
47                    function: |elements| array_element_type(first_element_type(elements)),
48                }),
49            ],
50            return_type: Box::new(DynamicType::new(first_element_type)),
51        },
52    );
53    map.insert(
54        "array_prepend",
55        Signature {
56            parameters: vec![
57                Box::new(AnyType),
58                Box::new(DynamicType {
59                    function: |elements| array_of_type(first_element_type(elements)),
60                }),
61            ],
62            return_type: Box::new(DynamicType::new(second_element_type)),
63        },
64    );
65    map.insert(
66        "array_remove",
67        Signature {
68            parameters: vec![
69                Box::new(ArrayType::new(Box::new(AnyType))),
70                Box::new(DynamicType {
71                    function: |elements| array_element_type(first_element_type(elements)),
72                }),
73            ],
74            return_type: Box::new(DynamicType::new(first_element_type)),
75        },
76    );
77    map.insert(
78        "array_cat",
79        Signature {
80            parameters: vec![
81                Box::new(ArrayType::new(Box::new(AnyType))),
82                Box::new(DynamicType::new(first_element_type)),
83            ],
84            return_type: Box::new(DynamicType::new(first_element_type)),
85        },
86    );
87    map.insert(
88        "array_length",
89        Signature {
90            parameters: vec![Box::new(ArrayType {
91                base: Box::new(AnyType),
92            })],
93            return_type: Box::new(IntType),
94        },
95    );
96    map.insert(
97        "array_shuffle",
98        Signature {
99            parameters: vec![Box::new(ArrayType {
100                base: Box::new(AnyType),
101            })],
102            return_type: Box::new(DynamicType {
103                function: first_element_type,
104            }),
105        },
106    );
107    map.insert(
108        "array_position",
109        Signature {
110            parameters: vec![
111                Box::new(ArrayType {
112                    base: Box::new(AnyType),
113                }),
114                Box::new(DynamicType {
115                    function: |elements| array_element_type(first_element_type(elements)),
116                }),
117            ],
118            return_type: Box::new(IntType),
119        },
120    );
121    map.insert(
122        "array_dims",
123        Signature {
124            parameters: vec![Box::new(ArrayType {
125                base: Box::new(AnyType),
126            })],
127            return_type: Box::new(TextType),
128        },
129    );
130    map.insert(
131        "array_replace",
132        Signature {
133            parameters: vec![
134                Box::new(ArrayType {
135                    base: Box::new(AnyType),
136                }),
137                Box::new(DynamicType {
138                    function: |elements| array_element_type(first_element_type(elements)),
139                }),
140                Box::new(DynamicType {
141                    function: |elements| array_element_type(first_element_type(elements)),
142                }),
143            ],
144            return_type: Box::new(DynamicType {
145                function: first_element_type,
146            }),
147        },
148    );
149    map.insert(
150        "trim_array",
151        Signature {
152            parameters: vec![
153                Box::new(ArrayType {
154                    base: Box::new(AnyType),
155                }),
156                Box::new(IntType),
157            ],
158            return_type: Box::new(DynamicType {
159                function: first_element_type,
160            }),
161        },
162    );
163    map.insert(
164        "cardinality",
165        Signature {
166            parameters: vec![Box::new(ArrayType::new(Box::new(AnyType)))],
167            return_type: Box::new(IntType),
168        },
169    );
170}
171
172pub fn array_append(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
173    let mut array = inputs[0].as_array().unwrap();
174    let element = &inputs[1];
175    array.push(element.to_owned());
176
177    let element_type = inputs[0].data_type().clone();
178    Box::new(ArrayValue::new(array, element_type))
179}
180
181pub fn array_prepend(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
182    let element = &inputs[0];
183    let mut array = inputs[1].as_array().unwrap();
184    array.insert(0, element.clone());
185
186    let element_type = inputs[0].data_type().clone();
187    Box::new(ArrayValue::new(array, element_type))
188}
189
190pub fn array_remove(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
191    let array = inputs[0].as_array().unwrap();
192    let element_to_remove = &inputs[1];
193    let array_after_remove = array
194        .into_iter()
195        .filter(|element| !element_to_remove.equals(element))
196        .collect();
197
198    let element_type = inputs[0].data_type().clone();
199    Box::new(ArrayValue::new(array_after_remove, element_type))
200}
201
202pub fn array_cat(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
203    let mut first = inputs[0].as_array().unwrap();
204    let mut other = inputs[1].as_array().unwrap();
205    let mut result = Vec::with_capacity(first.len() + other.len());
206    result.append(&mut first);
207    result.append(&mut other);
208
209    let element_type = inputs[0].data_type().clone();
210    Box::new(ArrayValue::new(result, element_type))
211}
212
213pub fn array_length(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
214    let array = inputs[0].as_array().unwrap();
215    let value = array.len() as i64;
216    Box::new(IntValue::new(value))
217}
218
219pub fn array_shuffle(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
220    let array_type = &inputs[0].data_type();
221    let element_type = &array_type
222        .as_any()
223        .downcast_ref::<ArrayType>()
224        .unwrap()
225        .base;
226    let mut array = inputs[0].as_array().unwrap();
227    array.shuffle(&mut rand::rng());
228    Box::new(ArrayValue::new(array, element_type.clone()))
229}
230
231pub fn array_position(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
232    let array = inputs[0].as_array().unwrap();
233    let elemnet = &inputs[1];
234    if let Some(index) = array.iter().position(|r| r.equals(elemnet)) {
235        return Box::new(IntValue::new((index + 1) as i64));
236    }
237    Box::new(NullValue)
238}
239
240pub fn array_positions(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
241    let array = inputs[0].as_array().unwrap();
242    let target = &inputs[1];
243    let mut positions: Vec<Box<dyn Value>> = vec![];
244    for (index, element) in array.into_iter().enumerate() {
245        if element.equals(target) {
246            positions.push(Box::new(IntValue::new((index + 1) as i64)));
247        }
248    }
249    Box::new(ArrayValue::new(positions, Box::new(IntType)))
250}
251
252pub fn array_dims(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
253    let array_type = inputs[0].data_type();
254    Box::new(TextValue::new(array_type.to_string()))
255}
256
257pub fn array_replace(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
258    let array_type = inputs[0].data_type();
259    let mut array_values = inputs[0].as_array().unwrap();
260    let from = &inputs[1];
261    let to = &inputs[2];
262    for element in &mut array_values {
263        if element.equals(from) {
264            *element = to.clone();
265        }
266    }
267    Box::new(ArrayValue::new(array_values, array_type))
268}
269
270pub fn array_trim(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
271    let mut array = inputs[0].as_array().unwrap();
272    let array_type = inputs[0].data_type();
273    let array_len = array.len();
274    let n = i64::min(array.len().try_into().unwrap(), inputs[1].as_int().unwrap());
275    array.truncate(array_len - n as usize);
276    Box::new(ArrayValue::new(array, array_type))
277}
278
279#[allow(clippy::borrowed_box)]
280pub fn array_cardinality(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
281    fn calculate_array_cardinality(value: &Box<dyn Value>) -> usize {
282        if let Some(array) = value.as_array() {
283            if array.is_empty() {
284                return 0;
285            }
286
287            return array.len() * calculate_array_cardinality(&array[0]);
288        }
289        1
290    }
291
292    let cardinality: usize = calculate_array_cardinality(&inputs[0]);
293    Box::new(IntValue::new(cardinality as i64))
294}