gitql_core/values/
base.rs

1use std::any::Any;
2use std::cmp::Ordering;
3use std::fmt;
4
5use dyn_clone::DynClone;
6use gitql_ast::operator::GroupComparisonOperator;
7use gitql_ast::types::DataType;
8use gitql_ast::Interval;
9
10use super::array::ArrayValue;
11use super::boolean::BoolValue;
12use super::composite::CompositeValue;
13use super::date::DateValue;
14use super::datetime::DateTimeValue;
15use super::float::FloatValue;
16use super::integer::IntValue;
17use super::interval::IntervalValue;
18use super::null::NullValue;
19use super::range::RangeValue;
20use super::text::TextValue;
21use super::time::TimeValue;
22
23dyn_clone::clone_trait_object!(Value);
24
25/// The in memory representation of the Values in the GitQL query engine
26pub trait Value: DynClone {
27    /// Return the literal representation for this [`Value`]
28    fn literal(&self) -> String;
29
30    /// Return if other [`Value`] is equal or not to current value
31    #[allow(clippy::borrowed_box)]
32    fn equals(&self, other: &Box<dyn Value>) -> bool;
33
34    /// Return the order between [`Value`] and the current value,
35    /// or None if they can't be ordered
36    #[allow(clippy::borrowed_box)]
37    fn compare(&self, other: &Box<dyn Value>) -> Option<Ordering>;
38
39    /// Return the [`DataType`] for the current [`Value`]
40    fn data_type(&self) -> Box<dyn DataType>;
41
42    /// Return the current value as dynamic [`Any`]
43    fn as_any(&self) -> &dyn Any;
44
45    /// Perform unary `=` operator and return new [`Value`] represent the result or Exception message as [`String`]
46    #[allow(unused_variables)]
47    #[allow(clippy::borrowed_box)]
48    fn add_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
49        Err("Unsupported operator for this type".to_string())
50    }
51
52    /// Perform unary `-` operator and return new [`Value`] represent the result or Exception message as [`String`]
53    #[allow(unused_variables)]
54    #[allow(clippy::borrowed_box)]
55    fn sub_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
56        Err("Unsupported operator for this type".to_string())
57    }
58
59    /// Perform unary `*` operator and return new [`Value`] represent the result or Exception message as [`String`]
60    #[allow(unused_variables)]
61    #[allow(clippy::borrowed_box)]
62    fn mul_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
63        Err("Unsupported operator for this type".to_string())
64    }
65
66    /// Perform unary `/` operator and return new [`Value`] represent the result or Exception message as [`String`]
67    #[allow(unused_variables)]
68    #[allow(clippy::borrowed_box)]
69    fn div_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
70        Err("Unsupported operator for this type".to_string())
71    }
72
73    /// Perform unary `%` operator and return new [`Value`] represent the result or Exception message as [`String`]
74    #[allow(unused_variables)]
75    #[allow(clippy::borrowed_box)]
76    fn rem_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
77        Err("Unsupported operator for this type".to_string())
78    }
79
80    /// Perform unary `^` operator and return new [`Value`] represent the result or Exception message as [`String`]
81    #[allow(unused_variables)]
82    #[allow(clippy::borrowed_box)]
83    fn caret_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
84        Err("Unsupported operator for this type".to_string())
85    }
86
87    /// Perform unary `|` operator and return new [`Value`] represent the result or Exception message as [`String`]
88    #[allow(unused_variables)]
89    #[allow(clippy::borrowed_box)]
90    fn or_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
91        Err("Unsupported operator for this type".to_string())
92    }
93
94    /// Perform unary `&` operator and return new [`Value`] represent the result or Exception message as [`String`]
95    #[allow(unused_variables)]
96    #[allow(clippy::borrowed_box)]
97    fn and_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
98        Err("Unsupported operator for this type".to_string())
99    }
100
101    /// Perform unary `#` operator and return new [`Value`] represent the result or Exception message as [`String`]
102    #[allow(unused_variables)]
103    #[allow(clippy::borrowed_box)]
104    fn xor_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
105        Err("Unsupported operator for this type".to_string())
106    }
107
108    /// Perform unary `||` or `OR` operator and return new [`Value`] represent the result or Exception message as [`String`]
109    #[allow(unused_variables)]
110    #[allow(clippy::borrowed_box)]
111    fn logical_or_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
112        Err("Unsupported operator for this type".to_string())
113    }
114
115    /// Perform unary `&&` or `AND` operator and return new [`Value`] represent the result or Exception message as [`String`]
116    #[allow(unused_variables)]
117    #[allow(clippy::borrowed_box)]
118    fn logical_and_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
119        Err("Unsupported operator for this type".to_string())
120    }
121
122    /// Perform unary `XOR` operator and return new [`Value`] represent the result or Exception message as [`String`]
123    #[allow(unused_variables)]
124    #[allow(clippy::borrowed_box)]
125    fn logical_xor_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
126        Err("Unsupported operator for this type".to_string())
127    }
128
129    /// Perform unary `<<` operator and return new [`Value`] represent the result or Exception message as [`String`]
130    #[allow(unused_variables)]
131    #[allow(clippy::borrowed_box)]
132    fn shl_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
133        Err("Unsupported operator for this type".to_string())
134    }
135
136    /// Perform unary `>>` operator and return new [`Value`] represent the result or Exception message as [`String`]
137    #[allow(unused_variables)]
138    #[allow(clippy::borrowed_box)]
139    fn shr_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
140        Err("Unsupported operator for this type".to_string())
141    }
142
143    /// Perform unary `[I]` operator and return new [`Value`] represent the result or Exception message as [`String`]
144    #[allow(unused_variables)]
145    #[allow(clippy::borrowed_box)]
146    fn index_op(&self, index: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
147        Err("Unsupported operator for this type".to_string())
148    }
149
150    /// Perform unary `[S:E]` operator and return new [`Value`] represent the result or Exception message as [`String`]
151    #[allow(unused_variables)]
152    #[allow(clippy::borrowed_box)]
153    fn slice_op(
154        &self,
155        start: &Option<Box<dyn Value>>,
156        end: &Option<Box<dyn Value>>,
157    ) -> Result<Box<dyn Value>, String> {
158        Err("Unsupported operator for this type".to_string())
159    }
160
161    /// Perform unary `=` operator and return new [`Value`] represent the result or Exception message as [`String`]
162    #[allow(unused_variables)]
163    #[allow(clippy::borrowed_box)]
164    fn eq_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
165        Err("Unsupported operator for this type".to_string())
166    }
167
168    /// Perform unary `= [ALL|ANY|SOME]` operator and return new [`Value`] represent the result or Exception message as [`String`]
169    #[allow(unused_variables)]
170    #[allow(clippy::borrowed_box)]
171    fn group_eq_op(
172        &self,
173        other: &Box<dyn Value>,
174        group_op: &GroupComparisonOperator,
175    ) -> Result<Box<dyn Value>, String> {
176        Err("Unsupported operator for this type".to_string())
177    }
178
179    /// Perform unary `!=` or `<>` operator and return new [`Value`] represent the result or Exception message as [`String`]
180    #[allow(unused_variables)]
181    #[allow(clippy::borrowed_box)]
182    fn bang_eq_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
183        Err("Unsupported operator for this type".to_string())
184    }
185
186    /// Perform unary `!= or <> [ALL|ANY|SOME]` operator and return new [`Value`] represent the result or Exception message as [`String`]
187    #[allow(unused_variables)]
188    #[allow(clippy::borrowed_box)]
189    fn group_bang_eq_op(
190        &self,
191        other: &Box<dyn Value>,
192        group_op: &GroupComparisonOperator,
193    ) -> Result<Box<dyn Value>, String> {
194        Err("Unsupported operator for this type".to_string())
195    }
196
197    /// Perform unary `<=>` operator and return new [`Value`] represent the result or Exception message as [`String`]
198    #[allow(unused_variables)]
199    #[allow(clippy::borrowed_box)]
200    fn null_safe_eq_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
201        Err("Unsupported operator for this type".to_string())
202    }
203
204    /// Perform unary `<=> [ALL|ANY|SOME]` operator and return new [`Value`] represent the result or Exception message as [`String`]
205    #[allow(unused_variables)]
206    #[allow(clippy::borrowed_box)]
207    fn group_null_safe_eq_op(
208        &self,
209        other: &Box<dyn Value>,
210        group_op: &GroupComparisonOperator,
211    ) -> Result<Box<dyn Value>, String> {
212        Err("Unsupported operator for this type".to_string())
213    }
214
215    /// Perform unary `>` operator and return new [`Value`] represent the result or Exception message as [`String`]
216    #[allow(unused_variables)]
217    #[allow(clippy::borrowed_box)]
218    fn gt_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
219        Err("Unsupported operator for this type".to_string())
220    }
221
222    /// Perform unary `> [ALL|ANY|SOME]` operator and return new [`Value`] represent the result or Exception message as [`String`]
223    #[allow(unused_variables)]
224    #[allow(clippy::borrowed_box)]
225    fn group_gt_op(
226        &self,
227        other: &Box<dyn Value>,
228        group_op: &GroupComparisonOperator,
229    ) -> Result<Box<dyn Value>, String> {
230        Err("Unsupported operator for this type".to_string())
231    }
232
233    /// Perform unary `>=` operator and return new [`Value`] represent the result or Exception message as [`String`]
234    #[allow(unused_variables)]
235    #[allow(clippy::borrowed_box)]
236    fn gte_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
237        Err("Unsupported operator for this type".to_string())
238    }
239
240    /// Perform unary `>= [ALL|ANY|SOME]` operator and return new [`Value`] represent the result or Exception message as [`String`]
241    #[allow(unused_variables)]
242    #[allow(clippy::borrowed_box)]
243    fn group_gte_op(
244        &self,
245        other: &Box<dyn Value>,
246        group_op: &GroupComparisonOperator,
247    ) -> Result<Box<dyn Value>, String> {
248        Err("Unsupported operator for this type".to_string())
249    }
250
251    /// Perform unary `<` operator and return new [`Value`] represent the result or Exception message as [`String`]
252    #[allow(unused_variables)]
253    #[allow(clippy::borrowed_box)]
254    fn lt_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
255        Err("Unsupported operator for this type".to_string())
256    }
257
258    /// Perform unary `< [ALL|ANY|SOME]` operator and return new [`Value`] represent the result or Exception message as [`String`]
259    #[allow(unused_variables)]
260    #[allow(clippy::borrowed_box)]
261    fn group_lt_op(
262        &self,
263        other: &Box<dyn Value>,
264        group_op: &GroupComparisonOperator,
265    ) -> Result<Box<dyn Value>, String> {
266        Err("Unsupported operator for this type".to_string())
267    }
268
269    /// Perform unary `<=` operator and return new [`Value`] represent the result or Exception message as [`String`]
270    #[allow(unused_variables)]
271    #[allow(clippy::borrowed_box)]
272    fn lte_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
273        Err("Unsupported operator for this type".to_string())
274    }
275
276    /// Perform unary `<= [ALL|ANY|SOME]` operator and return new [`Value`] represent the result or Exception message as [`String`]
277    #[allow(unused_variables)]
278    #[allow(clippy::borrowed_box)]
279    fn group_lte_op(
280        &self,
281        other: &Box<dyn Value>,
282        group_op: &GroupComparisonOperator,
283    ) -> Result<Box<dyn Value>, String> {
284        Err("Unsupported operator for this type".to_string())
285    }
286
287    /// Perform unary `NOT` operator and return new [`Value`] represent the result or Exception message as [`String`]
288    fn not_op(&self) -> Result<Box<dyn Value>, String> {
289        Err("Unsupported operator for this type".to_string())
290    }
291
292    /// Perform unary `-` operator and return new [`Value`] represent the result or Exception message as [`String`]
293    fn neg_op(&self) -> Result<Box<dyn Value>, String> {
294        Err("Unsupported operator for this type".to_string())
295    }
296
297    /// Perform unary `!` operator and return new [`Value`] represent the result or Exception message as [`String`]
298    fn bang_op(&self) -> Result<Box<dyn Value>, String> {
299        Err("Unsupported operator for this type".to_string())
300    }
301
302    /// Perform `@>` operator and return new [`Value`] represent the result or Exception message as [`String`]
303    #[allow(unused_variables)]
304    #[allow(clippy::borrowed_box)]
305    fn contains_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
306        Err("Unsupported operator for this type".to_string())
307    }
308
309    /// Perform `LIKE` operator and return new [`Value`] represent the result or Exception message as [`String`]
310    #[allow(unused_variables)]
311    #[allow(clippy::borrowed_box)]
312    fn like_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
313        Err("Unsupported operator for this type".to_string())
314    }
315
316    /// Perform `GLOB` operator and return new [`Value`] represent the result or Exception message as [`String`]
317    #[allow(unused_variables)]
318    #[allow(clippy::borrowed_box)]
319    fn glob_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
320        Err("Unsupported operator for this type".to_string())
321    }
322
323    /// Perform `REGEXP` operator and return new [`Value`] represent the result or Exception message as [`String`]
324    #[allow(unused_variables)]
325    #[allow(clippy::borrowed_box)]
326    fn regexp_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
327        Err("Unsupported operator for this type".to_string())
328    }
329
330    /// Perform Cast operator and return new [`Value`] represent the result or Exception message as [`String`]
331    #[allow(unused_variables)]
332    #[allow(clippy::borrowed_box)]
333    fn cast_op(&self, target_type: &Box<dyn DataType>) -> Result<Box<dyn Value>, String> {
334        Err("Unsupported operator for this type".to_string())
335    }
336}
337
338impl dyn Value {
339    /// Return true if this value is [`TextValue`]
340    pub fn is_text(&self) -> bool {
341        self.as_any().downcast_ref::<TextValue>().is_some()
342    }
343
344    /// Return List of [`String`] represent the inner value of [`IntValue`]
345    /// or None if this type it's called from wrong [`Value`]
346    pub fn as_text(&self) -> Option<String> {
347        if let Some(text_value) = self.as_any().downcast_ref::<TextValue>() {
348            return Some(text_value.value.to_string());
349        }
350        None
351    }
352
353    /// Return true if this value is [`IntValue`]
354    pub fn is_int(&self) -> bool {
355        self.as_any().downcast_ref::<IntValue>().is_some()
356    }
357
358    /// Return List of [`i64`] represent the inner value of [`IntValue`]
359    /// or None if this type it's called from wrong [`Value`]
360    pub fn as_int(&self) -> Option<i64> {
361        if let Some(int_value) = self.as_any().downcast_ref::<IntValue>() {
362            return Some(int_value.value);
363        }
364        None
365    }
366
367    /// Return true if this value is [`FloatValue`]
368    pub fn is_float(&self) -> bool {
369        self.as_any().downcast_ref::<FloatValue>().is_some()
370    }
371
372    /// Return List of [`f64`] represent the inner value of [`FloatValue`]
373    /// or None if this type it's called from wrong [`Value`]
374    pub fn as_float(&self) -> Option<f64> {
375        if let Some(float_value) = self.as_any().downcast_ref::<FloatValue>() {
376            return Some(float_value.value);
377        }
378        None
379    }
380
381    /// Return true if this value is [`IntValue`] or [`FloatValue`]
382    pub fn is_number(&self) -> bool {
383        self.is_int() || self.is_float()
384    }
385
386    /// Return true if this value is [`BoolValue`]
387    pub fn is_bool(&self) -> bool {
388        self.as_any().downcast_ref::<BoolValue>().is_some()
389    }
390
391    /// Return List of [`bool`] represent the inner value of [`BoolValue`]
392    /// or None if this type it's called from wrong [`Value`]
393    pub fn as_bool(&self) -> Option<bool> {
394        if let Some(bool_value) = self.as_any().downcast_ref::<BoolValue>() {
395            return Some(bool_value.value);
396        }
397        None
398    }
399
400    /// Return true if this value is [`DateValue`]
401    pub fn is_date(&self) -> bool {
402        self.as_any().downcast_ref::<DateValue>().is_some()
403    }
404
405    /// Return List of [`i64`] represent the inner value of [`DateValue`]
406    /// or None if this type it's called from wrong [`Value`]
407    pub fn as_date(&self) -> Option<i64> {
408        if let Some(date_value) = self.as_any().downcast_ref::<DateValue>() {
409            return Some(date_value.timestamp);
410        }
411        None
412    }
413
414    /// Return true if this value is [`TimeValue`]
415    pub fn is_time(&self) -> bool {
416        self.as_any().downcast_ref::<TimeValue>().is_some()
417    }
418
419    /// Return List of [`String`] represent the inner value of [`DateValue`]
420    /// or None if this type it's called from wrong [`Value`]
421    pub fn as_time(&self) -> Option<String> {
422        if let Some(time_value) = self.as_any().downcast_ref::<DateValue>() {
423            return Some(time_value.timestamp.to_string());
424        }
425        None
426    }
427
428    /// Return true if this value is [`DateTimeValue`]
429    pub fn is_date_time(&self) -> bool {
430        self.as_any().downcast_ref::<DateTimeValue>().is_some()
431    }
432
433    /// Return List of [`i64`] represent the value of [`DateTimeValue`]
434    /// or None if this type it's called from wrong [`Value`]
435    pub fn as_date_time(&self) -> Option<i64> {
436        if let Some(date_time_value) = self.as_any().downcast_ref::<DateTimeValue>() {
437            return Some(date_time_value.value);
438        }
439        None
440    }
441
442    /// Return true if this value is [`IntervalValue`]
443    pub fn is_interval(&self) -> bool {
444        self.as_any().downcast_ref::<IntervalValue>().is_some()
445    }
446
447    /// Return List of [`Interval`] represent the value of [`IntervalValue`]
448    /// or None if this type it's called from wrong [`Value`]
449    pub fn as_interval(&self) -> Option<Interval> {
450        if let Some(interval_value) = self.as_any().downcast_ref::<IntervalValue>() {
451            return Some(interval_value.interval.clone());
452        }
453        None
454    }
455
456    /// Return true if this value is [`ArrayValue`]
457    pub fn is_array(&self) -> bool {
458        self.as_any().downcast_ref::<ArrayValue>().is_some()
459    }
460
461    /// Return true if this value is [`ArrayValue`] and element type match condition
462    pub fn is_array_of(&self, condition: fn(&Box<dyn DataType>) -> bool) -> bool {
463        if let Some(array) = self.as_any().downcast_ref::<ArrayValue>() {
464            return condition(&array.base_type);
465        }
466        false
467    }
468
469    /// Return List of [`Value`] represent the inner values of [`ArrayValue`]
470    /// or None if this type it's called from wrong [`Value`]
471    pub fn as_array(&self) -> Option<Vec<Box<dyn Value>>> {
472        if let Some(array_value) = self.as_any().downcast_ref::<ArrayValue>() {
473            return Some(array_value.values.clone());
474        }
475        None
476    }
477
478    /// Return true if this value is [`RangeValue`]
479    pub fn is_range(&self) -> bool {
480        self.as_any().downcast_ref::<RangeValue>().is_some()
481    }
482
483    /// Return Tuple of two [`Value`] represent the start and the end of [`RangeValue`]
484    /// or None if this type it's called from wrong [`Value`]
485    pub fn as_range(&self) -> Option<(Box<dyn Value>, Box<dyn Value>)> {
486        if let Some(range_value) = self.as_any().downcast_ref::<RangeValue>() {
487            return Some((range_value.start.clone(), range_value.end.clone()));
488        }
489        None
490    }
491
492    /// Return true if this value is [`NullValue`]
493    pub fn is_null(&self) -> bool {
494        self.as_any().downcast_ref::<NullValue>().is_some()
495    }
496
497    /// Return true if this value is [`CompositeValue`]
498    pub fn is_composite(&self) -> bool {
499        self.as_any().downcast_ref::<CompositeValue>().is_some()
500    }
501}
502
503impl fmt::Display for Box<dyn Value> {
504    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
505        write!(f, "{}", self.literal())
506    }
507}
508
509impl PartialEq for Box<dyn Value> {
510    fn eq(&self, other: &Self) -> bool {
511        self.equals(other)
512    }
513}
514
515impl PartialOrd for Box<dyn Value> {
516    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
517        self.compare(other)
518    }
519}