use crate::errors::SqlBuilderError;
use core::fmt;
pub struct CreateTable {
table: String,
columns: Vec<Column>,
if_not_exists: bool,
}
impl CreateTable {
pub fn new<T: Into<String>>(table: T, columns: Vec<Column>) -> CreateTable {
CreateTable {
table: table.into(),
columns,
if_not_exists: false,
}
}
pub fn if_not_exists(mut self) -> Self {
self.if_not_exists = true;
self
}
pub fn build(&self) -> Result<String, SqlBuilderError> {
if self.table.is_empty() {
return Err(SqlBuilderError::EmptyTableName);
}
if self.columns.is_empty() {
return Err(SqlBuilderError::NoColumnsSpecified);
}
let mut statement = if self.if_not_exists {
format!("CREATE TABLE IF NOT EXISTS {} (", self.table)
} else {
format!("CREATE TABLE {} (", self.table)
};
let columns_sql: Result<Vec<String>, SqlBuilderError> =
self.columns.iter().map(|col| col.build()).collect();
statement.push_str(&columns_sql?.join(", "));
statement.push_str(");");
Ok(statement)
}
}
impl fmt::Display for CreateTable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.build() {
Err(e) => write!(f, "{}", e),
Ok(s) => write!(f, "{}", s),
}
}
}
#[derive(Debug)]
pub enum ColumnType {
Integer,
Text,
Real,
Boolean,
Blob,
Numeric,
Date,
Time,
Datetime,
}
impl fmt::Display for ColumnType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ColumnType::Integer => write!(f, "INTEGER"),
ColumnType::Text => write!(f, "TEXT"),
ColumnType::Real => write!(f, "REAL"),
ColumnType::Boolean => write!(f, "BOOLEAN"),
ColumnType::Blob => write!(f, "BLOB"),
ColumnType::Numeric => write!(f, "NUMERIC"),
ColumnType::Date => write!(f, "DATE"),
ColumnType::Time => write!(f, "TIME"),
ColumnType::Datetime => write!(f, "DATETIME"),
}
}
}
#[derive(Debug)]
pub enum ColumnOption {
NotNull,
Unique,
Default(String),
AutoIncrement,
PrimaryKey,
}
impl fmt::Display for ColumnOption {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ColumnOption::NotNull => write!(f, "NOT NULL"),
ColumnOption::Unique => write!(f, "UNIQUE"),
ColumnOption::Default(value) => write!(f, "DEFAULT {}", value),
ColumnOption::AutoIncrement => write!(f, "AUTOINCREMENT"),
ColumnOption::PrimaryKey => write!(f, "PRIMARY KEY"),
}
}
}
#[derive(Debug)]
pub struct Column {
name: String,
column_type: Option<ColumnType>,
options: Vec<ColumnOption>,
}
impl Column {
pub fn new(name: &str) -> Column {
Self {
name: name.to_string(),
column_type: None,
options: Vec::new(),
}
}
pub fn integer(mut self) -> Self {
self.column_type = Some(ColumnType::Integer);
self
}
pub fn text(mut self) -> Self {
self.column_type = Some(ColumnType::Text);
self
}
pub fn real(mut self) -> Self {
self.column_type = Some(ColumnType::Real);
self
}
pub fn boolean(mut self) -> Self {
self.column_type = Some(ColumnType::Boolean);
self
}
pub fn blob(mut self) -> Self {
self.column_type = Some(ColumnType::Blob);
self
}
pub fn numeric(mut self) -> Self {
self.column_type = Some(ColumnType::Numeric);
self
}
pub fn date(mut self) -> Self {
self.column_type = Some(ColumnType::Date);
self
}
pub fn time(mut self) -> Self {
self.column_type = Some(ColumnType::Time);
self
}
pub fn datetime(mut self) -> Self {
self.column_type = Some(ColumnType::Datetime);
self
}
pub fn not_null(mut self) -> Self {
self.options.push(ColumnOption::NotNull);
self
}
pub fn unique(mut self) -> Self {
self.options.push(ColumnOption::Unique);
self
}
pub fn default(mut self, value: &str) -> Self {
self.options.push(ColumnOption::Default(value.to_string()));
self
}
pub fn auto_increment(mut self) -> Self {
self.options.push(ColumnOption::AutoIncrement);
self
}
pub fn primary_key(mut self) -> Self {
self.options.push(ColumnOption::PrimaryKey);
self
}
pub fn build(&self) -> Result<String, SqlBuilderError> {
if self.name.is_empty() {
return Err(SqlBuilderError::EmptyColumnName);
}
let column_type_str = match &self.column_type {
Some(ct) => ct.to_string(),
None => return Err(SqlBuilderError::InvalidColumnType),
};
let options_str = self
.options
.iter()
.map(|opt| opt.to_string())
.collect::<Vec<String>>()
.join(" ");
Ok(format!("{} {} {}", self.name, column_type_str, options_str))
}
}
impl fmt::Display for Column {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.build() {
Err(e) => write!(f, "{}", e),
Ok(s) => write!(f, "{}", s),
}
}
}
pub struct Select {
table: String,
distinct: bool,
columns: Option<String>,
group: Option<String>,
order: Option<String>,
limit: Option<u32>,
offset: Option<u32>,
}
impl Select {
pub fn new<T: Into<String>>(table: T) -> Select {
Select {
table: table.into(),
distinct: false,
columns: None,
group: None,
order: None,
limit: None,
offset: None,
}
}
pub fn distinct(&mut self) -> &mut Self {
self.distinct = true;
self
}
pub fn columns<T: Into<String>>(&mut self, columns: T) -> &mut Self {
self.columns = Some(columns.into());
self
}
pub fn group<T: Into<String>>(&mut self, group: T) -> &mut Self {
self.group = Some(group.into());
self
}
pub fn order<T: Into<String>>(&mut self, order: T) -> &mut Self {
self.order = Some(order.into());
self
}
pub fn limit(&mut self, limit: u32) -> &mut Self {
self.limit = Some(limit);
self
}
pub fn offset(&mut self, offset: u32) -> &mut Self {
self.offset = Some(offset);
self
}
pub fn build(&self) -> Result<String, SqlBuilderError> {
if self.table.is_empty() {
return Err(SqlBuilderError::EmptyTableName);
}
let mut statement = String::from("SELECT");
if self.distinct {
statement.push_str(" DISTINCT");
}
if let Some(columns) = &self.columns {
statement.push_str(&format!(" {}", columns));
} else {
statement.push_str(" *");
}
statement.push_str(&format!(" FROM {}", self.table));
if let Some(group) = &self.group {
statement.push_str(&format!(" GROUP BY {}", group));
}
if let Some(order) = &self.order {
statement.push_str(&format!(" ORDER BY {}", order));
}
if let Some(limit) = &self.limit {
statement.push_str(&format!(" LIMIT {}", limit));
}
if let Some(offset) = &self.offset {
statement.push_str(&format!(" OFFSET {}", offset));
}
statement.push(';');
Ok(statement)
}
}
impl fmt::Display for Select {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.build() {
Err(e) => write!(f, "{}", e),
Ok(s) => write!(f, "{}", s),
}
}
}
pub struct Insert {
pub table: String,
pub values: Vec<(String, String)>,
}
impl Insert {
pub fn new<T: Into<String>>(table: T) -> Insert {
Insert {
table: table.into(),
values: Vec::new(),
}
}
pub fn values<T: ToString>(mut self, values: Vec<(&str, T)>) -> Self {
self.values = values
.into_iter()
.map(|(col, val)| (col.to_string(), val.to_string()))
.collect();
self
}
pub fn build(&self) -> Result<String, SqlBuilderError> {
if self.table.is_empty() {
return Err(SqlBuilderError::EmptyTableName);
}
if self.values.is_empty() {
return Err(SqlBuilderError::EmptyColumnAndValue);
}
let mut columns: Vec<String> = vec![];
let mut values: Vec<String> = vec![];
for (col, val) in &self.values {
if col.is_empty() {
return Err(SqlBuilderError::EmptyColumnName);
}
if val.is_empty() {
return Err(SqlBuilderError::EmptyValue);
}
columns.push(col.clone());
values.push(format!("'{}'", val.clone()));
}
Ok(format!(
"INSERT INTO {} ({}) VALUES ({});",
self.table,
columns.join(", "),
values.join(", ")
))
}
}
impl fmt::Display for Insert {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.build() {
Err(e) => write!(f, "{}", e),
Ok(s) => write!(f, "{}", s),
}
}
}