use core::marker::PhantomData;
use crate::relation::RelationDef;
use crate::{PaginationArg, SQL, SQLParam};
use super::builder::{
AllColumns, Clauses, HasLimit, HasOffset, HasOrderBy, HasWhere, IntoColumnSelection, NoLimit,
NoOrderBy, NoWhere, PartialColumns, QueryTable,
};
pub struct RelationHandle<
'a,
V: SQLParam,
R: RelationDef,
Nested = (),
Cols = AllColumns,
Cl = Clauses,
> {
pub(crate) where_sql: SQL<'a, V>,
pub(crate) order_by_sql: SQL<'a, V>,
pub(crate) limit: Option<SQL<'a, V>>,
pub(crate) offset: Option<SQL<'a, V>>,
pub(crate) nested: Nested,
pub(crate) cols: Cols,
pub(crate) _marker: PhantomData<(R, Cl)>,
}
impl<'a, V: SQLParam, R: RelationDef> RelationHandle<'a, V, R> {
#[must_use]
pub const fn new() -> Self {
Self {
where_sql: SQL::empty(),
order_by_sql: SQL::empty(),
limit: None,
offset: None,
nested: (),
cols: AllColumns,
_marker: PhantomData,
}
}
}
impl<'a, V: SQLParam, R: RelationDef> Default for RelationHandle<'a, V, R> {
fn default() -> Self {
Self::new()
}
}
impl<'a, V: SQLParam, R: RelationDef, Nested, Cols, Cl> RelationHandle<'a, V, R, Nested, Cols, Cl> {
#[allow(clippy::type_complexity)]
pub fn with<NR, NN, NC, NCl>(
self,
handle: RelationHandle<'a, V, NR, NN, NC, NCl>,
) -> RelationHandle<'a, V, R, (RelationHandle<'a, V, NR, NN, NC, NCl>, Nested), Cols, Cl>
where
NR: RelationDef<Source = R::Target> + 'static,
{
RelationHandle {
where_sql: self.where_sql,
order_by_sql: self.order_by_sql,
limit: self.limit,
offset: self.offset,
nested: (handle, self.nested),
cols: self.cols,
_marker: PhantomData,
}
}
}
impl<'a, V: SQLParam, R: RelationDef, Nested, Cols, Ord, Lim>
RelationHandle<'a, V, R, Nested, Cols, Clauses<NoWhere, Ord, Lim>>
{
pub fn r#where<E>(
self,
condition: E,
) -> RelationHandle<'a, V, R, Nested, Cols, Clauses<HasWhere, Ord, Lim>>
where
E: crate::expr::Expr<'a, V>,
E::SQLType: crate::types::BooleanLike,
V: 'a,
{
RelationHandle {
where_sql: condition.to_sql(),
order_by_sql: self.order_by_sql,
limit: self.limit,
offset: self.offset,
nested: self.nested,
cols: self.cols,
_marker: PhantomData,
}
}
}
impl<'a, V: SQLParam, R: RelationDef, Nested, Cols, W, Lim>
RelationHandle<'a, V, R, Nested, Cols, Clauses<W, NoOrderBy, Lim>>
{
pub fn order_by<E>(
self,
expr: E,
) -> RelationHandle<'a, V, R, Nested, Cols, Clauses<W, HasOrderBy, Lim>>
where
E: crate::traits::ToSQL<'a, V>,
V: 'a,
{
RelationHandle {
where_sql: self.where_sql,
order_by_sql: expr.to_sql(),
limit: self.limit,
offset: self.offset,
nested: self.nested,
cols: self.cols,
_marker: PhantomData,
}
}
}
impl<'a, V: SQLParam, R: RelationDef, Nested, Cols, W, Ord>
RelationHandle<'a, V, R, Nested, Cols, Clauses<W, Ord, NoLimit>>
{
pub fn limit<P>(self, n: P) -> RelationHandle<'a, V, R, Nested, Cols, Clauses<W, Ord, HasLimit>>
where
P: PaginationArg<'a, V>,
V: 'a,
{
RelationHandle {
where_sql: self.where_sql,
order_by_sql: self.order_by_sql,
limit: Some(n.into_pagination_sql()),
offset: self.offset,
nested: self.nested,
cols: self.cols,
_marker: PhantomData,
}
}
pub fn first(self) -> RelationHandle<'a, V, R, Nested, Cols, Clauses<W, Ord, HasLimit>> {
self.limit(1u32)
}
}
impl<'a, V: SQLParam, R: RelationDef, Nested, Cols, W, Ord>
RelationHandle<'a, V, R, Nested, Cols, Clauses<W, Ord, HasLimit>>
{
pub fn offset<P>(
self,
n: P,
) -> RelationHandle<'a, V, R, Nested, Cols, Clauses<W, Ord, HasOffset>>
where
P: PaginationArg<'a, V>,
V: 'a,
{
RelationHandle {
where_sql: self.where_sql,
order_by_sql: self.order_by_sql,
limit: self.limit,
offset: Some(n.into_pagination_sql()),
nested: self.nested,
cols: self.cols,
_marker: PhantomData,
}
}
}
impl<'a, V: SQLParam, R: RelationDef, Nested, Cl> RelationHandle<'a, V, R, Nested, AllColumns, Cl>
where
R::Target: QueryTable,
{
pub fn columns<S: IntoColumnSelection>(
self,
selector: S,
) -> RelationHandle<'a, V, R, Nested, PartialColumns, Cl> {
RelationHandle {
where_sql: self.where_sql,
order_by_sql: self.order_by_sql,
limit: self.limit,
offset: self.offset,
nested: self.nested,
cols: PartialColumns {
columns: selector.into_column_names(),
},
_marker: PhantomData,
}
}
pub fn omit<S: IntoColumnSelection>(
self,
selector: S,
) -> RelationHandle<'a, V, R, Nested, PartialColumns, Cl> {
let omitted = selector.into_column_names();
let columns = <R::Target as QueryTable>::COLUMN_NAMES
.iter()
.copied()
.filter(|c| !omitted.contains(c))
.collect();
RelationHandle {
where_sql: self.where_sql,
order_by_sql: self.order_by_sql,
limit: self.limit,
offset: self.offset,
nested: self.nested,
cols: PartialColumns { columns },
_marker: PhantomData,
}
}
}