1use std::cmp::Ordering;
2use std::collections::HashMap;
3
4use gitql_ast::types::any::AnyType;
5use gitql_ast::types::boolean::BoolType;
6use gitql_ast::types::dynamic::DynamicType;
7use gitql_ast::types::text::TextType;
8use gitql_ast::types::varargs::VarargsType;
9use gitql_core::signature::Signature;
10use gitql_core::signature::StandardFunction;
11use gitql_core::values::boolean::BoolValue;
12use gitql_core::values::text::TextValue;
13use gitql_core::values::Value;
14
15use crate::meta_types::first_element_type;
16use crate::meta_types::second_element_type;
17
18use uuid::Uuid;
19
20#[inline(always)]
21pub fn register_std_general_functions(map: &mut HashMap<&'static str, StandardFunction>) {
22 map.insert("isnull", general_is_null);
23 map.insert("isnumeric", general_is_numeric);
24 map.insert("typeof", general_type_of);
25 map.insert("greatest", general_greatest);
26 map.insert("least", general_least);
27 map.insert("uuid", general_uuid);
28 map.insert("if", general_if);
29 map.insert("ifnull", general_ifnull);
30}
31
32#[inline(always)]
33pub fn register_std_general_function_signatures(map: &mut HashMap<&'static str, Signature>) {
34 map.insert(
35 "isnull",
36 Signature {
37 parameters: vec![Box::new(AnyType)],
38 return_type: Box::new(BoolType),
39 },
40 );
41 map.insert(
42 "isnumeric",
43 Signature {
44 parameters: vec![Box::new(AnyType)],
45 return_type: Box::new(BoolType),
46 },
47 );
48 map.insert(
49 "typeof",
50 Signature {
51 parameters: vec![Box::new(AnyType)],
52 return_type: Box::new(TextType),
53 },
54 );
55 map.insert(
56 "greatest",
57 Signature {
58 parameters: vec![
59 Box::new(AnyType),
60 Box::new(AnyType),
61 Box::new(VarargsType {
62 base: Box::new(AnyType),
63 }),
64 ],
65 return_type: Box::new(AnyType),
66 },
67 );
68 map.insert(
69 "least",
70 Signature {
71 parameters: vec![
72 Box::new(AnyType),
73 Box::new(AnyType),
74 Box::new(VarargsType {
75 base: Box::new(AnyType),
76 }),
77 ],
78 return_type: Box::new(AnyType),
79 },
80 );
81 map.insert(
82 "uuid",
83 Signature {
84 parameters: vec![],
85 return_type: Box::new(TextType),
86 },
87 );
88 map.insert(
89 "if",
90 Signature {
91 parameters: vec![
92 Box::new(BoolType),
93 Box::new(AnyType),
94 Box::new(DynamicType {
95 function: second_element_type,
96 }),
97 ],
98 return_type: Box::new(DynamicType {
99 function: second_element_type,
100 }),
101 },
102 );
103 map.insert(
104 "ifnull",
105 Signature {
106 parameters: vec![
107 Box::new(AnyType),
108 Box::new(DynamicType {
109 function: first_element_type,
110 }),
111 ],
112 return_type: Box::new(DynamicType {
113 function: first_element_type,
114 }),
115 },
116 );
117}
118
119pub fn general_is_null(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
120 let is_null = inputs[0].data_type().is_null();
121 Box::new(BoolValue { value: is_null })
122}
123
124pub fn general_is_numeric(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
125 let input_type = inputs[0].data_type();
126 Box::new(BoolValue {
127 value: input_type.is_number(),
128 })
129}
130
131pub fn general_type_of(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
132 let input_type = inputs[0].data_type();
133 Box::new(TextValue {
134 value: input_type.to_string(),
135 })
136}
137
138pub fn general_greatest(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
139 let mut max = &inputs[0];
140
141 for value in inputs.iter().skip(1) {
142 if max.compare(value) == Some(Ordering::Greater) {
143 max = value;
144 }
145 }
146
147 max.to_owned()
148}
149
150pub fn general_least(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
151 let mut least = &inputs[0];
152
153 for value in inputs.iter().skip(1) {
154 if least.compare(value) == Some(Ordering::Less) {
155 least = value;
156 }
157 }
158
159 least.to_owned()
160}
161
162pub fn general_uuid(_inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
163 let uuid = Uuid::new_v4();
164 Box::new(TextValue {
165 value: uuid.to_string(),
166 })
167}
168
169pub fn general_if(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
170 let condition = inputs[0].as_bool().unwrap();
171 if condition {
172 inputs[1].clone()
173 } else {
174 inputs[2].clone()
175 }
176}
177
178pub fn general_ifnull(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
179 if inputs[0].data_type().is_null() {
180 return inputs[1].clone();
181 }
182 inputs[0].clone()
183}