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 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}