gitql_core/values/
date.rs

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