Added querybuilder
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::data::query::{Condition, QueryBuilder};
|
||||
use crate::error::SirenResult;
|
||||
|
||||
const TABLE_NAME: &str = "guilds";
|
||||
@@ -36,7 +37,10 @@ impl GuildCache {
|
||||
|
||||
pub async fn get_by_id(id: i64) -> SirenResult<Option<Self>> {
|
||||
let pool = crate::data::pool();
|
||||
let item = sqlx::query_as::<_, Self>(&format!("SELECT * FROM {} WHERE id = $1", TABLE_NAME))
|
||||
let query = QueryBuilder::new(TABLE_NAME)
|
||||
.where_condition(Condition::is_equal("id", "$1")) // Use a placeholder
|
||||
.build();
|
||||
let item = sqlx::query_as(&query)
|
||||
.bind(id)
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::error::SirenResult;
|
||||
pub mod events;
|
||||
pub mod guilds;
|
||||
pub mod messages;
|
||||
mod query;
|
||||
|
||||
static POOL: OnceLock<Pool<Postgres>> = OnceLock::new();
|
||||
static REDIS: OnceLock<RedisClient> = OnceLock::new();
|
||||
|
||||
163
src/data/query.rs
Normal file
163
src/data/query.rs
Normal file
@@ -0,0 +1,163 @@
|
||||
pub struct QueryBuilder {
|
||||
table: String,
|
||||
columns: Vec<String>,
|
||||
condition: Option<Condition>,
|
||||
order_by: Vec<String>,
|
||||
limit: Option<usize>,
|
||||
}
|
||||
|
||||
impl QueryBuilder {
|
||||
pub fn new(table: &str) -> Self {
|
||||
QueryBuilder {
|
||||
table: table.to_string(),
|
||||
columns: Vec::new(),
|
||||
condition: None,
|
||||
order_by: Vec::new(),
|
||||
limit: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select(mut self, columns: &[&str]) -> Self {
|
||||
self.columns = columns.iter().map(|s| s.to_string()).collect();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn where_condition(mut self, condition: Condition) -> Self {
|
||||
self.condition = Some(condition);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn order_by(mut self, column: &str, direction: &str) -> Self {
|
||||
self.order_by.push(format!("{} {}", column, direction));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn limit(mut self, limit: usize) -> Self {
|
||||
self.limit = Some(limit);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> String {
|
||||
let columns = if self.columns.is_empty() {
|
||||
"*".to_string()
|
||||
} else {
|
||||
self.columns.join(",")
|
||||
};
|
||||
|
||||
let mut query = format!("SELECT {} FROM {}", columns, self.table);
|
||||
|
||||
if let Some(condition) = self.condition {
|
||||
query.push_str(&format!(" WHERE {}", condition.to_sql()));
|
||||
}
|
||||
|
||||
if !self.order_by.is_empty() {
|
||||
query.push_str(&format!(" ORDER BY {}", self.order_by.join(" ORDER BY")));
|
||||
}
|
||||
|
||||
if let Some(limit) = self.limit {
|
||||
query.push_str(&format!(" LIMIT {}", limit));
|
||||
}
|
||||
|
||||
query
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Condition {
|
||||
Simple(String),
|
||||
And(Box<Condition>, Box<Condition>),
|
||||
Or(Box<Condition>, Box<Condition>),
|
||||
Group(Box<Condition>),
|
||||
}
|
||||
|
||||
impl Condition {
|
||||
pub fn new(condition: &str) -> Self {
|
||||
Condition::Simple(condition.to_string())
|
||||
}
|
||||
|
||||
pub fn and(self, other: Self) -> Self {
|
||||
Condition::And(Box::new(self), Box::new(other))
|
||||
}
|
||||
|
||||
pub fn or(self, other: Self) -> Self {
|
||||
Condition::Or(Box::new(self), Box::new(other))
|
||||
}
|
||||
|
||||
pub fn group(self) -> Self {
|
||||
Condition::Group(Box::new(self))
|
||||
}
|
||||
|
||||
pub fn is_equal(left: &str, right: &str) -> Self {
|
||||
Condition::Simple(format!("{} = {}", left, right))
|
||||
}
|
||||
|
||||
pub fn not_equal(left: &str, right: &str) -> Self {
|
||||
Condition::Simple(format!("{} != {}", left, right))
|
||||
}
|
||||
|
||||
pub fn is_null(value: &str) -> Self {
|
||||
Condition::Simple(format!("{} IS NULL", value))
|
||||
}
|
||||
|
||||
pub fn not_null(value: &str) -> Self {
|
||||
Condition::Simple(format!("{} IS NOT NULL", value))
|
||||
}
|
||||
|
||||
pub fn is_in(left: &str, right: &[&str]) -> Self {
|
||||
let right_list = right
|
||||
.iter()
|
||||
.map(|v| format!("'{}'", v))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
Condition::Simple(format!("{} IN ({})", left, right_list))
|
||||
}
|
||||
|
||||
pub fn not_in(left: &str, right: &[&str]) -> Self {
|
||||
let right_list = right
|
||||
.iter()
|
||||
.map(|v| format!("'{}'", v))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
Condition::Simple(format!("{} NOT IN ({})", left, right_list))
|
||||
}
|
||||
|
||||
pub fn like(left: &str, right: &str) -> Self {
|
||||
Condition::Simple(format!("{} LIKE '{}'", left, right))
|
||||
}
|
||||
|
||||
pub fn not_like(left: &str, right: &str) -> Self {
|
||||
Condition::Simple(format!("{} NOT LIKE '{}'", left, right))
|
||||
}
|
||||
|
||||
pub fn i_like(left: &str, right: &str) -> Self {
|
||||
Condition::Simple(format!("{} ILIKE '{}'", left, right))
|
||||
}
|
||||
|
||||
pub fn not_i_like(left: &str, right: &str) -> Self {
|
||||
Condition::Simple(format!("{} NOT ILIKE '{}'", left, right))
|
||||
}
|
||||
|
||||
pub fn gt(left: &str, right: &str) -> Self {
|
||||
Condition::Simple(format!("{} > {}", left, right))
|
||||
}
|
||||
|
||||
pub fn gte(left: &str, right: &str) -> Self {
|
||||
Condition::Simple(format!("{} >= {}", left, right))
|
||||
}
|
||||
|
||||
pub fn lt(left: &str, right: &str) -> Self {
|
||||
Condition::Simple(format!("{} < {}", left, right))
|
||||
}
|
||||
|
||||
pub fn lte(left: &str, right: &str) -> Self {
|
||||
Condition::Simple(format!("{} <= {}", left, right))
|
||||
}
|
||||
|
||||
fn to_sql(&self) -> String {
|
||||
match self {
|
||||
Condition::Simple(s) => s.to_string(),
|
||||
Condition::And(a, b) => format!("{} AND {}", a.to_sql(), b.to_sql()),
|
||||
Condition::Or(a, b) => format!("{} OR {}", a.to_sql(), b.to_sql()),
|
||||
Condition::Group(a) => format!("({})", a.to_sql()),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user