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