Added querybuilder

This commit is contained in:
2024-12-19 16:57:42 -05:00
parent 4a18af9014
commit 4840c7c001
4 changed files with 170 additions and 1 deletions

View File

@@ -30,3 +30,4 @@ axum = "0.7.7"
lazy_static = "1.5.0" lazy_static = "1.5.0"
futures = "0.3.31" futures = "0.3.31"
axum-login = "0.16.0" axum-login = "0.16.0"
sqlx-postgres = "0.8.2"

View File

@@ -1,4 +1,5 @@
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use crate::data::query::{Condition, QueryBuilder};
use crate::error::SirenResult; use crate::error::SirenResult;
const TABLE_NAME: &str = "guilds"; const TABLE_NAME: &str = "guilds";
@@ -36,7 +37,10 @@ impl GuildCache {
pub async fn get_by_id(id: i64) -> SirenResult<Option<Self>> { pub async fn get_by_id(id: i64) -> SirenResult<Option<Self>> {
let pool = crate::data::pool(); 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) .bind(id)
.fetch_optional(pool) .fetch_optional(pool)
.await?; .await?;

View File

@@ -7,6 +7,7 @@ use crate::error::SirenResult;
pub mod events; pub mod events;
pub mod guilds; pub mod guilds;
pub mod messages; pub mod messages;
mod query;
static POOL: OnceLock<Pool<Postgres>> = OnceLock::new(); static POOL: OnceLock<Pool<Postgres>> = OnceLock::new();
static REDIS: OnceLock<RedisClient> = OnceLock::new(); static REDIS: OnceLock<RedisClient> = OnceLock::new();

163
src/data/query.rs Normal file
View 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()),
}
}
}