use crate::ast::{
expr::{Expression, Identifier, TableName},
statements::query::SelectStatement,
};
use core::range::Range;
use oak_core::source::{SourceBuffer, ToSource};
use std::sync::Arc;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CreateStatement {
pub object_type: CreateObjectType,
pub name: Identifier,
pub if_not_exists: bool,
pub body: CreateBody,
#[serde(with = "oak_core::serde_range")]
pub span: Range<usize>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CreateBody {
Table {
columns: Vec<ColumnDefinition>,
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
View {
query: Box<SelectStatement>,
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
Index {
table_name: TableName,
columns: Vec<Identifier>,
unique: bool,
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
Database {
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
}
impl ToSource for CreateStatement {
fn to_source(&self, buffer: &mut SourceBuffer) {
buffer.push("CREATE");
if let CreateBody::Index { unique: true, .. } = &self.body {
buffer.push("UNIQUE");
}
self.object_type.to_source(buffer);
if self.if_not_exists {
buffer.push("IF");
buffer.push("NOT");
buffer.push("EXISTS");
}
self.name.to_source(buffer);
match &self.body {
CreateBody::Table { columns, .. } => {
if !columns.is_empty() {
buffer.push("(");
for (i, col) in columns.iter().enumerate() {
if i > 0 {
buffer.push(",");
}
col.to_source(buffer);
}
buffer.push(")");
}
}
CreateBody::View { query, .. } => {
buffer.push("AS");
query.to_source(buffer);
}
CreateBody::Index { table_name, columns, .. } => {
buffer.push("ON");
table_name.to_source(buffer);
buffer.push("(");
for (i, col) in columns.iter().enumerate() {
if i > 0 {
buffer.push(",");
}
col.to_source(buffer);
}
buffer.push(")");
}
CreateBody::Database { .. } => {}
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ColumnDefinition {
pub name: Identifier,
pub data_type: Arc<str>,
pub constraints: Vec<ColumnConstraint>,
#[serde(with = "oak_core::serde_range")]
pub span: Range<usize>,
}
impl ToSource for ColumnDefinition {
fn to_source(&self, buffer: &mut SourceBuffer) {
self.name.to_source(buffer);
buffer.push(&self.data_type);
for constraint in &self.constraints {
constraint.to_source(buffer);
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ColumnConstraint {
PrimaryKey {
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
NotNull {
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
Nullable {
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
Unique {
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
Default(Expression, #[serde(with = "oak_core::serde_range")] Range<usize>),
Check(Expression, #[serde(with = "oak_core::serde_range")] Range<usize>),
AutoIncrement {
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
}
impl ToSource for ColumnConstraint {
fn to_source(&self, buffer: &mut SourceBuffer) {
match self {
ColumnConstraint::PrimaryKey { .. } => {
buffer.push("PRIMARY");
buffer.push("KEY");
}
ColumnConstraint::NotNull { .. } => {
buffer.push("NOT");
buffer.push("NULL");
}
ColumnConstraint::Nullable { .. } => buffer.push("NULL"),
ColumnConstraint::Unique { .. } => buffer.push("UNIQUE"),
ColumnConstraint::Default(expr, _) => {
buffer.push("DEFAULT");
expr.to_source(buffer);
}
ColumnConstraint::Check(expr, _) => {
buffer.push("CHECK");
buffer.push("(");
expr.to_source(buffer);
buffer.push(")");
}
ColumnConstraint::AutoIncrement { .. } => buffer.push("AUTOINCREMENT"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CreateObjectType {
Table,
View,
Index,
Database,
}
impl ToSource for CreateObjectType {
fn to_source(&self, buffer: &mut SourceBuffer) {
match self {
CreateObjectType::Table => buffer.push("TABLE"),
CreateObjectType::View => buffer.push("VIEW"),
CreateObjectType::Index => buffer.push("INDEX"),
CreateObjectType::Database => buffer.push("DATABASE"),
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DropStatement {
pub object_type: DropObjectType,
pub name: Identifier,
pub if_exists: bool,
#[serde(with = "oak_core::serde_range")]
pub span: Range<usize>,
}
impl ToSource for DropStatement {
fn to_source(&self, buffer: &mut SourceBuffer) {
buffer.push("DROP");
self.object_type.to_source(buffer);
if self.if_exists {
buffer.push("IF");
buffer.push("EXISTS");
}
self.name.to_source(buffer);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DropObjectType {
Table,
View,
Index,
Database,
}
impl ToSource for DropObjectType {
fn to_source(&self, buffer: &mut SourceBuffer) {
match self {
DropObjectType::Table => buffer.push("TABLE"),
DropObjectType::View => buffer.push("VIEW"),
DropObjectType::Index => buffer.push("INDEX"),
DropObjectType::Database => buffer.push("DATABASE"),
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AlterStatement {
pub table_name: TableName,
pub action: Option<AlterAction>,
#[serde(with = "oak_core::serde_range")]
pub span: Range<usize>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AlterAction {
AddColumn {
name: Identifier,
data_type: Option<Arc<str>>,
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
DropColumn {
name: Identifier,
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
RenameTo {
new_name: Identifier,
#[serde(with = "oak_core::serde_range")]
span: Range<usize>,
},
}
impl ToSource for AlterStatement {
fn to_source(&self, buffer: &mut SourceBuffer) {
buffer.push("ALTER");
buffer.push("TABLE");
self.table_name.to_source(buffer);
if let Some(action) = &self.action {
match action {
AlterAction::AddColumn { name, data_type, .. } => {
buffer.push("ADD");
buffer.push("COLUMN");
name.to_source(buffer);
if let Some(dt) = data_type {
buffer.push(dt);
}
}
AlterAction::DropColumn { name, .. } => {
buffer.push("DROP");
buffer.push("COLUMN");
name.to_source(buffer);
}
AlterAction::RenameTo { new_name, .. } => {
buffer.push("RENAME");
buffer.push("TO");
new_name.to_source(buffer);
}
}
}
}
}