gitql_std/general/
mod.rs

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}