Added distinct_on to query builder

This commit is contained in:
2025-01-07 17:08:08 -05:00
parent 136600ee01
commit e7f337c735
3 changed files with 49 additions and 14 deletions

View File

@@ -1,21 +1,24 @@
use std::fmt::Write;
use crate::data::condition::Condition; use crate::data::condition::Condition;
use crate::data::executable_query::ExecutableQuery; use crate::data::executable_query::ExecutableQuery;
use crate::data::Value; use crate::data::Value;
pub struct QueryBuilder { pub struct QueryBuilder<'a> {
table: String, table: &'a str,
columns: Vec<String>, columns: Vec<&'a str>,
distinct_on: Option<Vec<String>>,
condition: Option<Condition>, condition: Option<Condition>,
order_by: Vec<String>, order_by: Vec<String>,
limit: Option<usize>, limit: Option<usize>,
offset: Option<usize>, offset: Option<usize>,
} }
impl QueryBuilder { impl<'a> QueryBuilder<'a> {
pub fn new(table: &str) -> Self { pub fn new(table: &'a str) -> Self {
QueryBuilder { QueryBuilder {
table: table.to_string(), table,
columns: Vec::new(), columns: Vec::new(),
distinct_on: None,
condition: None, condition: None,
order_by: Vec::new(), order_by: Vec::new(),
limit: None, limit: None,
@@ -23,8 +26,13 @@ impl QueryBuilder {
} }
} }
pub fn select(mut self, columns: &[&str]) -> Self { pub fn select(mut self, columns: &[&'a str]) -> Self {
self.columns = columns.iter().map(|s| s.to_string()).collect(); self.columns.extend(columns);
self
}
pub fn distinct_on(mut self, columns: &[&str]) -> Self {
self.distinct_on = Some(columns.iter().map(|s| s.to_string()).collect());
self self
} }
@@ -33,8 +41,11 @@ impl QueryBuilder {
self self
} }
pub fn order_by(mut self, column: &str, direction: &str) -> Self { pub fn order_by(mut self, column: &str, direction: Option<OrderDirection>) -> Self {
self.order_by.push(format!("{} {}", column, direction)); match direction {
Some(order) => self.order_by.push(format!("{} {}", column, order.to_string())),
None => self.order_by.push(column.to_string()),
}
self self
} }
@@ -44,7 +55,22 @@ impl QueryBuilder {
} }
} }
impl ExecutableQuery for QueryBuilder { pub enum OrderDirection {
Asc,
Desc
}
impl std::fmt::Display for OrderDirection {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let direction_str = match self {
OrderDirection::Asc => "ASC",
OrderDirection::Desc => "DESC",
};
write!(f, "{}", direction_str)
}
}
impl<'a> ExecutableQuery for QueryBuilder<'a> {
fn build(&self) -> (String, Vec<Value>) { fn build(&self) -> (String, Vec<Value>) {
let columns = if self.columns.is_empty() { let columns = if self.columns.is_empty() {
"*".to_string() "*".to_string()
@@ -52,7 +78,16 @@ impl ExecutableQuery for QueryBuilder {
self.columns.join(",") self.columns.join(",")
}; };
let mut query = format!("SELECT {} FROM {}", columns, self.table); let mut query = String::new();
if let Some(distinct_columns) = &self.distinct_on {
let distinct_on_clause = distinct_columns.join(",");
query = format!("SELECT DISTINCT ON ({}) {}", distinct_on_clause, columns);
} else {
query = format!("SELECT {}", columns);
}
query.push_str(format!(" FROM {}", self.table).as_str());
let mut values: Vec<Value> = Vec::new(); let mut values: Vec<Value> = Vec::new();
if let Some(condition) = &self.condition { if let Some(condition) = &self.condition {

View File

@@ -1,6 +1,6 @@
use std::fmt; use std::fmt;
use axum::http::StatusCode; use axum::http::StatusCode;
use axum::{http, Json}; use axum::Json;
use axum::response::{IntoResponse, Response}; use axum::response::{IntoResponse, Response};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@@ -1,7 +1,7 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::env; use std::env;
use std::sync::Arc; use std::sync::Arc;
use dotenv::{dotenv, from_filename}; use dotenv::from_filename;
use serenity::http::Http; use serenity::http::Http;
use serenity::prelude::*; use serenity::prelude::*;
use songbird::{SerenityInit, Songbird}; use songbird::{SerenityInit, Songbird};