uqa_sql/semantics/
period.rs1use crate::{
9 ast::RangeSubtype,
10 expr::{parse_multirange, parse_range, CanonicalRange},
11 ColumnType, SQLError,
12};
13use uqa_core::Value;
14
15pub fn period_ranges(
16 value: &Value,
17 column_type: &ColumnType,
18) -> Result<(RangeSubtype, Vec<CanonicalRange>), SQLError> {
19 let (Value::Str(text) | Value::FixedChar(text)) = value else {
20 return Err(SQLError::TypeMismatch(format!(
21 "PERIOD value has incompatible runtime carrier {value:?}"
22 )));
23 };
24 match column_type {
25 ColumnType::Range(subtype) => {
26 let range = parse_range(text, *subtype)?;
27 Ok((
28 *subtype,
29 (!range.is_empty()).then_some(range).into_iter().collect(),
30 ))
31 }
32 ColumnType::Multirange(subtype) => Ok((
33 *subtype,
34 parse_multirange(text, *subtype)?.ranges().to_vec(),
35 )),
36 other => Err(SQLError::TypeMismatch(format!(
37 "PERIOD column must be a range or multirange, got {}",
38 other.sql_name()
39 ))),
40 }
41}
42
43pub fn period_values_overlap(
44 left: &Value,
45 right: &Value,
46 column_type: &ColumnType,
47) -> Result<bool, SQLError> {
48 let (left_subtype, left) = period_ranges(left, column_type)?;
49 let (right_subtype, right) = period_ranges(right, column_type)?;
50 Ok(left_subtype == right_subtype
51 && left
52 .iter()
53 .any(|left| right.iter().any(|right| left.overlaps(right))))
54}