1use core::ops::{BitAnd, BitOr, Not};
27
28use crate::dialect::DialectTypes;
29use crate::sql::{SQL, SQLChunk, Token};
30use crate::traits::SQLParam;
31use crate::types::BooleanLike;
32
33use super::{AggOr, AggregateKind, Expr, NullOr, Nullability, SQLExpr};
34
35#[inline]
36fn operand_sql<'a, V, E>(value: E) -> SQL<'a, V>
37where
38 V: SQLParam + 'a,
39 E: Expr<'a, V>,
40 E::SQLType: BooleanLike,
41{
42 value.into_expr_sql()
43}
44
45#[inline]
46fn binary_logical_op<'a, V, L, R>(left: L, token: Token, right: R) -> SQL<'a, V>
47where
48 V: SQLParam + 'a,
49 L: Expr<'a, V>,
50 L::SQLType: BooleanLike,
51 R: Expr<'a, V>,
52 R::SQLType: BooleanLike,
53{
54 SQL::from(Token::LPAREN)
55 .append(operand_sql(left))
56 .push(token)
57 .append(operand_sql(right))
58 .push(Token::RPAREN)
59}
60
61pub fn not<'a, V, E>(
69 expr: E,
70) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, E::Nullable, E::Aggregate>
71where
72 V: SQLParam + 'a,
73 E: Expr<'a, V>,
74 E::SQLType: BooleanLike,
75 E::Nullable: Nullability,
76{
77 let expr_sql: SQL<'a, V> = expr.into_expr_sql();
78 let needs_paren = expr_sql.chunks.len() > 1
79 || (expr_sql.chunks.len() == 1
80 && !matches!(
81 expr_sql.chunks[0],
82 SQLChunk::Raw(_) | SQLChunk::Ident(_) | SQLChunk::Number(_)
83 ));
84
85 let sql = if needs_paren {
86 SQL::from_iter([Token::NOT, Token::LPAREN])
87 .append(expr_sql)
88 .push(Token::RPAREN)
89 } else {
90 SQL::from(Token::NOT).append(expr_sql)
91 };
92 SQLExpr::new(sql)
93}
94
95#[allow(clippy::type_complexity)]
109pub fn and<'a, V, L, R>(
110 left: L,
111 right: R,
112) -> SQLExpr<
113 'a,
114 V,
115 <V::DialectMarker as DialectTypes>::Bool,
116 <L::Nullable as NullOr<R::Nullable>>::Output,
117 <L::Aggregate as AggOr<R::Aggregate>>::Output,
118>
119where
120 V: SQLParam + 'a,
121 L: Expr<'a, V>,
122 L::SQLType: BooleanLike,
123 L::Nullable: NullOr<R::Nullable>,
124 L::Aggregate: AggOr<R::Aggregate>,
125 R: Expr<'a, V>,
126 R::SQLType: BooleanLike,
127 R::Nullable: Nullability,
128{
129 SQLExpr::new(binary_logical_op(left, Token::AND, right))
130}
131
132#[allow(clippy::type_complexity)]
146pub fn or<'a, V, L, R>(
147 left: L,
148 right: R,
149) -> SQLExpr<
150 'a,
151 V,
152 <V::DialectMarker as DialectTypes>::Bool,
153 <L::Nullable as NullOr<R::Nullable>>::Output,
154 <L::Aggregate as AggOr<R::Aggregate>>::Output,
155>
156where
157 V: SQLParam + 'a,
158 L: Expr<'a, V>,
159 L::SQLType: BooleanLike,
160 L::Nullable: NullOr<R::Nullable>,
161 L::Aggregate: AggOr<R::Aggregate>,
162 R: Expr<'a, V>,
163 R::SQLType: BooleanLike,
164 R::Nullable: Nullability,
165{
166 SQLExpr::new(binary_logical_op(left, Token::OR, right))
167}
168
169impl<'a, V, T, N, A> Not for SQLExpr<'a, V, T, N, A>
184where
185 V: SQLParam + 'a,
186 T: BooleanLike,
187 N: Nullability,
188 A: AggregateKind,
189{
190 type Output = SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Bool, N, A>;
191
192 fn not(self) -> Self::Output {
193 not(self)
194 }
195}
196
197impl<'a, V, T, N, A, Rhs> BitAnd<Rhs> for SQLExpr<'a, V, T, N, A>
208where
209 V: SQLParam + 'a,
210 T: BooleanLike,
211 N: Nullability + NullOr<Rhs::Nullable>,
212 A: AggOr<Rhs::Aggregate>,
213 Rhs: Expr<'a, V>,
214 Rhs::SQLType: BooleanLike,
215 Rhs::Nullable: Nullability,
216{
217 type Output = SQLExpr<
218 'a,
219 V,
220 <V::DialectMarker as DialectTypes>::Bool,
221 <N as NullOr<Rhs::Nullable>>::Output,
222 <A as AggOr<Rhs::Aggregate>>::Output,
223 >;
224
225 fn bitand(self, rhs: Rhs) -> Self::Output {
226 and(self, rhs)
227 }
228}
229
230impl<'a, V, T, N, A, Rhs> BitOr<Rhs> for SQLExpr<'a, V, T, N, A>
241where
242 V: SQLParam + 'a,
243 T: BooleanLike,
244 N: Nullability + NullOr<Rhs::Nullable>,
245 A: AggOr<Rhs::Aggregate>,
246 Rhs: Expr<'a, V>,
247 Rhs::SQLType: BooleanLike,
248 Rhs::Nullable: Nullability,
249{
250 type Output = SQLExpr<
251 'a,
252 V,
253 <V::DialectMarker as DialectTypes>::Bool,
254 <N as NullOr<Rhs::Nullable>>::Output,
255 <A as AggOr<Rhs::Aggregate>>::Output,
256 >;
257
258 fn bitor(self, rhs: Rhs) -> Self::Output {
259 or(self, rhs)
260 }
261}