use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Statement {
Select(SelectStatement),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SelectStatement {
pub projection: Vec<SelectItem>,
pub from: Option<TableReference>,
pub selection: Option<Expr>,
pub group_by: Vec<Expr>,
pub having: Option<Expr>,
pub order_by: Vec<OrderByExpr>,
pub limit: Option<usize>,
pub offset: Option<usize>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum SelectItem {
Wildcard,
QualifiedWildcard(String),
Expr {
expr: Expr,
alias: Option<String>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TableReference {
Table {
name: String,
alias: Option<String>,
},
Join {
left: Box<TableReference>,
right: Box<TableReference>,
join_type: JoinType,
on: Option<Expr>,
},
Subquery {
query: Box<SelectStatement>,
alias: String,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum JoinType {
Inner,
Left,
Right,
Full,
Cross,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Expr {
Column {
table: Option<String>,
name: String,
},
Literal(Literal),
BinaryOp {
left: Box<Expr>,
op: BinaryOperator,
right: Box<Expr>,
},
UnaryOp {
op: UnaryOperator,
expr: Box<Expr>,
},
Function {
name: String,
args: Vec<Expr>,
},
Case {
operand: Option<Box<Expr>>,
when_then: Vec<(Expr, Expr)>,
else_result: Option<Box<Expr>>,
},
Cast {
expr: Box<Expr>,
data_type: DataType,
},
IsNull(Box<Expr>),
IsNotNull(Box<Expr>),
InList {
expr: Box<Expr>,
list: Vec<Expr>,
negated: bool,
},
Between {
expr: Box<Expr>,
low: Box<Expr>,
high: Box<Expr>,
negated: bool,
},
Subquery(Box<SelectStatement>),
Wildcard,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Literal {
Null,
Boolean(bool),
Integer(i64),
Float(f64),
String(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BinaryOperator {
Plus,
Minus,
Multiply,
Divide,
Modulo,
Eq,
NotEq,
Lt,
LtEq,
Gt,
GtEq,
And,
Or,
Concat,
Like,
NotLike,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum UnaryOperator {
Minus,
Not,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OrderByExpr {
pub expr: Expr,
pub asc: bool,
pub nulls_first: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum DataType {
Boolean,
Int8,
Int16,
Int32,
Int64,
UInt8,
UInt16,
UInt32,
UInt64,
Float32,
Float64,
String,
Binary,
Timestamp,
Date,
Geometry,
}
impl fmt::Display for Statement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Statement::Select(select) => write!(f, "{}", select),
}
}
}
impl fmt::Display for SelectStatement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SELECT ")?;
for (i, item) in self.projection.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", item)?;
}
if let Some(from) = &self.from {
write!(f, " FROM {}", from)?;
}
if let Some(selection) = &self.selection {
write!(f, " WHERE {}", selection)?;
}
if !self.group_by.is_empty() {
write!(f, " GROUP BY ")?;
for (i, expr) in self.group_by.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", expr)?;
}
}
if let Some(having) = &self.having {
write!(f, " HAVING {}", having)?;
}
if !self.order_by.is_empty() {
write!(f, " ORDER BY ")?;
for (i, expr) in self.order_by.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", expr)?;
}
}
if let Some(limit) = self.limit {
write!(f, " LIMIT {}", limit)?;
}
if let Some(offset) = self.offset {
write!(f, " OFFSET {}", offset)?;
}
Ok(())
}
}
impl fmt::Display for SelectItem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SelectItem::Wildcard => write!(f, "*"),
SelectItem::QualifiedWildcard(table) => write!(f, "{}.*", table),
SelectItem::Expr { expr, alias } => {
write!(f, "{}", expr)?;
if let Some(alias) = alias {
write!(f, " AS {}", alias)?;
}
Ok(())
}
}
}
}
impl fmt::Display for TableReference {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TableReference::Table { name, alias } => {
write!(f, "{}", name)?;
if let Some(alias) = alias {
write!(f, " AS {}", alias)?;
}
Ok(())
}
TableReference::Join {
left,
right,
join_type,
on,
} => {
write!(f, "{} {} JOIN {}", left, join_type, right)?;
if let Some(on) = on {
write!(f, " ON {}", on)?;
}
Ok(())
}
TableReference::Subquery { query, alias } => {
write!(f, "({}) AS {}", query, alias)
}
}
}
}
impl fmt::Display for JoinType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
JoinType::Inner => write!(f, "INNER"),
JoinType::Left => write!(f, "LEFT"),
JoinType::Right => write!(f, "RIGHT"),
JoinType::Full => write!(f, "FULL"),
JoinType::Cross => write!(f, "CROSS"),
}
}
}
impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expr::Column { table, name } => {
if let Some(table) = table {
write!(f, "{}.{}", table, name)
} else {
write!(f, "{}", name)
}
}
Expr::Literal(lit) => write!(f, "{}", lit),
Expr::BinaryOp { left, op, right } => {
write!(f, "({} {} {})", left, op, right)
}
Expr::UnaryOp { op, expr } => write!(f, "({} {})", op, expr),
Expr::Function { name, args } => {
write!(f, "{}(", name)?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", arg)?;
}
write!(f, ")")
}
Expr::Case {
operand,
when_then,
else_result,
} => {
write!(f, "CASE")?;
if let Some(operand) = operand {
write!(f, " {}", operand)?;
}
for (when, then) in when_then {
write!(f, " WHEN {} THEN {}", when, then)?;
}
if let Some(else_result) = else_result {
write!(f, " ELSE {}", else_result)?;
}
write!(f, " END")
}
Expr::Cast { expr, data_type } => {
write!(f, "CAST({} AS {:?})", expr, data_type)
}
Expr::IsNull(expr) => write!(f, "{} IS NULL", expr),
Expr::IsNotNull(expr) => write!(f, "{} IS NOT NULL", expr),
Expr::InList {
expr,
list,
negated,
} => {
write!(f, "{}", expr)?;
if *negated {
write!(f, " NOT")?;
}
write!(f, " IN (")?;
for (i, item) in list.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", item)?;
}
write!(f, ")")
}
Expr::Between {
expr,
low,
high,
negated,
} => {
write!(f, "{}", expr)?;
if *negated {
write!(f, " NOT")?;
}
write!(f, " BETWEEN {} AND {}", low, high)
}
Expr::Subquery(query) => write!(f, "({})", query),
Expr::Wildcard => write!(f, "*"),
}
}
}
impl fmt::Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Literal::Null => write!(f, "NULL"),
Literal::Boolean(b) => write!(f, "{}", b),
Literal::Integer(i) => write!(f, "{}", i),
Literal::Float(fl) => write!(f, "{}", fl),
Literal::String(s) => write!(f, "'{}'", s),
}
}
}
impl fmt::Display for BinaryOperator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BinaryOperator::Plus => write!(f, "+"),
BinaryOperator::Minus => write!(f, "-"),
BinaryOperator::Multiply => write!(f, "*"),
BinaryOperator::Divide => write!(f, "/"),
BinaryOperator::Modulo => write!(f, "%"),
BinaryOperator::Eq => write!(f, "="),
BinaryOperator::NotEq => write!(f, "<>"),
BinaryOperator::Lt => write!(f, "<"),
BinaryOperator::LtEq => write!(f, "<="),
BinaryOperator::Gt => write!(f, ">"),
BinaryOperator::GtEq => write!(f, ">="),
BinaryOperator::And => write!(f, "AND"),
BinaryOperator::Or => write!(f, "OR"),
BinaryOperator::Concat => write!(f, "||"),
BinaryOperator::Like => write!(f, "LIKE"),
BinaryOperator::NotLike => write!(f, "NOT LIKE"),
}
}
}
impl fmt::Display for UnaryOperator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnaryOperator::Minus => write!(f, "-"),
UnaryOperator::Not => write!(f, "NOT"),
}
}
}
impl fmt::Display for OrderByExpr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.expr)?;
if self.asc {
write!(f, " ASC")?;
} else {
write!(f, " DESC")?;
}
if self.nulls_first {
write!(f, " NULLS FIRST")?;
} else {
write!(f, " NULLS LAST")?;
}
Ok(())
}
}