use crate::ast::expr::{Expression, Identifier, TableName};
use core::range::Range;
use oak_core::source::{SourceBuffer, ToSource};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SelectStatement {
pub items: Vec<SelectItem>,
pub from: Option<TableName>,
pub joins: Vec<JoinClause>,
pub expr: Option<Expression>, pub group_by: Option<GroupByClause>,
pub having: Option<HavingClause>,
pub order_by: Option<OrderByClause>,
pub limit: Option<LimitClause>,
#[serde(with = "oak_core::serde_range")]
pub span: Range<usize>,
}
impl ToSource for SelectStatement {
fn to_source(&self, buffer: &mut SourceBuffer) {
buffer.push("SELECT");
for (i, item) in self.items.iter().enumerate() {
if i > 0 {
buffer.push(",");
}
item.to_source(buffer);
}
if let Some(from) = &self.from {
buffer.push("FROM");
from.to_source(buffer);
}
for join in &self.joins {
join.to_source(buffer);
}
if let Some(expr) = &self.expr {
buffer.push("WHERE");
expr.to_source(buffer);
}
if let Some(group_by) = &self.group_by {
group_by.to_source(buffer);
}
if let Some(having) = &self.having {
having.to_source(buffer);
}
if let Some(order_by) = &self.order_by {
order_by.to_source(buffer);
}
if let Some(limit) = &self.limit {
limit.to_source(buffer);
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SelectItem {
Star {
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
Expression {
expr: Expression,
alias: Option<Identifier>,
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
}
impl ToSource for SelectItem {
fn to_source(&self, buffer: &mut SourceBuffer) {
match self {
SelectItem::Star { .. } => buffer.push("*"),
SelectItem::Expression { expr, alias, .. } => {
expr.to_source(buffer);
if let Some(alias) = alias {
buffer.push("AS");
alias.to_source(buffer);
}
}
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct JoinClause {
pub join_type: JoinType,
pub table: TableName,
pub on: Option<Expression>,
#[serde(with = "oak_core::serde_range")]
pub span: Range<usize>,
}
impl ToSource for JoinClause {
fn to_source(&self, buffer: &mut SourceBuffer) {
self.join_type.to_source(buffer);
buffer.push("JOIN");
self.table.to_source(buffer);
if let Some(on) = &self.on {
buffer.push("ON");
on.to_source(buffer);
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum JoinType {
Inner,
Left,
Right,
Full,
}
impl ToSource for JoinType {
fn to_source(&self, buffer: &mut SourceBuffer) {
match self {
JoinType::Inner => buffer.push("INNER"),
JoinType::Left => buffer.push("LEFT"),
JoinType::Right => buffer.push("RIGHT"),
JoinType::Full => buffer.push("FULL"),
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GroupByClause {
pub columns: Vec<Expression>,
#[serde(with = "oak_core::serde_range")]
pub span: Range<usize>,
}
impl ToSource for GroupByClause {
fn to_source(&self, buffer: &mut SourceBuffer) {
buffer.push("GROUP");
buffer.push("BY");
for (i, col) in self.columns.iter().enumerate() {
if i > 0 {
buffer.push(",");
}
col.to_source(buffer);
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct HavingClause {
pub condition: Expression,
#[serde(with = "oak_core::serde_range")]
pub span: Range<usize>,
}
impl ToSource for HavingClause {
fn to_source(&self, buffer: &mut SourceBuffer) {
buffer.push("HAVING");
self.condition.to_source(buffer);
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct OrderByClause {
pub items: Vec<OrderByItem>,
#[serde(with = "oak_core::serde_range")]
pub span: Range<usize>,
}
impl ToSource for OrderByClause {
fn to_source(&self, buffer: &mut SourceBuffer) {
buffer.push("ORDER");
buffer.push("BY");
for (i, item) in self.items.iter().enumerate() {
if i > 0 {
buffer.push(",");
}
item.to_source(buffer);
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct OrderByItem {
pub expr: Expression,
pub direction: OrderDirection,
#[serde(with = "oak_core::serde_range")]
pub span: Range<usize>,
}
impl ToSource for OrderByItem {
fn to_source(&self, buffer: &mut SourceBuffer) {
self.expr.to_source(buffer);
self.direction.to_source(buffer);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OrderDirection {
Asc,
Desc,
}
impl ToSource for OrderDirection {
fn to_source(&self, buffer: &mut SourceBuffer) {
match self {
OrderDirection::Asc => buffer.push("ASC"),
OrderDirection::Desc => buffer.push("DESC"),
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LimitClause {
pub limit: Expression,
pub offset: Option<Expression>,
#[serde(with = "oak_core::serde_range")]
pub span: Range<usize>,
}
impl ToSource for LimitClause {
fn to_source(&self, buffer: &mut SourceBuffer) {
buffer.push("LIMIT");
self.limit.to_source(buffer);
if let Some(offset) = &self.offset {
buffer.push("OFFSET");
offset.to_source(buffer);
}
}
}