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}