1use std::cmp::Ordering;
2use std::collections::HashMap;
3use std::sync::OnceLock;
4
5use gitql_ast::types::any::AnyType;
6use gitql_ast::types::boolean::BoolType;
7use gitql_ast::types::date::DateType;
8use gitql_ast::types::datetime::DateTimeType;
9use gitql_ast::types::dynamic::DynamicType;
10use gitql_ast::types::float::FloatType;
11use gitql_ast::types::integer::IntType;
12use gitql_ast::types::null::NullType;
13use gitql_ast::types::optional::OptionType;
14use gitql_ast::types::text::TextType;
15use gitql_ast::types::time::TimeType;
16use gitql_ast::types::varargs::VarargsType;
17use gitql_ast::types::variant::VariantType;
18use gitql_core::signature::AggregationFunction;
19use gitql_core::signature::Signature;
20use gitql_core::values::array::ArrayValue;
21use gitql_core::values::boolean::BoolValue;
22use gitql_core::values::integer::IntValue;
23use gitql_core::values::null::NullValue;
24use gitql_core::values::text::TextValue;
25use gitql_core::values::Value;
26
27use crate::meta_types::array_of_type;
28use crate::meta_types::first_element_type;
29
30pub fn aggregation_functions() -> &'static HashMap<&'static str, AggregationFunction> {
31 static HASHMAP: OnceLock<HashMap<&'static str, AggregationFunction>> = OnceLock::new();
32 HASHMAP.get_or_init(|| {
33 let mut map: HashMap<&'static str, AggregationFunction> = HashMap::new();
34 map.insert("max", aggregation_max);
35 map.insert("min", aggregation_min);
36 map.insert("sum", aggregation_sum);
37 map.insert("avg", aggregation_average);
38 map.insert("count", aggregation_count);
39 map.insert("group_concat", aggregation_group_concat);
40 map.insert("bool_and", aggregation_bool_and);
41 map.insert("bool_or", aggregation_bool_or);
42 map.insert("bit_and", aggregation_bit_and);
43 map.insert("bit_or", aggregation_bit_or);
44 map.insert("bit_xor", aggregation_bit_xor);
45 map.insert("array_agg", aggregation_array_agg);
46 map
47 })
48}
49
50pub fn aggregation_function_signatures() -> HashMap<&'static str, Signature> {
51 let mut map: HashMap<&'static str, Signature> = HashMap::new();
52 map.insert(
53 "max",
54 Signature {
55 parameters: vec![Box::new(VariantType {
56 variants: vec![
57 Box::new(IntType),
58 Box::new(FloatType),
59 Box::new(TextType),
60 Box::new(DateType),
61 Box::new(TimeType),
62 Box::new(DateTimeType),
63 ],
64 })],
65 return_type: Box::new(DynamicType {
66 function: first_element_type,
67 }),
68 },
69 );
70 map.insert(
71 "min",
72 Signature {
73 parameters: vec![Box::new(VariantType {
74 variants: vec![
75 Box::new(IntType),
76 Box::new(FloatType),
77 Box::new(TextType),
78 Box::new(DateType),
79 Box::new(TimeType),
80 Box::new(DateTimeType),
81 ],
82 })],
83 return_type: Box::new(DynamicType {
84 function: first_element_type,
85 }),
86 },
87 );
88 map.insert(
89 "sum",
90 Signature {
91 parameters: vec![Box::new(IntType)],
92 return_type: Box::new(IntType),
93 },
94 );
95 map.insert(
96 "avg",
97 Signature {
98 parameters: vec![Box::new(IntType)],
99 return_type: Box::new(IntType),
100 },
101 );
102 map.insert(
103 "count",
104 Signature {
105 parameters: vec![Box::new(OptionType {
106 base: Some(Box::new(AnyType)),
107 })],
108 return_type: Box::new(IntType),
109 },
110 );
111 map.insert(
112 "group_concat",
113 Signature {
114 parameters: vec![Box::new(VarargsType {
115 base: Box::new(AnyType),
116 })],
117 return_type: Box::new(TextType),
118 },
119 );
120 map.insert(
121 "bool_and",
122 Signature {
123 parameters: vec![Box::new(BoolType)],
124 return_type: Box::new(BoolType),
125 },
126 );
127 map.insert(
128 "bool_or",
129 Signature {
130 parameters: vec![Box::new(BoolType)],
131 return_type: Box::new(BoolType),
132 },
133 );
134 map.insert(
135 "bit_and",
136 Signature {
137 parameters: vec![Box::new(IntType)],
138 return_type: Box::new(IntType),
139 },
140 );
141 map.insert(
142 "bit_or",
143 Signature {
144 parameters: vec![Box::new(IntType)],
145 return_type: Box::new(IntType),
146 },
147 );
148 map.insert(
149 "bit_xor",
150 Signature {
151 parameters: vec![Box::new(IntType)],
152 return_type: Box::new(IntType),
153 },
154 );
155 map.insert(
156 "array_agg",
157 Signature {
158 parameters: vec![Box::new(AnyType)],
159 return_type: Box::new(DynamicType {
160 function: |elements| array_of_type(first_element_type(elements)),
161 }),
162 },
163 );
164 map
165}
166
167pub fn aggregation_max(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
168 let mut max_value = &group_values[0][0];
169 for row_values in group_values {
170 let single_value = &row_values[0];
171 if max_value.compare(single_value) == Some(Ordering::Less) {
172 max_value = single_value;
173 }
174 }
175 max_value.clone()
176}
177
178pub fn aggregation_min(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
179 let mut min_value = &group_values[0][0];
180 for row_values in group_values {
181 let single_value = &row_values[0];
182 if min_value.compare(single_value) == Some(Ordering::Greater) {
183 min_value = single_value;
184 }
185 }
186 min_value.clone()
187}
188
189pub fn aggregation_sum(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
190 let mut sum: i64 = 0;
191 for row_values in group_values {
192 if let Some(int_value) = row_values[0].as_any().downcast_ref::<IntValue>() {
193 sum += int_value.value;
194 }
195 }
196 Box::new(IntValue { value: sum })
197}
198
199pub fn aggregation_average(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
200 let mut sum: i64 = 0;
201 for row_values in group_values {
202 if let Some(int_value) = row_values[0].as_any().downcast_ref::<IntValue>() {
203 sum += int_value.value;
204 }
205 }
206 let count: i64 = group_values[0].len().try_into().unwrap();
207 Box::new(IntValue { value: sum / count })
208}
209
210pub fn aggregation_count(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
211 Box::new(IntValue {
212 value: group_values.len() as i64,
213 })
214}
215
216pub fn aggregation_group_concat(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
217 let mut string_values: Vec<String> = vec![];
218 for row_values in group_values {
219 for value in row_values {
220 string_values.push(value.literal());
221 }
222 }
223 Box::new(TextValue {
224 value: string_values.concat(),
225 })
226}
227
228pub fn aggregation_bool_and(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
229 for row_values in group_values {
230 if let Some(bool_value) = row_values[0].as_any().downcast_ref::<BoolValue>() {
231 if !bool_value.value {
232 return Box::new(BoolValue { value: false });
233 }
234 }
235 }
236 Box::new(BoolValue { value: true })
237}
238
239pub fn aggregation_bool_or(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
240 for row_values in group_values {
241 if let Some(bool_value) = row_values[0].as_any().downcast_ref::<BoolValue>() {
242 if bool_value.value {
243 return Box::new(BoolValue { value: true });
244 }
245 }
246 }
247 Box::new(BoolValue { value: false })
248}
249
250pub fn aggregation_bit_and(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
251 let mut value: i64 = 1;
252 let mut has_non_null = false;
253 for row_values in group_values {
254 if row_values[0].data_type().is_null() {
255 continue;
256 }
257
258 if let Some(int_value) = row_values[0].as_any().downcast_ref::<IntValue>() {
259 value &= int_value.value;
260 has_non_null = true;
261 }
262 }
263
264 if has_non_null {
265 Box::new(IntValue { value })
266 } else {
267 Box::new(NullValue)
268 }
269}
270
271pub fn aggregation_bit_or(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
272 let mut value: i64 = 0;
273 let mut has_non_null = false;
274 for row_values in group_values {
275 if row_values[0].data_type().is_null() {
276 continue;
277 }
278
279 if let Some(int_value) = row_values[0].as_any().downcast_ref::<IntValue>() {
280 value |= int_value.value;
281 has_non_null = true;
282 }
283 }
284
285 if has_non_null {
286 Box::new(IntValue { value })
287 } else {
288 Box::new(NullValue)
289 }
290}
291
292pub fn aggregation_bit_xor(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
293 let mut value: i64 = 0;
294 let mut has_non_null = false;
295 for row_values in group_values {
296 if row_values[0].data_type().is_null() {
297 continue;
298 }
299
300 if let Some(int_value) = row_values[0].as_any().downcast_ref::<IntValue>() {
301 value ^= int_value.value;
302 has_non_null = true;
303 }
304 }
305
306 if has_non_null {
307 Box::new(IntValue { value })
308 } else {
309 Box::new(NullValue)
310 }
311}
312
313pub fn aggregation_array_agg(group_values: &[Vec<Box<dyn Value>>]) -> Box<dyn Value> {
314 let mut array: Vec<Box<dyn Value>> = vec![];
315 for row_values in group_values {
316 array.push(row_values[0].clone());
317 }
318
319 let element_type = if array.is_empty() {
320 Box::new(NullType)
321 } else {
322 array[0].data_type()
323 };
324
325 Box::new(ArrayValue {
326 values: array,
327 base_type: element_type,
328 })
329}