use core::ops::{BitAnd, BitOr, Not};
use crate::sql::{SQL, SQLChunk, Token};
use crate::traits::{SQLParam, ToSQL};
use crate::types::Bool;
use super::{AggregateKind, Expr, NonNull, Nullability, SQLExpr, Scalar};
pub fn not<'a, V, E>(expr: E) -> SQLExpr<'a, V, Bool, NonNull, Scalar>
where
V: SQLParam + 'a,
E: ToSQL<'a, V>,
{
let expr_sql = expr.into_sql();
let needs_paren = expr_sql.chunks.len() > 1
|| (expr_sql.chunks.len() == 1
&& !matches!(expr_sql.chunks[0], SQLChunk::Raw(_) | SQLChunk::Ident(_)));
let sql = if needs_paren {
SQL::from_iter([Token::NOT, Token::LPAREN])
.append(expr_sql)
.push(Token::RPAREN)
} else {
SQL::from(Token::NOT).append(expr_sql)
};
SQLExpr::new(sql)
}
pub fn and<'a, V, I, E>(conditions: I) -> SQLExpr<'a, V, Bool, NonNull, Scalar>
where
V: SQLParam + 'a,
I: IntoIterator<Item = E>,
E: ToSQL<'a, V>,
{
let mut iter = conditions.into_iter();
let sql = match iter.next() {
None => SQL::empty(),
Some(first) => {
let first_sql = first.into_sql();
let Some(second) = iter.next() else {
return SQLExpr::new(first_sql);
};
let all_conditions = core::iter::once(first_sql)
.chain(core::iter::once(second.into_sql()))
.chain(iter.map(|c| c.into_sql()));
SQL::from(Token::LPAREN)
.append(SQL::join(all_conditions, Token::AND))
.push(Token::RPAREN)
}
};
SQLExpr::new(sql)
}
pub fn and2<'a, V, L, R>(left: L, right: R) -> SQLExpr<'a, V, Bool, NonNull, Scalar>
where
V: SQLParam + 'a,
L: ToSQL<'a, V>,
R: ToSQL<'a, V>,
{
SQLExpr::new(
SQL::from(Token::LPAREN)
.append(left.into_sql())
.push(Token::AND)
.append(right.into_sql())
.push(Token::RPAREN),
)
}
pub fn or<'a, V, I, E>(conditions: I) -> SQLExpr<'a, V, Bool, NonNull, Scalar>
where
V: SQLParam + 'a,
I: IntoIterator<Item = E>,
E: ToSQL<'a, V>,
{
let mut iter = conditions.into_iter();
let sql = match iter.next() {
None => SQL::empty(),
Some(first) => {
let first_sql = first.into_sql();
let Some(second) = iter.next() else {
return SQLExpr::new(first_sql);
};
let all_conditions = core::iter::once(first_sql)
.chain(core::iter::once(second.into_sql()))
.chain(iter.map(|c| c.into_sql()));
SQL::from(Token::LPAREN)
.append(SQL::join(all_conditions, Token::OR))
.push(Token::RPAREN)
}
};
SQLExpr::new(sql)
}
pub fn or2<'a, V, L, R>(left: L, right: R) -> SQLExpr<'a, V, Bool, NonNull, Scalar>
where
V: SQLParam + 'a,
L: ToSQL<'a, V>,
R: ToSQL<'a, V>,
{
SQLExpr::new(
SQL::from(Token::LPAREN)
.append(left.into_sql())
.push(Token::OR)
.append(right.into_sql())
.push(Token::RPAREN),
)
}
impl<'a, V, N, A> Not for SQLExpr<'a, V, Bool, N, A>
where
V: SQLParam + 'a,
N: Nullability,
A: AggregateKind,
{
type Output = SQLExpr<'a, V, Bool, NonNull, Scalar>;
fn not(self) -> Self::Output {
not(self)
}
}
impl<'a, V, N, A, Rhs> BitAnd<Rhs> for SQLExpr<'a, V, Bool, N, A>
where
V: SQLParam + 'a,
N: Nullability,
A: AggregateKind,
Rhs: Expr<'a, V>,
{
type Output = SQLExpr<'a, V, Bool, NonNull, Scalar>;
fn bitand(self, rhs: Rhs) -> Self::Output {
and2(self, rhs)
}
}
impl<'a, V, N, A, Rhs> BitOr<Rhs> for SQLExpr<'a, V, Bool, N, A>
where
V: SQLParam + 'a,
N: Nullability,
A: AggregateKind,
Rhs: Expr<'a, V>,
{
type Output = SQLExpr<'a, V, Bool, NonNull, Scalar>;
fn bitor(self, rhs: Rhs) -> Self::Output {
or2(self, rhs)
}
}