gitql_core/values/
range.rs1use 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 if self.lower.is_null() {
114 true
115 }
116 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 if self.upper.is_null() {
128 true
129 }
130 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}