use crate::{
ast::dml::{
expressions::{
between::BetweenExpression, binary::BinaryOperatorExpression, call::CallExpression,
list::ListExpression, not_between::NotBetweenExpression,
parentheses::ParenthesesExpression, subquery::SubqueryExpression,
unary::UnaryOperatorExpression,
},
parts::_where::WhereClause,
},
executor::config::row::TableDataFieldType,
utils::collection::join_vec,
};
use serde::{Deserialize, Serialize};
use super::select_column::SelectColumn;
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub enum SQLExpression {
Unary(Box<UnaryOperatorExpression>), Binary(Box<BinaryOperatorExpression>), Between(Box<BetweenExpression>), NotBetween(Box<NotBetweenExpression>), Parentheses(Box<ParenthesesExpression>), FunctionCall(CallExpression), Subquery(SubqueryExpression),
Integer(i64),
Float(f64),
Boolean(bool),
String(String),
List(ListExpression),
SelectColumn(SelectColumn),
Null,
}
impl SQLExpression {
pub fn is_unary(&self) -> bool {
#[allow(clippy::match_like_matches_macro)]
match self.clone() {
Self::Unary(_) => true,
_ => false,
}
}
pub fn get_select_column_list(&self) -> Vec<SelectColumn> {
Self::get_select_column_list_recursion(self)
}
fn get_select_column_list_recursion(expression: &Self) -> Vec<SelectColumn> {
match expression {
SQLExpression::Integer(_)
| SQLExpression::Float(_)
| SQLExpression::Boolean(_)
| SQLExpression::String(_)
| SQLExpression::Null => {
vec![]
}
SQLExpression::List(list) => list
.value
.iter()
.flat_map(Self::get_select_column_list_recursion)
.collect(),
SQLExpression::SelectColumn(column) => {
vec![column.to_owned()]
}
SQLExpression::Unary(unary) => Self::get_select_column_list(&unary.operand),
SQLExpression::Binary(binary) => join_vec!(
Self::get_select_column_list(&binary.lhs),
Self::get_select_column_list(&binary.rhs)
),
SQLExpression::Between(between) => join_vec!(
Self::get_select_column_list(&between.a),
Self::get_select_column_list(&between.x),
Self::get_select_column_list(&between.y)
),
SQLExpression::NotBetween(between) => join_vec!(
Self::get_select_column_list(&between.a),
Self::get_select_column_list(&between.x),
Self::get_select_column_list(&between.y)
),
SQLExpression::Parentheses(paren) => Self::get_select_column_list(&paren.expression),
SQLExpression::FunctionCall(function_call) => function_call
.arguments
.iter()
.flat_map(Self::get_select_column_list_recursion)
.collect(),
SQLExpression::Subquery(_subquery) => unimplemented!(),
}
}
pub fn has_aggregate(&self) -> bool {
Self::has_aggregate_recursion(self)
}
fn has_aggregate_recursion(this: &Self) -> bool {
match this {
Self::Unary(unary) => Self::has_aggregate_recursion(&unary.operand),
Self::Binary(binary) => {
Self::has_aggregate_recursion(&binary.lhs)
| Self::has_aggregate_recursion(&binary.rhs)
}
Self::Between(between) => {
Self::has_aggregate_recursion(&between.a)
| Self::has_aggregate_recursion(&between.x)
| Self::has_aggregate_recursion(&between.y)
}
Self::NotBetween(not_between) => {
Self::has_aggregate_recursion(¬_between.a)
| Self::has_aggregate_recursion(¬_between.x)
| Self::has_aggregate_recursion(¬_between.y)
}
Self::Parentheses(paren) => Self::has_aggregate_recursion(&paren.expression),
Self::FunctionCall(call) => call.function.is_aggregate(),
_ => false,
}
}
pub fn find_non_aggregate_columns(&self) -> Vec<SelectColumn> {
Self::find_non_aggregate_columns_recursion(self)
}
fn find_non_aggregate_columns_recursion(this: &Self) -> Vec<SelectColumn> {
match this {
Self::Unary(unary) => Self::find_non_aggregate_columns_recursion(&unary.operand),
Self::Binary(binary) => join_vec!(
Self::find_non_aggregate_columns_recursion(&binary.lhs),
Self::find_non_aggregate_columns_recursion(&binary.rhs)
),
Self::Between(between) => join_vec!(
Self::find_non_aggregate_columns_recursion(&between.a),
Self::find_non_aggregate_columns_recursion(&between.x),
Self::find_non_aggregate_columns_recursion(&between.y)
),
Self::NotBetween(not_between) => join_vec!(
Self::find_non_aggregate_columns_recursion(¬_between.a),
Self::find_non_aggregate_columns_recursion(¬_between.x),
Self::find_non_aggregate_columns_recursion(¬_between.y)
),
Self::Parentheses(paren) => {
Self::find_non_aggregate_columns_recursion(&paren.expression)
}
Self::FunctionCall(call) => {
if call.function.is_aggregate() {
vec![]
} else {
call.arguments
.iter()
.cloned()
.flat_map(|e| Self::find_non_aggregate_columns_recursion(&e))
.collect()
}
}
Self::SelectColumn(column) => vec![column.to_owned()],
_ => vec![],
}
}
pub fn find_aggregate_columns(&self) -> Vec<SelectColumn> {
Self::find_aggregate_columns_recursion(self, Default::default())
}
fn find_aggregate_columns_recursion(
this: &Self,
mut context: RecursionContext,
) -> Vec<SelectColumn> {
match this {
Self::Unary(unary) => Self::find_aggregate_columns_recursion(&unary.operand, context),
Self::Binary(binary) => join_vec!(
Self::find_aggregate_columns_recursion(&binary.lhs, context),
Self::find_aggregate_columns_recursion(&binary.rhs, context)
),
Self::Between(between) => join_vec!(
Self::find_aggregate_columns_recursion(&between.a, context),
Self::find_aggregate_columns_recursion(&between.x, context),
Self::find_aggregate_columns_recursion(&between.y, context)
),
Self::NotBetween(not_between) => join_vec!(
Self::find_aggregate_columns_recursion(¬_between.a, context),
Self::find_aggregate_columns_recursion(¬_between.x, context),
Self::find_aggregate_columns_recursion(¬_between.y, context)
),
Self::Parentheses(paren) => {
Self::find_aggregate_columns_recursion(&paren.expression, context)
}
Self::FunctionCall(call) => {
if call.function.is_aggregate() {
context.in_aggregate = true;
call.arguments
.iter()
.cloned()
.flat_map(|e| Self::find_aggregate_columns_recursion(&e, context))
.collect()
} else {
vec![]
}
}
Self::SelectColumn(column) => {
if context.in_aggregate {
vec![column.to_owned()]
} else {
vec![]
}
}
_ => vec![],
}
}
}
impl From<SQLExpression> for WhereClause {
fn from(value: SQLExpression) -> WhereClause {
WhereClause { expression: value }
}
}
impl From<SQLExpression> for Option<Box<SQLExpression>> {
fn from(value: SQLExpression) -> Option<Box<SQLExpression>> {
Some(Box::new(value))
}
}
impl From<TableDataFieldType> for SQLExpression {
fn from(value: TableDataFieldType) -> SQLExpression {
match value {
TableDataFieldType::Integer(value) => SQLExpression::Integer(value),
TableDataFieldType::Float(value) => SQLExpression::Float(value.into()),
TableDataFieldType::Boolean(value) => SQLExpression::Boolean(value),
TableDataFieldType::String(value) => SQLExpression::String(value),
TableDataFieldType::Null => SQLExpression::Null,
TableDataFieldType::Array(value) => SQLExpression::List(
value
.into_iter()
.map(|e| e.into())
.collect::<Vec<_>>()
.into(),
),
}
}
}
#[derive(Debug, Clone, Default, Copy)]
struct RecursionContext {
pub in_aggregate: bool,
}