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 lower: Box<dyn Value>,
13    pub upper: Box<dyn Value>,
14    pub base_type: Box<dyn DataType>,
15    pub is_lower_bound_inclusive: bool,
16    pub is_upper_bound_inclusive: bool,
17}
18
19impl RangeValue {
20    pub fn new(lower: Box<dyn Value>, upper: Box<dyn Value>, base_type: Box<dyn DataType>) -> Self {
21        RangeValue {
22            lower,
23            upper,
24            base_type,
25            is_lower_bound_inclusive: true,
26            is_upper_bound_inclusive: false,
27        }
28    }
29}
30
31impl Value for RangeValue {
32    fn literal(&self) -> String {
33        let lower_bound = if self.is_lower_bound_inclusive {
34            '['
35        } else {
36            '('
37        };
38
39        let upper_bound = if self.is_upper_bound_inclusive {
40            ']'
41        } else {
42            ')'
43        };
44
45        format!(
46            "{lower_bound}{}..{}{upper_bound}",
47            self.lower.literal(),
48            self.upper.literal()
49        )
50    }
51
52    fn equals(&self, other: &Box<dyn Value>) -> bool {
53        if let Some(other_range) = other.as_any().downcast_ref::<RangeValue>() {
54            return self.base_type.equals(&other_range.base_type)
55                && self.lower.equals(&other_range.lower)
56                && self.upper.equals(&other_range.upper)
57                && self.is_lower_bound_inclusive == other_range.is_lower_bound_inclusive
58                && self.is_upper_bound_inclusive == other_range.is_upper_bound_inclusive;
59        }
60        false
61    }
62
63    fn compare(&self, _other: &Box<dyn Value>) -> Option<Ordering> {
64        None
65    }
66
67    fn data_type(&self) -> Box<dyn DataType> {
68        Box::new(RangeType::new(self.base_type.clone()))
69    }
70
71    fn as_any(&self) -> &dyn Any {
72        self
73    }
74
75    fn logical_and_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
76        if let Some(other_range) = other.as_any().downcast_ref::<RangeValue>() {
77            if !self.data_type().equals(&other.data_type()) {
78                return Err("Overlap operator expect both Ranges to have the same type".to_string());
79            }
80
81            let compare_lowers = self.lower.compare(&other_range.lower).unwrap();
82            let max_lower = if (self.is_lower_bound_inclusive
83                == other_range.is_lower_bound_inclusive
84                && compare_lowers.is_ge())
85                || compare_lowers.is_gt()
86            {
87                &self.lower
88            } else {
89                &other_range.lower
90            };
91
92            let compare_uppers = self.upper.compare(&other_range.upper).unwrap();
93            let max_upper = if (self.is_lower_bound_inclusive
94                == other_range.is_lower_bound_inclusive
95                && compare_uppers.is_le())
96                || compare_uppers.is_lt()
97            {
98                &self.upper
99            } else {
100                &other_range.upper
101            };
102
103            let is_overlap = max_upper.compare(max_lower).unwrap().is_gt();
104            return Ok(Box::new(BoolValue::new(is_overlap)));
105        }
106        Err("Unexpected type to perform `Range Overlap &&` with".to_string())
107    }
108
109    fn contains_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
110        if let Some(other_range) = other.as_any().downcast_ref::<RangeValue>() {
111            let is_lower_in_range =
112            // Current range has no lower boundraies
113            if self.lower.is_null() {
114                true
115            }
116            // Current range has lower boundraies, but the other range hasn't
117            else if other_range.lower.is_null() {
118                false
119            } else {
120                let compare_lowers = other_range.lower.compare(&self.lower).unwrap();
121                if self.is_lower_bound_inclusive || (self.is_upper_bound_inclusive == other_range.is_upper_bound_inclusive)
122                    { compare_lowers.is_ge() } else  { compare_lowers.is_gt() }
123            };
124
125            let is_range_contains = is_lower_in_range &&
126            // Current range has no upper boundraies
127            if self.upper.is_null() {
128                true
129            }
130            // Current range has upper boundraies, but the other range hasn't
131            else if other_range.upper.is_null() {
132                false
133            } else {
134                let compare_uppers = other_range.upper.compare(&self.upper).unwrap();
135                if self.is_upper_bound_inclusive || (self.is_upper_bound_inclusive == other_range.is_upper_bound_inclusive)
136                    { compare_uppers.is_le() } else  { compare_uppers.is_lt() }
137            };
138
139            return Ok(Box::new(BoolValue::new(is_range_contains)));
140        }
141
142        if self.base_type.equals(&other.data_type()) {
143            let is_lower_in = self.lower.is_null()
144                || if self.is_lower_bound_inclusive {
145                    other.compare(&self.lower).unwrap().is_ge()
146                } else {
147                    other.compare(&self.lower).unwrap().is_gt()
148                };
149            let is_upper_in = self.upper.is_null()
150                || if self.is_upper_bound_inclusive {
151                    other.compare(&self.upper).unwrap().is_le()
152                } else {
153                    other.compare(&self.upper).unwrap().is_lt()
154                };
155            return Ok(Box::new(BoolValue::new(is_lower_in && is_upper_in)));
156        }
157
158        Err("Unexpected type to perform `Range contains @>` with".to_string())
159    }
160}