gitql_core/values/
range.rs

1use std::any::Any;
2use std::cmp::Ordering;
3
4use gitql_ast::types::range::RangeType;
5use gitql_ast::types::DataType;
6
7use super::base::Value;
8use super::boolean::BoolValue;
9
10#[derive(Clone)]
11pub struct RangeValue {
12    pub start: Box<dyn Value>,
13    pub end: Box<dyn Value>,
14    pub base_type: Box<dyn DataType>,
15}
16
17impl RangeValue {
18    pub fn new(start: Box<dyn Value>, end: Box<dyn Value>, base_type: Box<dyn DataType>) -> Self {
19        RangeValue {
20            start,
21            end,
22            base_type,
23        }
24    }
25}
26
27impl Value for RangeValue {
28    fn literal(&self) -> String {
29        format!("{}..{}", self.start.literal(), self.end.literal())
30    }
31
32    fn equals(&self, other: &Box<dyn Value>) -> bool {
33        if let Some(other_range) = other.as_any().downcast_ref::<RangeValue>() {
34            return self.base_type.equals(&other_range.base_type)
35                && self.start.equals(&other_range.start)
36                && self.end.equals(&other_range.end);
37        }
38        false
39    }
40
41    fn compare(&self, _other: &Box<dyn Value>) -> Option<Ordering> {
42        None
43    }
44
45    fn data_type(&self) -> Box<dyn DataType> {
46        Box::new(RangeType {
47            base: self.base_type.clone(),
48        })
49    }
50
51    fn as_any(&self) -> &dyn Any {
52        self
53    }
54
55    fn logical_or_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
56        if let Some(other_range) = other.as_any().downcast_ref::<RangeValue>() {
57            if !self.equals(other) {
58                return Err("Overlap operator expect both Ranges to have same type".to_string());
59            }
60
61            let max_start = if self.start.compare(&other_range.start).unwrap().is_ge() {
62                &self.start
63            } else {
64                &other_range.start
65            };
66
67            let max_end = if self.end.compare(&other_range.end).unwrap().is_lt() {
68                &self.end
69            } else {
70                &other_range.end
71            };
72
73            let is_overlap = max_end.compare(max_start).unwrap().is_ge();
74            return Ok(Box::new(BoolValue { value: is_overlap }));
75        }
76        Err("Unexpected type to perform `Range Overlap &&` with".to_string())
77    }
78
79    fn contains_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
80        if let Some(other_range) = other.as_any().downcast_ref::<RangeValue>() {
81            let is_in_range = other_range.start.compare(&self.start).unwrap().is_ge()
82                && other_range.end.compare(&self.end).unwrap().is_le();
83            return Ok(Box::new(BoolValue { value: is_in_range }));
84        }
85
86        if self.base_type.equals(&other.data_type()) {
87            let is_in_range = other.compare(&self.start).unwrap().is_ge()
88                && other.compare(&self.end).unwrap().is_le();
89            return Ok(Box::new(BoolValue { value: is_in_range }));
90        }
91
92        Err("Unexpected type to perform `Range contains @>` with".to_string())
93    }
94}