use std::fmt::Debug;
use crate::{
bounds::{FieldIdentifier, FieldValueIdentifier, QueryParameter},
crud::{CrudOperations, Transaction},
mapper::RowMapper,
query_elements::query::Query,
Operator,
};
pub mod ops {
pub use super::*;
pub trait QueryBuilder<'a, T>
where
T: Debug + CrudOperations<T> + Transaction<T> + RowMapper<T>,
{
fn read_sql(&'a self) -> &'a str;
fn push_sql(&mut self, sql: &str);
fn r#where<Z: FieldValueIdentifier<'a, T>>(
&mut self,
column: Z,
op: impl Operator,
) -> &mut Self
where
T: Debug + CrudOperations<T> + Transaction<T> + RowMapper<T>;
fn and<Z: FieldValueIdentifier<'a, T>>(
&mut self,
column: Z,
op: impl Operator,
) -> &mut Self;
fn and_values_in<Z, Q>(&mut self, column: Z, values: &'a [Q]) -> &mut Self
where
Z: FieldIdentifier<T>,
Q: QueryParameter<'a>;
fn or_values_in<Z, Q>(&mut self, r#or: Z, values: &'a [Q]) -> &mut Self
where
Z: FieldIdentifier<T>,
Q: QueryParameter<'a>;
fn or<Z: FieldValueIdentifier<'a, T>>(&mut self, column: Z, op: impl Operator)
-> &mut Self;
fn order_by<Z: FieldIdentifier<T>>(&mut self, order_by: Z, desc: bool) -> &mut Self;
}
}
#[derive(Debug, Clone)]
pub struct QueryBuilder<'a, T>
where
T: CrudOperations<T> + Transaction<T> + RowMapper<T>,
{
query: Query<'a, T>,
datasource_name: &'a str,
}
unsafe impl<'a, T> Send for QueryBuilder<'a, T> where
T: CrudOperations<T> + Transaction<T> + RowMapper<T>
{
}
unsafe impl<'a, T> Sync for QueryBuilder<'a, T> where
T: CrudOperations<T> + Transaction<T> + RowMapper<T>
{
}
impl<'a, T> QueryBuilder<'a, T>
where
T: CrudOperations<T> + Transaction<T> + RowMapper<T>,
{
pub fn new(query: Query<'a, T>, datasource_name: &'a str) -> Self {
Self {
query,
datasource_name,
}
}
#[allow(clippy::question_mark)]
pub async fn query(
&'a mut self,
) -> Result<Vec<T>, Box<(dyn std::error::Error + Sync + Send + 'static)>> {
self.query.sql.push(';');
let result = T::query(
self.query.sql.clone(),
self.query.params.to_vec(),
self.datasource_name,
)
.await;
if let Err(error) = result {
Err(error)
} else {
Ok(result.ok().unwrap().get_entities::<T>())
}
}
pub fn r#where<Z: FieldValueIdentifier<'a, T>>(&mut self, r#where: Z, op: impl Operator) {
let (column_name, value) = r#where.value();
let where_ = String::from(" WHERE ")
+ column_name
+ op.as_str()
+ "$"
+ &(self.query.params.len() + 1).to_string();
self.query.sql.push_str(&where_);
self.query.params.push(value);
}
pub fn and<Z: FieldValueIdentifier<'a, T>>(&mut self, r#and: Z, op: impl Operator) {
let (column_name, value) = r#and.value();
let and_ = String::from(" AND ")
+ column_name
+ op.as_str()
+ "$"
+ &(self.query.params.len() + 1).to_string()
+ " ";
self.query.sql.push_str(&and_);
self.query.params.push(value);
}
pub fn or<Z: FieldValueIdentifier<'a, T>>(&mut self, r#and: Z, op: impl Operator) {
let (column_name, value) = r#and.value();
let and_ = String::from(" OR ")
+ column_name
+ op.as_str()
+ "$"
+ &(self.query.params.len() + 1).to_string()
+ " ";
self.query.sql.push_str(&and_);
self.query.params.push(value);
}
pub fn and_values_in<Z, Q>(&mut self, r#and: Z, values: &'a [Q])
where
Z: FieldIdentifier<T>,
Q: QueryParameter<'a>,
{
if values.is_empty() {
return;
}
self.query
.sql
.push_str(&format!(" AND {} IN (", r#and.as_str()));
let mut counter = 1;
values.iter().for_each(|qp| {
if values.len() != counter {
self.query
.sql
.push_str(&format!("${}, ", self.query.params.len()));
counter += 1;
} else {
self.query
.sql
.push_str(&format!("${}", self.query.params.len()));
}
self.query.params.push(qp)
});
self.query.sql.push_str(") ");
}
fn or_values_in<Z, Q>(&mut self, r#or: Z, values: &'a [Q])
where
Z: FieldIdentifier<T>,
Q: QueryParameter<'a>,
{
if values.is_empty() {
return;
}
self.query
.sql
.push_str(&format!(" OR {} IN (", r#or.as_str()));
let mut counter = 1;
values.iter().for_each(|qp| {
if values.len() != counter {
self.query
.sql
.push_str(&format!("${}, ", self.query.params.len()));
counter += 1;
} else {
self.query
.sql
.push_str(&format!("${}", self.query.params.len()));
}
self.query.params.push(qp)
});
self.query.sql.push_str(") ");
}
#[inline]
pub fn order_by<Z: FieldIdentifier<T>>(&mut self, order_by: Z, desc: bool) {
self.query.sql.push_str(
&(format!(
" ORDER BY {}{}",
order_by.as_str(),
if desc { " DESC " } else { "" }
)),
);
}
}
#[derive(Debug, Clone)]
pub struct SelectQueryBuilder<'a, T>
where
T: CrudOperations<T> + Transaction<T> + RowMapper<T>,
{
_inner: QueryBuilder<'a, T>,
}
impl<'a, T> SelectQueryBuilder<'a, T>
where
T: CrudOperations<T> + Transaction<T> + RowMapper<T>,
{
pub fn new(table_schema_data: &str, datasource_name: &'a str) -> Self {
Self {
_inner: QueryBuilder::<T>::new(
Query::new(format!("SELECT * FROM {table_schema_data}")),
datasource_name,
),
}
}
#[inline]
pub async fn query(
&'a mut self,
) -> Result<Vec<T>, Box<(dyn std::error::Error + Sync + Send + 'static)>> {
self._inner.query().await
}
pub fn left_join(&mut self, join_table: &str, col1: &str, col2: &str) -> &mut Self {
self._inner
.query
.sql
.push_str(&format!(" LEFT JOIN {join_table} ON {col1} = {col2}"));
self
}
pub fn inner_join(&mut self, join_table: &str, col1: &str, col2: &str) -> &mut Self {
self._inner
.query
.sql
.push_str(&format!(" INNER JOIN {join_table} ON {col1} = {col2}"));
self
}
pub fn right_join(&mut self, join_table: &str, col1: &str, col2: &str) -> &mut Self {
self._inner
.query
.sql
.push_str(&format!(" RIGHT JOIN {join_table} ON {col1} = {col2}"));
self
}
pub fn full_join(&mut self, join_table: &str, col1: &str, col2: &str) -> &mut Self {
self._inner
.query
.sql
.push_str(&format!(" FULL JOIN {join_table} ON {col1} = {col2}"));
self
}
}
impl<'a, T> ops::QueryBuilder<'a, T> for SelectQueryBuilder<'a, T>
where
T: Debug + CrudOperations<T> + Transaction<T> + RowMapper<T> + Send,
{
#[inline]
fn read_sql(&'a self) -> &'a str {
self._inner.query.sql.as_str()
}
#[inline(always)]
fn push_sql(&mut self, sql: &str) {
self._inner.query.sql.push_str(sql);
}
#[inline]
fn r#where<Z: FieldValueIdentifier<'a, T>>(
&mut self,
r#where: Z,
op: impl Operator,
) -> &mut Self {
self._inner.r#where(r#where, op);
self
}
#[inline]
fn and<Z: FieldValueIdentifier<'a, T>>(&mut self, column: Z, op: impl Operator) -> &mut Self {
self._inner.and(column, op);
self
}
#[inline]
fn and_values_in<Z, Q>(&mut self, r#and: Z, values: &'a [Q]) -> &mut Self
where
Z: FieldIdentifier<T>,
Q: QueryParameter<'a>,
{
self._inner.and_values_in(and, values);
self
}
#[inline]
fn or<Z: FieldValueIdentifier<'a, T>>(&mut self, column: Z, op: impl Operator) -> &mut Self {
self._inner.or(column, op);
self
}
#[inline]
fn or_values_in<Z, Q>(&mut self, r#and: Z, values: &'a [Q]) -> &mut Self
where
Z: FieldIdentifier<T>,
Q: QueryParameter<'a>,
{
self._inner.or_values_in(and, values);
self
}
#[inline]
fn order_by<Z: FieldIdentifier<T>>(&mut self, order_by: Z, desc: bool) -> &mut Self {
self._inner.order_by(order_by, desc);
self
}
}
#[derive(Debug, Clone)]
pub struct UpdateQueryBuilder<'a, T>
where
T: CrudOperations<T> + Transaction<T> + RowMapper<T>,
{
_inner: QueryBuilder<'a, T>,
}
impl<'a, T> UpdateQueryBuilder<'a, T>
where
T: CrudOperations<T> + Transaction<T> + RowMapper<T>,
{
pub fn new(table_schema_data: &str, datasource_name: &'a str) -> Self {
Self {
_inner: QueryBuilder::<T>::new(
Query::new(format!("UPDATE {table_schema_data}")),
datasource_name,
),
}
}
#[inline]
pub async fn query(
&'a mut self,
) -> Result<Vec<T>, Box<(dyn std::error::Error + Sync + Send + 'static)>> {
self._inner.query().await
}
pub fn set<Z, Q>(&mut self, columns: &'a [(Z, Q)]) -> &mut Self
where
Z: FieldIdentifier<T> + Clone,
Q: QueryParameter<'a>,
{
if columns.is_empty() {
return self;
}
if self._inner.query.sql.contains("SET") {
panic!(
"\n{}",
String::from("\t[PANIC!] - Don't use chained calls of the .set(...) method. ")
+ "\n\tPass all the values in a unique call within the 'columns' "
+ "array of tuples parameter\n"
)
}
let cap = columns.len() * 50; let mut set_clause = String::with_capacity(cap);
set_clause.push_str(" SET ");
for (idx, column) in columns.iter().enumerate() {
set_clause.push_str(&format!(
"{} = ${}",
column.0.as_str(),
self._inner.query.params.len() + 1
));
if idx < columns.len() - 1 {
set_clause.push_str(", ");
}
self._inner.query.params.push(&column.1);
}
self._inner.query.sql.push_str(&set_clause);
self
}
}
impl<'a, T> ops::QueryBuilder<'a, T> for UpdateQueryBuilder<'a, T>
where
T: Debug + CrudOperations<T> + Transaction<T> + RowMapper<T> + Send,
{
#[inline]
fn read_sql(&'a self) -> &'a str {
self._inner.query.sql.as_str()
}
#[inline(always)]
fn push_sql(&mut self, sql: &str) {
self._inner.query.sql.push_str(sql);
}
#[inline]
fn r#where<Z: FieldValueIdentifier<'a, T>>(
&mut self,
r#where: Z,
op: impl Operator,
) -> &mut Self {
self._inner.r#where(r#where, op);
self
}
#[inline]
fn and<Z: FieldValueIdentifier<'a, T>>(&mut self, column: Z, op: impl Operator) -> &mut Self {
self._inner.and(column, op);
self
}
#[inline]
fn and_values_in<Z, Q>(&mut self, r#and: Z, values: &'a [Q]) -> &mut Self
where
Z: FieldIdentifier<T>,
Q: QueryParameter<'a>,
{
self._inner.and_values_in(and, values);
self
}
#[inline]
fn or<Z: FieldValueIdentifier<'a, T>>(&mut self, column: Z, op: impl Operator) -> &mut Self {
self._inner.or(column, op);
self
}
#[inline]
fn or_values_in<Z, Q>(&mut self, r#or: Z, values: &'a [Q]) -> &mut Self
where
Z: FieldIdentifier<T>,
Q: QueryParameter<'a>,
{
self._inner.or_values_in(or, values);
self
}
#[inline]
fn order_by<Z: FieldIdentifier<T>>(&mut self, order_by: Z, desc: bool) -> &mut Self {
self._inner.order_by(order_by, desc);
self
}
}
#[derive(Debug, Clone)]
pub struct DeleteQueryBuilder<'a, T>
where
T: CrudOperations<T> + Transaction<T> + RowMapper<T>,
{
_inner: QueryBuilder<'a, T>,
}
impl<'a, T> DeleteQueryBuilder<'a, T>
where
T: CrudOperations<T> + Transaction<T> + RowMapper<T>,
{
pub fn new(table_schema_data: &str, datasource_name: &'a str) -> Self {
Self {
_inner: QueryBuilder::<T>::new(
Query::new(format!("DELETE FROM {table_schema_data}")),
datasource_name,
),
}
}
#[inline]
pub async fn query(
&'a mut self,
) -> Result<Vec<T>, Box<(dyn std::error::Error + Sync + Send + 'static)>> {
self._inner.query().await
}
}
impl<'a, T> ops::QueryBuilder<'a, T> for DeleteQueryBuilder<'a, T>
where
T: Debug + CrudOperations<T> + Transaction<T> + RowMapper<T> + Send,
{
#[inline]
fn read_sql(&'a self) -> &'a str {
self._inner.query.sql.as_str()
}
#[inline(always)]
fn push_sql(&mut self, sql: &str) {
self._inner.query.sql.push_str(sql);
}
#[inline]
fn r#where<Z: FieldValueIdentifier<'a, T>>(
&mut self,
r#where: Z,
op: impl Operator,
) -> &mut Self {
self._inner.r#where(r#where, op);
self
}
#[inline]
fn and<Z: FieldValueIdentifier<'a, T>>(&mut self, column: Z, op: impl Operator) -> &mut Self {
self._inner.and(column, op);
self
}
#[inline]
fn and_values_in<Z, Q>(&mut self, r#and: Z, values: &'a [Q]) -> &mut Self
where
Z: FieldIdentifier<T>,
Q: QueryParameter<'a>,
{
self._inner.or_values_in(and, values);
self
}
#[inline]
fn or<Z: FieldValueIdentifier<'a, T>>(&mut self, column: Z, op: impl Operator) -> &mut Self {
self._inner.or(column, op);
self
}
#[inline]
fn or_values_in<Z, Q>(&mut self, r#or: Z, values: &'a [Q]) -> &mut Self
where
Z: FieldIdentifier<T>,
Q: QueryParameter<'a>,
{
self._inner.or_values_in(or, values);
self
}
#[inline]
fn order_by<Z: FieldIdentifier<T>>(&mut self, order_by: Z, desc: bool) -> &mut Self {
self._inner.order_by(order_by, desc);
self
}
}