Skip to content

Commit 61413c1

Browse files
committed
Add support for Range lower and upper bounds
1 parent c761052 commit 61413c1

4 files changed

Lines changed: 112 additions & 46 deletions

File tree

crates/gitql-ast/src/types/range.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ impl DataType for RangeType {
3939
vec![Box::new(self.clone()), self.base.clone()]
4040
}
4141

42-
fn can_perform_logical_or_op_with(&self) -> Vec<Box<dyn DataType>> {
42+
fn can_perform_logical_and_op_with(&self) -> Vec<Box<dyn DataType>> {
4343
vec![Box::new(self.clone())]
4444
}
4545

46-
fn logical_or_op_result_type(&self, _other: &Box<dyn DataType>) -> Box<dyn DataType> {
46+
fn logical_and_op_result_type(&self, _other: &Box<dyn DataType>) -> Box<dyn DataType> {
4747
Box::new(BoolType)
4848
}
4949
}

crates/gitql-core/src/values/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ impl dyn Value {
484484
/// or None if this type it's called from wrong [`Value`]
485485
pub fn as_range(&self) -> Option<(Box<dyn Value>, Box<dyn Value>)> {
486486
if let Some(range_value) = self.as_any().downcast_ref::<RangeValue>() {
487-
return Some((range_value.start.clone(), range_value.end.clone()));
487+
return Some((range_value.lower.clone(), range_value.upper.clone()));
488488
}
489489
None
490490
}

crates/gitql-core/src/values/range.rs

Lines changed: 94 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,53 @@ use super::boolean::BoolValue;
99

1010
#[derive(Clone)]
1111
pub struct RangeValue {
12-
pub start: Box<dyn Value>,
13-
pub end: Box<dyn Value>,
12+
pub lower: Box<dyn Value>,
13+
pub upper: Box<dyn Value>,
1414
pub base_type: Box<dyn DataType>,
15+
pub is_lower_bound_inclusive: bool,
16+
pub is_upper_bound_inclusive: bool,
1517
}
1618

1719
impl RangeValue {
18-
pub fn new(start: Box<dyn Value>, end: Box<dyn Value>, base_type: Box<dyn DataType>) -> Self {
20+
pub fn new(lower: Box<dyn Value>, upper: Box<dyn Value>, base_type: Box<dyn DataType>) -> Self {
1921
RangeValue {
20-
start,
21-
end,
22+
lower,
23+
upper,
2224
base_type,
25+
is_lower_bound_inclusive: true,
26+
is_upper_bound_inclusive: false,
2327
}
2428
}
2529
}
2630

2731
impl Value for RangeValue {
2832
fn literal(&self) -> String {
29-
format!("{}..{}", self.start.literal(), self.end.literal())
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+
)
3050
}
3151

3252
fn equals(&self, other: &Box<dyn Value>) -> bool {
3353
if let Some(other_range) = other.as_any().downcast_ref::<RangeValue>() {
3454
return self.base_type.equals(&other_range.base_type)
35-
&& self.start.equals(&other_range.start)
36-
&& self.end.equals(&other_range.end);
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;
3759
}
3860
false
3961
}
@@ -43,50 +65,94 @@ impl Value for RangeValue {
4365
}
4466

4567
fn data_type(&self) -> Box<dyn DataType> {
46-
Box::new(RangeType {
47-
base: self.base_type.clone(),
48-
})
68+
Box::new(RangeType::new(self.base_type.clone()))
4969
}
5070

5171
fn as_any(&self) -> &dyn Any {
5272
self
5373
}
5474

55-
fn logical_or_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
75+
fn logical_and_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
5676
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());
77+
if !self.data_type().equals(&other.data_type()) {
78+
return Err("Overlap operator expect both Ranges to have the same type".to_string());
5979
}
6080

61-
let max_start = if self.start.compare(&other_range.start).unwrap().is_ge() {
62-
&self.start
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
6388
} else {
64-
&other_range.start
89+
&other_range.lower
6590
};
6691

67-
let max_end = if self.end.compare(&other_range.end).unwrap().is_lt() {
68-
&self.end
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
6999
} else {
70-
&other_range.end
100+
&other_range.upper
71101
};
72102

73-
let is_overlap = max_end.compare(max_start).unwrap().is_ge();
74-
return Ok(Box::new(BoolValue { value: is_overlap }));
103+
let is_overlap = max_upper.compare(max_lower).unwrap().is_gt();
104+
return Ok(Box::new(BoolValue::new(is_overlap)));
75105
}
76106
Err("Unexpected type to perform `Range Overlap &&` with".to_string())
77107
}
78108

79109
fn contains_op(&self, other: &Box<dyn Value>) -> Result<Box<dyn Value>, String> {
80110
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 }));
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)));
84140
}
85141

86142
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 }));
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)));
90156
}
91157

92158
Err("Unexpected type to perform `Range contains @>` with".to_string())

crates/gitql-std/src/range/mod.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,27 +61,27 @@ pub fn register_std_range_function_signatures(map: &mut HashMap<&'static str, Si
6161
}
6262

6363
pub fn int4range(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
64-
Box::new(RangeValue {
65-
start: inputs[0].clone(),
66-
end: inputs[1].clone(),
67-
base_type: Box::new(IntType),
68-
})
64+
Box::new(RangeValue::new(
65+
inputs[0].clone(),
66+
inputs[1].clone(),
67+
Box::new(IntType),
68+
))
6969
}
7070

7171
pub fn daterange(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
72-
Box::new(RangeValue {
73-
start: inputs[0].clone(),
74-
end: inputs[1].clone(),
75-
base_type: Box::new(DateType),
76-
})
72+
Box::new(RangeValue::new(
73+
inputs[0].clone(),
74+
inputs[1].clone(),
75+
Box::new(DateType),
76+
))
7777
}
7878

7979
pub fn tsrange(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
80-
Box::new(RangeValue {
81-
start: inputs[0].clone(),
82-
end: inputs[1].clone(),
83-
base_type: Box::new(DateTimeType),
84-
})
80+
Box::new(RangeValue::new(
81+
inputs[0].clone(),
82+
inputs[1].clone(),
83+
Box::new(DateTimeType),
84+
))
8585
}
8686

8787
pub fn isempty(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {

0 commit comments

Comments
 (0)