diff --git a/src/data/query.rs b/src/data/query.rs index 9278812..af0cc52 100644 --- a/src/data/query.rs +++ b/src/data/query.rs @@ -1,21 +1,24 @@ +use std::fmt::Write; use crate::data::condition::Condition; use crate::data::executable_query::ExecutableQuery; use crate::data::Value; -pub struct QueryBuilder { - table: String, - columns: Vec, +pub struct QueryBuilder<'a> { + table: &'a str, + columns: Vec<&'a str>, + distinct_on: Option>, condition: Option, order_by: Vec, limit: Option, offset: Option, } -impl QueryBuilder { - pub fn new(table: &str) -> Self { +impl<'a> QueryBuilder<'a> { + pub fn new(table: &'a str) -> Self { QueryBuilder { - table: table.to_string(), + table, columns: Vec::new(), + distinct_on: None, condition: None, order_by: Vec::new(), limit: None, @@ -23,8 +26,13 @@ impl QueryBuilder { } } - pub fn select(mut self, columns: &[&str]) -> Self { - self.columns = columns.iter().map(|s| s.to_string()).collect(); + pub fn select(mut self, columns: &[&'a str]) -> Self { + 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 } @@ -33,8 +41,11 @@ impl QueryBuilder { self } - pub fn order_by(mut self, column: &str, direction: &str) -> Self { - self.order_by.push(format!("{} {}", column, direction)); + pub fn order_by(mut self, column: &str, direction: Option) -> Self { + match direction { + Some(order) => self.order_by.push(format!("{} {}", column, order.to_string())), + None => self.order_by.push(column.to_string()), + } 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) { let columns = if self.columns.is_empty() { "*".to_string() @@ -52,7 +78,16 @@ impl ExecutableQuery for QueryBuilder { 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 = Vec::new(); if let Some(condition) = &self.condition { diff --git a/src/error.rs b/src/error.rs index 576c388..61ae7f7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,6 @@ use std::fmt; use axum::http::StatusCode; -use axum::{http, Json}; +use axum::Json; use axum::response::{IntoResponse, Response}; use serde::{Deserialize, Serialize}; diff --git a/src/main.rs b/src/main.rs index a03c5e5..990f67e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use std::env; use std::sync::Arc; -use dotenv::{dotenv, from_filename}; +use dotenv::from_filename; use serenity::http::Http; use serenity::prelude::*; use songbird::{SerenityInit, Songbird};