gitql_core/values/
date.rs1use 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}