use super::super::Rule;
use crate::velesql::ast::{CompoundQuery, Query, SetOperator};
use crate::velesql::error::ParseError;
use crate::velesql::Parser;
impl Parser {
pub(crate) fn parse_compound_query(
pair: pest::iterators::Pair<Rule>,
) -> Result<Query, ParseError> {
let mut select_stmts = Vec::new();
let mut set_ops = Vec::new();
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::select_stmt => select_stmts.push(Self::parse_select_stmt(inner_pair)?),
Rule::set_operator => set_ops.push(Self::parse_set_operator(inner_pair.as_str())),
_ => {}
}
}
let select = select_stmts
.first()
.cloned()
.ok_or_else(|| ParseError::syntax(0, "", "Expected SELECT statement"))?;
let compound = if set_ops.is_empty() {
None
} else {
let operations: Vec<(SetOperator, _)> = set_ops
.into_iter()
.zip(select_stmts.into_iter().skip(1))
.collect();
if operations.is_empty() {
None
} else {
Some(CompoundQuery { operations })
}
};
Ok(Query {
select,
compound,
match_clause: None,
dml: None,
train: None,
})
}
fn parse_set_operator(text: &str) -> SetOperator {
let upper = text.to_uppercase();
if upper.contains("UNION") && upper.contains("ALL") {
SetOperator::UnionAll
} else if upper.contains("UNION") {
SetOperator::Union
} else if upper.contains("INTERSECT") {
SetOperator::Intersect
} else {
SetOperator::Except
}
}
}