gitql_core/values/
datetime.rs

1use std::any::Any;
2use std::cmp::Ordering;
3
4use super::base::Value;
5use super::boolean::BoolValue;
6use super::date::DateValue;
7
8use chrono::DateTime;
9use gitql_ast::operator::GroupComparisonOperator;
10use gitql_ast::types::datetime::DateTimeType;
11use gitql_ast::types::DataType;
12
13const VALUE_DATE_TIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S%.3f";
14
15#[derive(Clone)]
16pub struct DateTimeValue {
17    pub value: i64,
18}
19
20impl DateTimeValue {
21    pub fn new(timestamp: i64) -> Self {
22        DateTimeValue { value: timestamp }
23    }
24}
25
26impl Value for DateTimeValue {
27    fn literal(&self) -> String {
28        let datetime = DateTime::from_timestamp(self.value, 0).unwrap();
29        format!("{}", datetime.format(VALUE_DATE_TIME_FORMAT))
30    }
31
32    fn equals(&self, other: &Box<dyn Value>) -> bool {
33        if let Some(other_datetime) = other.as_any().downcast_ref::<DateTimeValue>() {
34            return self.value == other_datetime.value;
35        }
36        false
37    }
38
39    fn compare(&self, other: &Box<dyn Value>) -> Option<Ordering> {
40        if let Some(other_datetime) = other.as_any().downcast_ref::<DateTimeValue>() {
41            return self.value.partial_cmp(&other_datetime.value);
42        }
43        None
44    }
45
46    fn data_type(&self) -> Box<dyn DataType> {
47        Box::new(DateTimeType)
48    }
49
50    fn as_any(&self) -> &dyn Any {
51        self
52    }
53
54    fn eq_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
55        if let Some(other_text) = other.as_any().downcast_ref::<DateTimeValue>() {
56            let are_equals = self.value == other_text.value;
57            return Ok(Box::new(BoolValue { value: are_equals }));
58        }
59        Err("Unexpected type to perform `=` with".to_string())
60    }
61
62    fn group_eq_op(
63        &self,
64        other: &Box<dyn Value>,
65        group_op: &GroupComparisonOperator,
66    ) -> Result<Box<dyn Value>, String> {
67        if other.is_array_of(|element_type| element_type.is_date_time()) {
68            let elements = &other.as_array().unwrap();
69            let mut matches_count = 0;
70            for element in elements.iter() {
71                if self.value == element.as_date_time().unwrap() {
72                    matches_count += 1;
73                    if GroupComparisonOperator::Any.eq(group_op) {
74                        break;
75                    }
76                }
77            }
78
79            let result = match group_op {
80                GroupComparisonOperator::All => matches_count == elements.len(),
81                GroupComparisonOperator::Any => matches_count > 0,
82            };
83
84            return Ok(Box::new(BoolValue::new(result)));
85        }
86        Err("Unexpected type to perform `=` with".to_string())
87    }
88
89    fn bang_eq_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
90        if let Some(other_text) = other.as_any().downcast_ref::<DateTimeValue>() {
91            let are_equals = self.value != other_text.value;
92            return Ok(Box::new(BoolValue { value: are_equals }));
93        }
94        Err("Unexpected type to perform `!=` with".to_string())
95    }
96
97    fn group_bang_eq_op(
98        &self,
99        other: &Box<dyn Value>,
100        group_op: &GroupComparisonOperator,
101    ) -> Result<Box<dyn Value>, String> {
102        if other.is_array_of(|element_type| element_type.is_date_time()) {
103            let elements = &other.as_array().unwrap();
104            let mut matches_count = 0;
105            for element in elements.iter() {
106                if self.value != element.as_date_time().unwrap() {
107                    matches_count += 1;
108                    if GroupComparisonOperator::Any.eq(group_op) {
109                        break;
110                    }
111                }
112            }
113
114            let result = match group_op {
115                GroupComparisonOperator::All => matches_count == elements.len(),
116                GroupComparisonOperator::Any => matches_count > 0,
117            };
118
119            return Ok(Box::new(BoolValue::new(result)));
120        }
121        Err("Unexpected type to perform `!=` with".to_string())
122    }
123
124    fn gt_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
125        if let Some(other_text) = other.as_any().downcast_ref::<DateTimeValue>() {
126            let are_equals = self.value > other_text.value;
127            return Ok(Box::new(BoolValue { value: are_equals }));
128        }
129        Err("Unexpected type to perform `>` with".to_string())
130    }
131
132    fn group_gt_op(
133        &self,
134        other: &Box<dyn Value>,
135        group_op: &GroupComparisonOperator,
136    ) -> Result<Box<dyn Value>, String> {
137        if other.is_array_of(|element_type| element_type.is_date_time()) {
138            let elements = &other.as_array().unwrap();
139            let mut matches_count = 0;
140            for element in elements.iter() {
141                if self.value > element.as_date_time().unwrap() {
142                    matches_count += 1;
143                    if GroupComparisonOperator::Any.eq(group_op) {
144                        break;
145                    }
146                }
147            }
148
149            let result = match group_op {
150                GroupComparisonOperator::All => matches_count == elements.len(),
151                GroupComparisonOperator::Any => matches_count > 0,
152            };
153
154            return Ok(Box::new(BoolValue::new(result)));
155        }
156        Err("Unexpected type to perform `>` with".to_string())
157    }
158
159    fn gte_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
160        if let Some(other_text) = other.as_any().downcast_ref::<DateTimeValue>() {
161            let are_equals = self.value >= other_text.value;
162            return Ok(Box::new(BoolValue { value: are_equals }));
163        }
164        Err("Unexpected type to perform `>=` with".to_string())
165    }
166
167    fn group_gte_op(
168        &self,
169        other: &Box<dyn Value>,
170        group_op: &GroupComparisonOperator,
171    ) -> Result<Box<dyn Value>, String> {
172        if other.is_array_of(|element_type| element_type.is_date_time()) {
173            let elements = &other.as_array().unwrap();
174            let mut matches_count = 0;
175            for element in elements.iter() {
176                if self.value >= element.as_date_time().unwrap() {
177                    matches_count += 1;
178                    if GroupComparisonOperator::Any.eq(group_op) {
179                        break;
180                    }
181                }
182            }
183
184            let result = match group_op {
185                GroupComparisonOperator::All => matches_count == elements.len(),
186                GroupComparisonOperator::Any => matches_count > 0,
187            };
188
189            return Ok(Box::new(BoolValue::new(result)));
190        }
191        Err("Unexpected type to perform `>=` with".to_string())
192    }
193
194    fn lt_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
195        if let Some(other_text) = other.as_any().downcast_ref::<DateTimeValue>() {
196            let are_equals = self.value < other_text.value;
197            return Ok(Box::new(BoolValue { value: are_equals }));
198        }
199        Err("Unexpected type to perform `<` with".to_string())
200    }
201
202    fn group_lt_op(
203        &self,
204        other: &Box<dyn Value>,
205        group_op: &GroupComparisonOperator,
206    ) -> Result<Box<dyn Value>, String> {
207        if other.is_array_of(|element_type| element_type.is_date_time()) {
208            let elements = &other.as_array().unwrap();
209            let mut matches_count = 0;
210            for element in elements.iter() {
211                if self.value < element.as_date_time().unwrap() {
212                    matches_count += 1;
213                    if GroupComparisonOperator::Any.eq(group_op) {
214                        break;
215                    }
216                }
217            }
218
219            let result = match group_op {
220                GroupComparisonOperator::All => matches_count == elements.len(),
221                GroupComparisonOperator::Any => matches_count > 0,
222            };
223
224            return Ok(Box::new(BoolValue::new(result)));
225        }
226        Err("Unexpected type to perform `<` with".to_string())
227    }
228
229    fn lte_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
230        if let Some(other_text) = other.as_any().downcast_ref::<DateTimeValue>() {
231            let are_equals = self.value <= other_text.value;
232            return Ok(Box::new(BoolValue { value: are_equals }));
233        }
234        Err("Unexpected type to perform `<=` with".to_string())
235    }
236
237    fn group_lte_op(
238        &self,
239        other: &Box<dyn Value>,
240        group_op: &GroupComparisonOperator,
241    ) -> Result<Box<dyn Value>, String> {
242        if other.is_array_of(|element_type| element_type.is_date_time()) {
243            let elements = &other.as_array().unwrap();
244            let mut matches_count = 0;
245            for element in elements.iter() {
246                if self.value <= element.as_date_time().unwrap() {
247                    matches_count += 1;
248                    if GroupComparisonOperator::Any.eq(group_op) {
249                        break;
250                    }
251                }
252            }
253
254            let result = match group_op {
255                GroupComparisonOperator::All => matches_count == elements.len(),
256                GroupComparisonOperator::Any => matches_count > 0,
257            };
258
259            return Ok(Box::new(BoolValue::new(result)));
260        }
261        Err("Unexpected type to perform `<=` with".to_string())
262    }
263
264    fn cast_op(&self, target_type: &Box<dyn DataType>) -> Result<Box<dyn Value>, String> {
265        if target_type.is_date() {
266            return Ok(Box::new(DateValue {
267                timestamp: self.value,
268            }));
269        }
270        Err("Unexpected type to perform `Cast` with".to_string())
271    }
272}