use std::marker::PhantomData;
pub struct Select;
pub struct From;
pub struct Where;
pub struct Join;
pub struct Limit;
pub struct Table;
pub struct Insert;
pub struct InsertColumns;
pub struct Set;
pub struct Orm<State = Select> {
query: String,
state: PhantomData<State>,
has_where_clause: bool,
}
impl Orm {
pub fn select(columns: &str) -> Orm<From> {
Orm {
query: format!("SELECT {}", columns),
has_where_clause: false,
state: PhantomData,
}
}
pub fn select_single(columns: &str) -> String {
format!("SELECT {};", columns)
}
pub fn insert_or_ignore(table: &str) -> Orm<InsertColumns> {
Orm {
query: format!("INSERT OR IGNORE INTO {table}"),
has_where_clause: false,
state: PhantomData,
}
}
pub fn insert(table: &str) -> Orm<InsertColumns> {
Orm {
query: format!("INSERT INTO {table}"),
has_where_clause: false,
state: PhantomData,
}
}
pub fn delete(columns: &str) -> Orm<Where> {
Orm {
query: format!("DELETE {}", columns),
has_where_clause: false,
state: PhantomData,
}
}
pub fn update(columns: &str) -> Orm<Set> {
Orm {
query: format!("UPDATE {}", columns),
has_where_clause: false,
state: PhantomData,
}
}
}
impl Orm<Set> {
pub fn set(self, values: &str) -> Orm<Where> {
Orm {
query: format!("{} {values}", self.query),
has_where_clause: false,
state: PhantomData,
}
}
}
#[allow(clippy::single_char_add_str)]
impl<State> Orm<State> {
pub fn ready(&mut self) -> String {
if self.query.ends_with(',') {
self.query.pop();
}
self.query.push_str(";");
self.query.clone()
}
pub fn as_(self, short: &str) -> Orm<State> {
Orm {
query: format!("{} AS {}", self.query, short),
has_where_clause: self.has_where_clause,
state: PhantomData,
}
}
pub fn and(self) -> Orm<State> {
Orm {
query: format!("{} AND", self.query),
has_where_clause: self.has_where_clause,
state: PhantomData,
}
}
pub fn where_(&mut self) -> Orm<Where> {
Orm {
query: format!("{} WHERE", self.query),
has_where_clause: false,
state: PhantomData,
}
}
}
impl Orm<InsertColumns> {
pub fn set_columns(self, columns: &str) -> Orm<Insert> {
Orm {
query: format!("{} ({columns}) VALUES", self.query),
has_where_clause: false,
state: PhantomData,
}
}
}
impl Orm<Insert> {
pub fn add_value(self, values: &str) -> Orm<Insert> {
Orm {
query: format!("{} ({values}),", self.query),
has_where_clause: false,
state: PhantomData,
}
}
pub fn add_many(self, values: &str) -> Orm<Insert> {
Orm {
query: format!("{} {values}", self.query),
has_where_clause: false,
state: PhantomData,
}
}
}
impl Orm<Table> {
pub fn drop_table(self, table: &str) -> Orm<Table> {
Orm {
query: format!("DROP TABLE {table}"),
has_where_clause: false,
state: PhantomData,
}
}
pub fn truncate_table(self, table: &str) -> Orm<Table> {
Orm {
query: format!("TRUNCATE TABLE {table}"),
has_where_clause: false,
state: PhantomData,
}
}
pub fn alter_table(self, table: &str) -> Orm<Table> {
Orm {
query: format!("ALTER TABLE {table}"),
has_where_clause: false,
state: PhantomData,
}
}
pub fn add(self, column: &str, data_type: &str) -> Orm<Table> {
Orm {
query: format!("{} ADD {column} {data_type}", self.query),
has_where_clause: self.has_where_clause,
state: PhantomData,
}
}
}
impl Orm<From> {
pub fn from(self, table: &str) -> Orm<From> {
Orm {
query: format!("{} FROM {}", self.query, table),
has_where_clause: self.has_where_clause,
state: PhantomData,
}
}
pub fn from_subquery(self, subquery: &str) -> Orm<From> {
Orm {
query: format!("{} FROM {}", self.query, subquery),
has_where_clause: self.has_where_clause,
state: PhantomData,
}
}
pub fn join(self, table: &str) -> Orm<Join> {
Orm {
query: format!("{} JOIN {}", self.query, table),
has_where_clause: self.has_where_clause,
state: PhantomData,
}
}
}
impl Orm<Join> {
pub fn join(self, table: &str) -> Orm<Join> {
Orm {
query: format!("{} JOIN {}", self.query, table),
has_where_clause: self.has_where_clause,
state: PhantomData,
}
}
pub fn left_join(self, table: &str) -> Orm<Join> {
Orm {
query: format!("{} LEFT JOIN {}", self.query, table),
has_where_clause: self.has_where_clause,
state: PhantomData,
}
}
pub fn on(self, on_clause: &str) -> Orm<Join> {
Orm {
query: format!("{} ON {}", self.query, on_clause),
has_where_clause: self.has_where_clause,
state: PhantomData,
}
}
}
impl Orm<Where> {
pub fn equal(&mut self, column: &str, value: &str) -> &mut Self {
self.and_for_where();
self.query
.push_str(&format!(" {} = {}", column, Self::correct_value(value)));
self
}
pub fn not_equal(&mut self, column: &str, value: &str) -> &mut Self {
self.and_for_where();
self.query
.push_str(&format!(" {} != {}", column, Self::correct_value(value)));
self
}
pub fn less_than(&mut self, column: &str, value: &str) -> &mut Self {
self.and_for_where();
self.query
.push_str(&format!("{} < {}", column, Self::correct_value(value)));
self
}
pub fn greater_than(&mut self, column: &str, value: &str) -> &mut Self {
self.and_for_where();
self.query
.push_str(&format!("{} > {}", column, Self::correct_value(value)));
self
}
pub fn less_than_or_equal(&mut self, column: &str, value: &str) -> &mut Self {
self.and_for_where();
self.query
.push_str(&format!("{} <= {}", column, Self::correct_value(value)));
self
}
pub fn greater_than_or_equal(&mut self, column: &str, value: &str) -> &mut Self {
self.and_for_where();
self.query
.push_str(&format!("{} >= {}", column, Self::correct_value(value)));
self
}
pub fn like(&mut self, column: &str, pattern: &str) -> &mut Self {
self.and_for_where();
self.query.push_str(&format!("{} LIKE {}", column, pattern));
self
}
pub fn not_like(&mut self, column: &str, pattern: &str) -> &mut Self {
self.and_for_where();
self.query
.push_str(&format!("{} NOT LIKE {}", column, pattern));
self
}
pub fn in_values(&mut self, column: &str, values: &[&str]) -> &mut Self {
self.and_for_where();
let value_list = values
.iter()
.map(|value| Self::correct_value(value).to_string())
.collect::<Vec<String>>()
.join(", ");
self.query
.push_str(&format!("{} IN ({})", column, value_list));
self
}
pub fn not_in_values(&mut self, column: &str, values: &[&str]) -> &mut Self {
self.and_for_where();
let value_list = values
.iter()
.map(|value| Self::correct_value(value).to_string())
.collect::<Vec<String>>()
.join(", ");
self.query
.push_str(&format!("{} NOT IN ({})", column, value_list));
self
}
pub fn and_for_where(&mut self) -> &mut Self {
if self.has_where_clause {
self.query.push_str(" AND ");
} else {
self.has_where_clause = true;
}
self
}
fn correct_value(value: &str) -> String {
if value.parse::<f64>().is_ok() || value.parse::<i64>().is_ok() {
return value.to_string();
}
format!("'{}'", value.to_owned())
}
}
impl Orm<Limit> {
pub fn limit(&mut self, limit: u32) -> Orm<Limit> {
Orm {
query: format!("{} LIMIT {}", self.query, limit),
has_where_clause: self.has_where_clause,
state: PhantomData,
}
}
}