use crate::model_traits::{HasSchema, TableColumns, TableInfo};
use crate::query::builder::QueryBuilder;
use crate::query::clause::{AsFieldName, ClauseAdder};
use crate::query::select_cols::group_by::GroupBy;
use crate::query::select_cols::select_column::SelectKind;
use crate::relations::{HasRelations, Relationship};
use crate::writers::alias::TableAlias;
pub use join::Join;
use join::JoinBuilder;
use select_column::SelectColumn;
use std::sync::Arc;
mod exec;
mod group_by;
mod join;
mod select_column;
#[cfg(test)]
mod tests;
pub struct SelectBuilder<T> {
qb: QueryBuilder<T>,
selects: Vec<SelectColumn>,
joins: Vec<JoinBuilder>,
group_bys: Vec<GroupBy>,
distinct: bool,
}
impl<T> Clone for SelectBuilder<T> {
fn clone(&self) -> Self {
Self {
qb: self.qb.clone(),
selects: self.selects.clone(),
joins: self.joins.clone(),
group_bys: self.group_bys.clone(),
distinct: self.distinct,
}
}
}
impl<T> SelectBuilder<T>
where
T: Send + HasSchema,
{
pub fn new(qb: QueryBuilder<T>) -> Self {
Self {
qb,
selects: Vec::default(),
joins: Vec::default(),
group_bys: Vec::default(),
distinct: false,
}
}
pub fn select<V, FN: AsFieldName<V>>(
mut self,
lam: impl Fn(<T as HasSchema>::Schema) -> FN,
) -> SelectBuilder<T> {
let field = lam(Default::default());
self.selects.push(SelectColumn {
col_name: field.colname().to_string(),
field_name: field.fieldname().to_string(),
kind: SelectKind::Column,
});
self
}
pub fn select_all(mut self) -> SelectBuilder<T> {
self.selects.push(SelectColumn {
col_name: Default::default(),
field_name: Default::default(),
kind: SelectKind::All,
});
self
}
pub fn select_as<V, FN: AsFieldName<V>>(
mut self,
lam: impl Fn(<T as HasSchema>::Schema) -> FN,
as_name: &'static str,
) -> SelectBuilder<T> {
let field = lam(Default::default());
self.selects.push(SelectColumn {
col_name: field.colname().to_string(),
field_name: as_name.to_string(),
kind: SelectKind::Column,
});
self
}
pub fn select_count<V, FN: AsFieldName<V>>(
mut self,
lam: impl Fn(<T as HasSchema>::Schema) -> FN,
as_name: &'static str,
) -> SelectBuilder<T> {
let field = lam(Default::default());
self.selects.push(SelectColumn {
col_name: field.colname().to_string(),
field_name: as_name.to_string(),
kind: SelectKind::Count,
});
self
}
pub fn select_max<V, FN: AsFieldName<V>>(
mut self,
lam: impl Fn(<T as HasSchema>::Schema) -> FN,
as_name: &'static str,
) -> SelectBuilder<T> {
let field = lam(Default::default());
self.selects.push(SelectColumn {
col_name: field.colname().to_string(),
field_name: as_name.to_string(),
kind: SelectKind::Max,
});
self
}
pub fn select_min<V, FN: AsFieldName<V>>(
mut self,
lam: impl Fn(<T as HasSchema>::Schema) -> FN,
as_name: &'static str,
) -> SelectBuilder<T> {
let field = lam(Default::default());
self.selects.push(SelectColumn {
col_name: field.colname().to_string(),
field_name: as_name.to_string(),
kind: SelectKind::Min,
});
self
}
pub fn select_avg<V, FN: AsFieldName<V>>(
mut self,
lam: impl Fn(<T as HasSchema>::Schema) -> FN,
as_name: &'static str,
) -> SelectBuilder<T> {
let field = lam(Default::default());
self.selects.push(SelectColumn {
col_name: field.colname().to_string(),
field_name: as_name.to_string(),
kind: SelectKind::Average,
});
self
}
pub fn select_sum<V, FN: AsFieldName<V>>(
mut self,
lam: impl Fn(<T as HasSchema>::Schema) -> FN,
as_name: &'static str,
) -> SelectBuilder<T> {
let field = lam(Default::default());
self.selects.push(SelectColumn {
col_name: field.colname().to_string(),
field_name: as_name.to_string(),
kind: SelectKind::Sum,
});
self
}
pub fn where_col(
mut self,
lam: impl Fn(<T as HasSchema>::Schema) -> Box<dyn ClauseAdder>,
) -> Self
where
<T as HasSchema>::Schema: Default,
{
self.qb = self.qb.where_col(lam);
self
}
pub fn where_relation<R, Ship>(
mut self,
relationship: impl Fn(<T as HasRelations>::Relation) -> Ship,
filter: QueryBuilder<R>,
) -> Self
where
T: HasRelations,
Ship: Relationship<T, R>,
R: HasSchema,
T: HasSchema,
R: Send + HasSchema,
<R as HasSchema>::Schema: TableInfo + TableColumns,
<T as HasSchema>::Schema: TableInfo + TableColumns,
<T as HasRelations>::Relation: Default,
{
self.qb = self.qb.where_relation(relationship, filter);
self
}
pub fn join<R, Ship>(
self,
relationship: impl Fn(<T as HasRelations>::Relation) -> Ship,
sb: SelectBuilder<R>,
) -> Self
where
T: HasRelations,
Ship: Relationship<T, R>,
R: HasSchema,
R: Send + HasSchema,
<R as HasSchema>::Schema: TableInfo + TableColumns,
<T as HasSchema>::Schema: TableInfo + TableColumns,
{
self.join_with(relationship, sb, Join::Inner)
}
pub fn left_join<R, Ship>(
self,
relationship: impl Fn(<T as HasRelations>::Relation) -> Ship,
sb: SelectBuilder<R>,
) -> Self
where
T: HasRelations,
Ship: Relationship<T, R>,
R: HasSchema,
R: Send + HasSchema,
<R as HasSchema>::Schema: TableInfo + TableColumns,
<T as HasSchema>::Schema: TableInfo + TableColumns,
{
self.join_with(relationship, sb, Join::Left)
}
pub fn join_with<R, Ship>(
mut self,
relationship: impl Fn(<T as HasRelations>::Relation) -> Ship,
mut sb: SelectBuilder<R>,
join_type: Join,
) -> Self
where
T: HasRelations,
Ship: Relationship<T, R>,
R: HasSchema,
R: Send + HasSchema,
<R as HasSchema>::Schema: TableInfo + TableColumns,
<T as HasSchema>::Schema: TableInfo + TableColumns,
{
let ship = relationship(Default::default());
sb.set_aliases(&self.qb.alias_asigner);
let _joined_group_bys = sb
.group_bys
.drain(..)
.map(|gb| self.group_bys.push(gb.set_alias(&sb.qb.alias)))
.collect::<Vec<_>>();
let outer_key = ship.my_key();
let inner_key = ship.their_key();
let mut jb = JoinBuilder::new(sb, outer_key, inner_key);
jb.ty = join_type;
self.joins.push(jb);
self
}
pub fn group_by<V, FN: AsFieldName<V>>(
mut self,
lam: impl Fn(<T as HasSchema>::Schema) -> FN,
) -> Self {
let field = lam(Default::default());
self.group_bys.push(GroupBy::new(field.colname()));
self
}
pub fn distinct(mut self) -> Self {
self.distinct = true;
self
}
pub fn limit(mut self, x: i64) -> Self {
self.qb = self.qb.limit(x);
self
}
pub fn offset(mut self, x: i64) -> Self {
self.qb = self.qb.offset(x);
self
}
pub fn order_by_desc<V, FN: AsFieldName<V>>(
mut self,
lam: impl Fn(<T as HasSchema>::Schema) -> FN,
) -> Self {
self.qb = self.qb.order_by_desc(lam);
self
}
pub fn order_by_asc<V, FN: AsFieldName<V>>(
mut self,
lam: impl Fn(<T as HasSchema>::Schema) -> FN,
) -> Self {
self.qb = self.qb.order_by_asc(lam);
self
}
pub fn order_manual(mut self, sql: &'static str) -> Self {
self.qb = self.qb.order_manual(sql);
self
}
pub(crate) fn set_aliases(&mut self, alias_asigner: &Arc<TableAlias>) {
self.qb.set_aliases(alias_asigner);
for join in &mut self.joins {
join.set_aliases(&self.qb.alias_asigner);
}
}
}