use std::mem::swap;
use hamelin_lib::operator::Operator;
use hamelin_lib::sql::expression::apply::BinaryOperatorApply;
use hamelin_lib::sql::expression::identifier::Identifier;
use hamelin_lib::sql::expression::{OrderByExpression, SQLExpression};
use hamelin_lib::sql::query::projection::{Binding, Projection};
use hamelin_lib::sql::query::SQLQuery;
use crate::env::Environment;
pub fn prepend_projections(
query: &SQLQuery,
mut projections: Vec<Projection>,
env: &Environment,
) -> SQLQuery {
let mut ret = query.clone();
if ret.references_column_in_projections(&projections) {
ret = ret.push_down();
}
let new_names: Vec<Identifier> = projections
.iter()
.map(|p| match p {
Projection::Binding(Binding { name, .. }) => name.clone().into(),
Projection::ColumnProjection(cp) => cp.identifier.clone(),
})
.collect();
ret = ret.remove_projections(&new_names[..]);
swap(&mut ret.projections, &mut projections);
ret.projections.extend(projections.iter().cloned());
for projection in env.get_column_projections() {
if ret.projections.iter().all(|p| match p {
Projection::ColumnProjection(cp) => {
cp.identifier.last() != projection.identifier.last()
}
Projection::Binding(Binding { name, .. }) => {
let id: Identifier = name.clone().into();
id != projection.identifier
}
}) {
ret.projections.push(projection.into());
}
}
ret
}
pub fn add_filter_condition(
query: &SQLQuery,
condition: SQLExpression,
env: &Environment,
) -> SQLQuery {
let mut ret = query.clone();
if ret.references_columns_in_column_refs(&condition.get_column_references()[..]) {
ret = ret.push_down().select(
env.get_column_projections()
.into_iter()
.map(|cp| cp.into())
.collect(),
);
}
let new_where = ret
.where_
.map(|current| {
BinaryOperatorApply::new(
Operator::And.try_into().unwrap(),
condition.clone(),
current.clone(),
)
.into()
})
.unwrap_or(condition);
ret.where_ = Some(new_where);
ret
}
pub fn add_order_expression(
query: SQLQuery,
order_by: Vec<OrderByExpression>,
env: &Environment,
) -> SQLQuery {
let push_down_needed = order_by
.iter()
.map(|e| SQLExpression::from(e.clone()).get_column_references())
.any(|c| query.references_columns_in_column_refs(&c[..]));
let ret_query = if push_down_needed {
query.push_down().select(
env.get_column_projections()
.into_iter()
.map(|cp| Projection::from(cp))
.collect(),
)
} else {
query.clone()
};
ret_query.order_by(order_by)
}
pub fn apply_limit(query: SQLQuery, limit: SQLExpression, env: &Environment) -> SQLQuery {
if query.limit.is_some() {
query
.push_down()
.select(
env.get_column_projections()
.into_iter()
.map(|cp| Projection::from(cp))
.collect(),
)
.limit(limit)
} else {
query.limit(limit)
}
}